专栏算法工具链YOLOv5的量化流程及部署方法

YOLOv5的量化流程及部署方法

DR_KAN2024-11-28
340
3

技术背景

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)

 

 

算法工具链
社区征文杂谈
评论2
0/1000
  • 默认25184
    Lv.1

    请教下为什么要把sigmoid放到后处理让cpu运算?我理解sigmoid算子放在bpu加速,推理+后处理的整体耗时表现会更好?

    2025-03-19
    0
    1
    • DR_KAN回复默认25184:

      可以提前卡阈值筛选一部分输出,筛选掉的就不需要sigmoid了

      2025-03-21
      0
  • 新宇
    Lv.1

    为什么源码那些展开看不全啊,源码展开只能看到222行

    2026-02-10
    0
    0