YOLOv5
YOLOv5
本教程将引导你如何通过 CPU 或 NPU 在 RevyOS 系统上运行 YOLOv5 模型。
在按照本教程操作前,请确保你已经完成了环境配置部分的内容。
示例代码获取
本教程配套的示例代码已更新到 Github 中,使用 git 命令将其克隆到本地。
$ git clone https://github.com/zhangwm-pt/lpi4a-example.git
适用于本教程的代码位于 detection/yolov5 目录下。
模型获取
本教程中使用的模型来自 yolov5 模型仓库,可通过其 export.py 脚本导出。
$ git clone https://github.com/ultralytics/yolov5.git
$ cd yolov5
$ pip3 install ultralytics
$ python3 export.py --weights yolov5n.pt --include onnx --imgsz 384 640
如果你在中国大陆访问 GitHub 时遇到网络问题,可以考虑使用网络代理工具来加速访问。
转换和编译模型
环境配置完成后,即可使用 HHB 编译模型为 c920 上的可执行程序。
本教程中使用的检测模型是 yolov5n,针对 yolov5n,hhb 命令中截取到最后的卷积层为止,卷积层之后的后处理,交由示例中已准备好的 yolov5n.c 文件处理。
进入 detection/yolov5 目录,执行以下命令:
- NPU
- CPU
$ hhb -D --model-file yolov5n.onnx --data-scale-div 255 \
--board c920 --input-name "images" --output-name \
"/model.24/m.0/Conv_output_0;/model.24/m.1/Conv_output_0;/model.24/m.2/Conv_output_0" \
--input-shape "1 3 384 640" --quantization-scheme float16
$ hhb -D --model-file yolov5n.onnx --data-scale-div 255 \
--board th1520 --input-name "images" --output-name \
"/model.24/m.0/Conv_output_0;/model.24/m.1/Conv_output_0;/model.24/m.2/Conv_output_0" \
--input-shape "1 3 384 640" --calibrate-dataset kite.jpg \
--quantization-scheme "int8_asym"
-D:指定 HHB 流程执行到生成可执行文件的阶段为止--model-file:指定输入模型文件--data-mean:指定均值--data-scale:指定缩放值--board:指定目标平台为 C920(CPU) 或 TH1520(NPU)--input-name: 模型的输入 tensor 名--output-name:模型的输出 tensor 名--input-shape:模型的输入 tensor 形状--postprocess:指定 HHB 生成的胶水代码的后处理行为。save_and_top5表示保存输出结果,并且打印 top5 结果--quantization-scheme:指定量化类型
你可以通过运行 hhb --help 查看所有可用的参数和选项。
命令执行完成后,会在当前目录生成 hhb_out 子目录,里面的包括了 hhb_runtime model.c 等多个文件:
hhb.bm:HHB 的模型文件,包括了量化后的权重数据等信息hhb_runtime:适用于开发板的可执行文件,由目录中的C文件编译而成main.c:HHB 生成的示例程序的参考入口model.c:HHB 模型结构表示文件,与模型结构相关model.params:模型权重文件io.c:HHB 生成的示例程序,包含读写文件的辅助函数io.h:HHB 生成的示例程序,包含读写文件的辅助函数声明process.c:HHB 生成的示例程序,包含图像预处理函数process.h:HHB 生成的示例程序,包含图像预处理函数声明
gcc 编译后处理
本教程中,使用了 c 代码实现模型的后半部分和 NMS,后处理输出图片对应的检测结果。
$ riscv64-unknown-linux-gnu-gcc yolov5n.c -o yolov5n_example hhb_out/io.c \
hhb_out/model.c -Wl,--gc-sections -O2 -g -mabi=lp64d -I hhb_out/ -L \
/usr/local/lib/python3.8/dist-packages/hhb/install_nn2/th1520/lib/ \
-lshl -L /usr/local/lib/python3.8/dist-packages/hhb/prebuilt/decode/install/lib/rv \
-L /usr/local/lib/python3.8/dist-packages/hhb/prebuilt/runtime/riscv_linux \
-lprebuilt_runtime -ljpeg -lpng -lz -lstdc++ -lm -I \
/usr/local/lib/python3.8/dist-packages/hhb/install_nn2/th1520/include/ -mabi=lp64d \
-march=rv64gcv0p7_zfh_xtheadc -Wl,-unresolved-symbols=ignore-in-shared-libs -I \
/usr/local/lib/python3.8/dist-packages/hhb/install_nn2/th1520/include/shl_public/ \
-I /usr/local/lib/python3.8/dist-packages/hhb/install_nn2/th1520/include/csinn/
本教程的示例代码中链接了 shl 库,比如 shl 的安装目录在 /usr/local/lib/python3.8/dist-packages/shl。
-Ihhb_out -I/usr/local/lib/python3.8/dist-packages/shl/install_nn2/c920/include/:头文件的搜索路径,指定到 shl 的头文件路径-L/usr/local/lib/python3.8/dist-packages/shl/install_nn2/c920/lib:库的搜索路径,指定到预编译好的 shl 的二进制库路径-static:指定为静态链接-o yolov5n_example:指定生成名为 yolov5n_example 的可执行文件
编译命令正确执行完成后会在示例目录生成 yolov5n_example 文件。
执行
交叉编译完成后,即可将程序执行所需的文件复制到开发板的目录中。
以开发板 ip 为 10.63.x.x,使用 /demo 目录为例,主机上将示例程序的目录通过 scp 复制到目录中:
scp -r yolov5n th1520@10.63.x.x:/demo/
linux 命令行执行时,开发板的命令行终端上,到示例目录执行命令。执行完成后,会在终端上提示执行到的各个阶段:
- 预处理:将原图填充缩放到 384 * 640 的大小
- 模型执行和后处理:执行模型推理,并做 nms 等后处理
- 画框:将检测结果画在 384 * 640 尺寸的图上,并输出新图片
kite.jpg:输入图片image_preprocessed.bin:预处理阶段,根据输入图片生成的中间结果yolov5n_example:模型执行阶段使用的文件,由x86主机上 gcc 编译生成hhb_out/hhb.bm:模型执行阶段使用的文件,由x86主机上 HHB 生成detect.txt:后处理阶段的输出文件,包括了图片中检测出来的 4 个目标kite_result.jpg:输出图片,将检测框加入到输入图上的结果
参考结果
本教程中输入如下图,是一个一家三口放风筝的图片,预期 yolov5 的检测结果是检测到三个人和一个风筝。

