本篇博客记录将yolov5s移植到瑞芯微3566上的整体流程。当然在其它芯片上的操作类似,差别会在具体的API的调用上。
1 芯片相关
- 芯片参数:https://www.rock-chips.com/a/cn/product/RK35xilie/2021/0113/1273.html
- CPU:四核,1.8GHZ.
- NPU:1TOPs@Int8,每秒一万亿次运算。
gitlab连接如下:
RKNN Toolkit:包含python的安装包、安装说明文档、python将onnx转成rknn示例工程。
- RK1808/RK1806/RV1109/RV1126/RK3399Pro 使用: https://github.com/rockchip-linux/rknn-toolkit
- RK3566/RK3568/RK3588/RV1103/RV1106使用:https://github.com/rockchip-linux/rknn-toolkit2
Rockchip NPU提供驱动、C++推理示例
- RK1808/RK1806/RV1109/RV1126,参考:https://github.com/rockchip-linux/rknpu
- RK3566/RK3568/RK3588/RV1103/RV1106,参考:https://github.com/rockchip-linux/rknpu2
- RK3399Pro用户态的库及驱动,参考:https://github.com/airockchip/RK3399Pro_npu
这里记录基于3566上的v1.4.0的版本的环境安装流程和部署工作。故没有下载master分支,而是下载 rknn-toolkit2-v1.4.0分支、rknpu2-v1.4.0分支,然后解压。
另外补充说下,官方文档里面介绍api是比较详细的,如果按照下面流程依然无法正确跑通,就多看看文档了。
2 DEMO工程的运行
2.1 配置环境与demo模型转换
进入【rknn-toolkit2-v1.4.0】工程根目录,文件夹下的树状结构如下。tree的安装命令为【sudo apt-get -y install tree】
- 创建虚拟环境
1.4的版本支持python3.6、python3.8。这里选择python3.6
conda create -n RK3566 python=3.6
conda activate RK3566
- 安装依赖库
安装必要的依赖包。下面的命令添加了清华镜像,加快安装速度,否则跟蜗牛一样。
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r ./doc/requirements_cp36-1.4.0.txt
- 安装rk的包
pip install ./packages/rknn_toolkit2-1.4.0_22dcfef4-cp36-cp36m-linux_x86_64.whl
- 检查是否安装成功
- 运行官方的yolov5demo
cd examples/onnx/yolov5
python test.py
其中,yolov5s.rknn为转换后的模型,test.png为结果的可视化图片
python的工作到此结束。
我们需要注意下,对于RK1126相似系列的代码中模型转换时,模型build时,有个预编译参数,仿真时和端侧运行时的设置是不一致且不通用的。
2.2 demo工程编译与板端运行
进入【rknpu2-v1.4.0】工程根目录,文件夹下的树状结构如下
- 下载交叉编译器
交叉编译器可通过两种方式安装:
- a) 终端命令安装
查看可安装版本:apt-cache search aarch64
安装指定版本为:apt-get install gcc-10-aarch64-linux-gnc
报错"E: Unmet dependencies"时:apt --fix-broken install
- b) 官方软件包下载
我这里在【官方软件包下载路径】下载版本【gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu】,下载文件夹里面是已经编译好的二进制可执行程序。下载后解压,bin目录下存放这所需的交叉编译器,可直接使用- 编译官方 yolov5 demo
demo路径为【./examples/rknn_yolov5_demo】。需要先修改工程中的交叉编译器路径
cd ./examples/rknn_yolov5_demo
打开文件【build-linux_RK356X.sh】并修改【GCC_COMPILER】路径,
- 板端运行demo
将编译好的install目录推到板端的【/userdata/】路径下。然后运行
adb shell
cd /userdata/install/rknn_yolov5_demo_Linux
./rknn_yolov5_demo ./model/RK356X/yolov5s-640-640.rknn ./model/bus.jpg
3 相关代码解析
3.1 onnx转rknn的核心代码
在【doc/
Rockchip_User_Guide_RKNN_Toolkit2_CN-1.4.0.pdf
】中,详细介绍了API接口的使用规则。这里只记录需要注意的点。
均值方差的设置
模型在训练时,图片会经过归一化处理,一般都是减均值除方差。在yolov5目标检测的训练时候,均值方差分别为[0,0,0]、[255,255,255]。代码设置如下截图。
如果个人实际训练中,修改了均值方差,对应位置修改即可。加载ONNX模型并设置输出节点
源码中的设置如图
但我们自己训练的yolov5的onnx模型使用【Netron】打开,如下图。
当想要3层的输出时,需要指定输出节点才行。
- 可以看到模型提供的3个输出层的节点名称分别为[339,392,445],对应的输出shape分别为 (1x3x20x20x22)、(1x3x40x40x22)、(1x3x80x80x22)。
- 这三层输出的reshape前的节点分别为[326,379,432],对用的shape分别为(1x66x20x20)、(1x66x40x40)、(1x66x80x80)。
- 我们可以看到仿真器的后处理,以及C++部署的后处理都是针对(1x66x20x20)、(1x66x40x40)、(1x66x80x80)。所以这里需要设置节点为[326,379,432]。当我们优化改造过模型,这三个节点具体的名称会发生变化,所以一定要可视化onnx模型确认节点名称
是否量化的设置
在rknn.build(do_quantization=QUANTIZE_ON, dataset=DATASET)中,前者是设置是否进行量,后者是量化时使用的数据集的图片路径。量化的图片的shape和网络输入如果不一致,这里会自动resize,所以为了保证精度,我们的量化数据集的shape尽量与输入一致。
在【Rockchip_Trouble_Shooting_RKNN_Toolkit_V1.7.3_CN.pdf】中有简单介绍。
导出rknn模型
导出的模型,用于板端的推理
rknn仿真器推理结果
结果后处理
3.2 rknn板端推理核心代码
这部分代码不需要我们修改多的内容,就是自己实际使用时,想要将其添加到其他工程中,就需要将其重构成一个类,实现出对外可调用的3个成员函数:
init_model
、detect
、destroy_model
,具体修改这里不做记录。这里说明如下几点:
通过
rknn_query
获取加载后的rk模型的相关信息
代码实现和终端打印如下:
上图分别获取的内容:rk的版本信息、模型的输入输出数量的信息、输入节点相关的信息、输出节点相关的信息
1)自己曾遇到过sdk version 和driver version的版本不兼容导致模型无法加载正确。所以模型在有些主板上可加载成功 有些不能,可留心板端的的库的版本等信息是否正确。
2)对于输入输出节点信息的打印,我们能看到的元素有:
- index:模型的第几个输入或输出
- name:节点的名称
- n_dims:节点的维度数量
- dims:节点的具体的维度数值
- n_elems:节点中有多少个数值
- size:节点的内存大小,单位为Byte。当为int8时,一个数大小为1Byte,此时n_elems=size。
- fmt:该节点维度维度为NCHW、或 NHWC
- type:该节点的数据类型
- qnt_type:量化的方式
- zp:量化时候的偏移
- scale:量化时候的缩放
通过
rknn_input
实现输入数据的设置
注意这里设置的信息要与前面网络模型获取的输入节点信息相匹配。这里的buf的设置时,一定保证图片的大小和网络的输入是相同的尺寸。
在源码中是先有个判断,如果两者不一致会进行resize处理,这里使用的是rga库进行resize的。较早的rk提供板端的推理工程图片读取处理使用的都是rga,该库的速度会很快。但在一般图像相关工程中都会使用到opencv,所以rk修改为使用opencv的库读取图片,但opencv的resize较为耗时,这里还是选择rga的resize进行操作
当我们网络为多输入时候,设置如下即可: