技术背景
YOLOv5是一种高效的目标检测算法,尤其在实时目标检测任务中表现突出。YOLOv5通过三种不同尺度的检测头分别处理大、中、小物体;检测头共包括三个关键任务:边界框回归、类别预测、置信度预测;每个检测头都会逐像素地使用三个Anchor,以帮助算法更准确地预测物体边界。
YOLOv5具有多种不同大小的模型(YOLOv5n、YOLOv5s、YOLOv5m、YOLOv5l、YOLOv5x)以适配不同的任务类型和硬件平台。本文以基于色选机数据集训练出的YOLOv5n模型为例,介绍如何使用PTQ进行量化编译并使用C++进行全流程的板端部署。
模型输入输出说明
本示例使用的yolov5n模型,相较于公版在输入和输出上存在以下2点变动:
1、输入分辨率设定为384x2048,从而输出分辨率也调整为了48x256,24x128,12x64
2、类别数量设定为17,因此输出tensor的通道数变为了(17+4+1)x3=66
从pytorch导出的onnx模型,具体的输入输出信息如下图所示:

同时,为了优化整体耗时,模型尾部的sigmoid计算被放在了后处理。
工具链环境
PTQ量化编译流程
准备校准数据

先准备100张如上图所示的色选机数据集图片存放在seed100文件夹,之后可借助horizon_model_convert_sample的02_preprocess.sh脚本帮助我们生成校准数据。
02_preprocess.sh
preprocess.py
校准数据仅需resize成符合模型输入的尺寸,并处理成chw和rgb即可。也就是说,除了归一化,其他操作都要对齐浮点模型训练时的数据预处理,而归一化可以放到模型的预处理节点中实现加速计算。
配置yaml文件
input_type_rt指模型在部署时输入的数据类型,考虑到视频通路传来的通常都是nv12,因此我们将该项置为nv12
input_type_train指浮点模型训练时使用的数据类型,这里使用rgb
input_layout_train指浮点模型训练时使用的数据排布,这里使用NCHW
norm_type和scale_value根据浮点模型训练时使用的归一化参数设置,这里配置scale为1/255(mean和scale的具体计算方法可参考文章 https://developer.d-robotics.cc/forumDetail/71036815603174578)
这样配置后,上板模型会自带一个预处理节点,用来将nv12数据转换为rgb并做归一化,这个预处理节点可以被等效转换为卷积,从而支持BPU加速计算,进而显著减少预处理耗时。我们强烈建议您在编译处理图像任务的模型时,使用这种配置方法。上板模型的数据输入类型可直接使用nv12,同时我们也提供了板端读取bgr图片并转换为nv12格式的C++代码供您参考。
编译上板模型
执行以上命令后,即可编译出用于板端部署的bin模型。
根据编译日志可看出,yolov5n模型的三个输出头,量化前后的余弦相似度均>0.99,符合精度要求。
onnx和bin的一致性验证(可选流程)
PTQ量化流程会生成yolov5n_quantized_model.onnx和yolov5n.bin,前者是量化后的onnx模型,后者是上板模型。通常来说,这两个模型具有完全相同的精度,可以使用这种方法进行验证。
yolov5n_quantized_model.onnx
在读取原始图像后,将其转换为nv12格式并保存,之后处理成yuv444_128格式并送给模型推理。该段代码的详细说明可参考文章 https://developer.d-robotics.cc/forumDetail/118364000835765839 。
由print(output[0][0][0][0])打印出的信息如下:
yolov5n.bin
这里我们将上一步保存的nv12数据作为bin模型的输入,并保存输出数据,其中第一个输出分支的数据如下:
可以看到,yolov5n_quantized_model.onnx和yolov5n.bin具有相同的输出。
Runtime部署流程
在算法工具链的交付包中,ai benchmark示例包含了读图、前处理、推理、后处理等完整流程的C++源码,但考虑到ai benchmark代码耦合度较高,有不低的学习成本,不方便用户嵌入到自己的工程应用中,因此我们提供了基于horizon_runtime_sample示例修改的简易版本C++代码,只包含1个头文件和1个C++源码,用户仅需替换原有的00_quick_start示例即可编译运行。
该C++ demo包含对单帧数据的读图(bgr->nv12),模型推理(包含预处理),后处理,打印输出结果等步骤。
头文件
该头文件内容主要来自于ai benchmark的code/include/base/perception_common.h头文件,包含了对argmax和计时功能的定义,以及目标检测任务相关结构体的定义。
源码
为方便用户阅读,该源码使用全局变量定义了若干参数,请用户在实际的应用工程中,避免使用过多全局变量。代码中已在合适的位置添加中文注释。
运行说明
用户可将头文件和源码放入horizon_runtime_sample/code/00_quick_start/src路径,并执行build_x5.sh编译工程,再将horizon_runtime_sample/x5文件夹复制到开发板的/userdata目录,并在/userdata/x5/script/00_quick_start/路径下存放上板模型、测试图片等文件,并编写板端运行脚本:
运行结果如下:
对于这次推理,我们的输入图像为下图:

可以看到,推理程序成功识别到了1枚瓜子,并且给出了正确的坐标信息。
模型推理耗时说明
需要强调的是,应用程序在推理第一帧的时候,会产生加载推理框架导致的额外耗时,因此运行该程序测出的模型推理耗时是偏高的。
准确的模型的推理时间应当以hrt_model_exec工具实测结果为准,参考命令:
hrt_model_exec perf --model-file ./yolov5n.bin --thread-num 1(测试单线程单帧延时,关注latency)
hrt_model_exec perf --model-file ./yolov5n.bin --thread-num 8(测试多线程极限吞吐量,关注FPS)