示例正常执行时,会有类似如下打印:
- NPU
- CPU
$ .python3 inference.py
********** preprocess image **********
******* run yolov5 and postprocess *******
Run graph execution time: 401.13336ms, FPS=2.49
detect num: 4
id: label score x1 y1 x2 y2
[0]: 0 0.899609 274.486389 158.510849 359.157715 332.118591
[1]: 0 0.880201 80.017410 184.470093 190.141861 349.840637
[2]: 0 0.844358 219.474869 221.711838 283.615723 333.643250
[3]: 33 0.667759 67.194008 174.118088 203.020660 220.667618
********** draw bbox **********
[274.486389, 158.510849, 359.157715, 332.118591, 0.899609, 0]
[80.01741, 184.470093, 190.141861, 349.840637, 0.880201, 0]
[219.474869, 221.711838, 283.615723, 333.64325, 0.844358, 0]
[67.194008, 174.118088, 203.02066, 220.667618, 0.667759, 33]
$ python3 inference.py
********** preprocess image **********
******* run yolov5 and postprocess *******
INFO: NNA clock:1001624 [kHz]
INFO: Heap :anonymous (0x2)
INFO: Heap :dmabuf (0x2)
INFO: Heap :unified (0x5)
WARNING: Mapping to the on chip ram failed (128 > 0), continuing...
FATAL: Importing 737280 bytes of CPU memory has failed (Invalid argument)
Run graph execution time: 11.96299ms, FPS=83.59
detect num: 4
id: label score x1 y1 x2 y2
[0]: 0 0.895277 273.492188 161.245056 359.559814 330.644257
[1]: 0 0.887368 79.860062 179.181244 190.755692 354.304474
[2]: 0 0.815214 222.054565 224.477600 279.828979 333.717285
[3]: 33 0.563324 67.625580 173.948883 201.687988 219.065765
********** draw bbox **********
[273.492188, 161.245056, 359.559814, 330.644257, 0.895277, 0]
[79.860062, 179.181244, 190.755692, 354.304474, 0.887368, 0]
[222.054565, 224.4776, 279.828979, 333.717285, 0.815214, 0]
[67.62558, 173.948883, 201.687988, 219.065765, 0.563324, 33]