K230 AI实战 - HHB神经网络模型部署工具
1.概述
HHB程序在k230 rtt上部署运行, 需要如下步骤
- 基于HHB开发环境, 编译模型生成c代码
- 使用k230 rtt交叉编译工具链编译c代码
- 上板运行可执行程序
1.1 HHB
HHB (Heterogeneous Honey Badger) 是 T-Head 提供的一套针对玄铁芯片平台的神经网络模型部署工具集。包括了编译优化,性能分析,过程调试,结果模拟等一系列部署时所需的工具。
HHB 的功能与特性:
- 支持 caffe,tensorflow,onnx 和 tflite 对应格式的模型
- 支持 8/16 位定点和 16/32 位浮点等数据类型
- 支持对称和非对称定点量化,支持通道量化
- 可在部署前优化模型的网络结构
- 编译生成可在无剑 SoC 平台上执行的二进制
- 支持在主机上做行为模拟
- 多组件形式的工具集方便二次开发
- 同时提供传统习惯的 Unix 命令行和 Python 接口
HHB 已支持语音和视觉的 多种不同业务算法,可导入 PyTorch 和 TensorFlow 等不同训练框架的模型。
HHB 以开源项目 TVM 为基础架构,添加了丰富的命令行选项提供命令模式;预置了多类量化算法适配不同平台可支持的数据类型;根据不同平台特点,输出调用 SHL 的 C 代码,或者直接输出可执行的二进制。
详细使用方法可参考HHB用户手册
1.2 SHL
SHL 是 T-HEAD 提供的一组针对玄铁 CPU 平台的神经网络库 API。抽象了各种常用的网络层的接口,并且提供一系列已优化的二进制库。
SHL 的特性:
- C 代码版本的参考实现。
- 提供玄铁系列 CPU 的汇编优化实现。
- 支持对称量化和非对称量化。
- 支持8位定点,16位定点和16位浮点等数据类型。
- 兼容 NCHW 和 NHWC 格式。
- 搭配 HHB 实现代码自动调用。
- 覆盖 CPU,NPU 等不同体系结构。
- 附加异构参考实现。
SHL 提供了完成的接口声明和接口的参考实现,各个设备提供商可以依此针对性的完成各个接口的优化工作。
详细使用方法可参考SHL用户手册
2. HHB编译模型
2.1 环境搭建
前置条件: 本地PC已安装docker
-
去HHB下载hhb-2.2.35 docker image
-
解压/加载/启动docker image
tar xzf hhb-2.2.35.docker.tar.gz
cd hhb-2.2.35.docker/
docker load < hhb.2.2.35.img.tar
./start_hhb.sh
2.2 编译模型
目前这个版本docker image没有集成c908模型编译, 这里拷贝c906并修改相关配置。
root@02297217e66d:~# cd /home/example/
root@02297217e66d:/home/example# cp -a c906 c908
root@02297217e66d:/home/example# cd c908/onnx_mobilenetv2/
run.sh相关修改
- 修改--board参数的值(c906改为c908)
- 添加校正集参数( -cd )
- 添加量化参数(--quantization-scheme)
最后修改后run.sh内容如下
#!/bin/bash -x
hhb -S --model-file mobilenetv2-12.onnx --data-scale 0.017 --data-mean "124 117 104" --board c908 --input-name "input" --output-name "output" --input-shape "1 3 224 224" --postprocess save_and_top5 --simulate-data persian_cat.jpg -cd persian_cat.jpg --quantization-scheme "int8_asym_w_sym" --fuse-conv-relu
注: 不同的模型, 编译参数有可能不同,会造成性能数据差异。用户需要基于自己的模型, 深入了解hhb各参数含义(hhb -h)或者咨询平头哥等。
执行run.sh开始编译
root@02297217e66d:/home/example/c908/onnx_mobilenetv2# ./run.sh
+ hhb -S --model-file mobilenetv2-12.onnx --data-scale 0.017 --data-mean '124 117 104' --board c908 --input-name input --output-name output --input-shape '1 3 224 224' --postprocess save_and_top5 --simulate-data persian_cat.jpg -cd persian_cat.jpg --quantization-scheme int8_asym_w_sym --fuse-conv-relu
[2023-06-21 09:02:53] (HHB LOG): Start import model.
[2023-06-21 09:02:55] (HHB LOG): Model import completed!
[2023-06-21 09:02:55] (HHB LOG): Start quantization.
[2023-06-21 09:02:55] (HHB LOG): get calibrate dataset from persian_cat.jpg
[2023-06-21 09:02:55] (HHB LOG): Start optimization.
[2023-06-21 09:02:55] (HHB LOG): Optimization completed!
Calibrating: 100%|###############################################################################################################################################################################################################################| 153/153 [00:14<00:00, 10.66it/s]
[2023-06-21 09:03:10] (HHB LOG): Start conversion to csinn.
[2023-06-21 09:03:10] (HHB LOG): Conversion completed!
[2023-06-21 09:03:10] (HHB LOG): Start operator fusion.
[2023-06-21 09:03:10] (HHB LOG): Operator fusion completed!
[2023-06-21 09:03:10] (HHB LOG): Start operator split.
[2023-06-21 09:03:10] (HHB LOG): Operator split completed!
[2023-06-21 09:03:10] (HHB LOG): Start layout convert.
[2023-06-21 09:03:10] (HHB LOG): Layout convert completed!
[2023-06-21 09:03:10] (HHB LOG): Quantization completed!
[2023-06-21 09:03:14] (HHB LOG): cd hhb_out; qemu-riscv64 -cpu c908v hhb_runtime ./hhb.bm persian_cat.jpg.0.bin
Run graph execution time: 1675.78113ms, FPS=0.60
=== tensor info ===
shape: 1 3 224 224
data pointer: 0x2e0b40
=== tensor info ===
shape: 1 1000
data pointer: 0x325530
The max_value of output: 16.053827
The min_value of output: -8.026914
The mean_value of output: 0.002078
The std_value of output: 11.213154
============ top5: ===========
283: 16.053827
281: 14.920615
282: 12.559759
285: 12.182022
287: 11.520982
最后生成hhb_out目录,如下
root@02297217e66d:/home/example/c908/onnx_mobilenetv2# ll hhb_out
total 17940
drwxr-xr-x 2 root root 4096 Jun 21 09:03 ./
drwxr-xr-x 5 root root 4096 Jun 21 09:02 ../
-rw-r--r-- 1 root root 3554304 Jun 21 09:03 hhb.bm
-rwxr-xr-x 1 root root 6140744 Jun 21 09:03 hhb_runtime*
-rw-r--r-- 1 root root 602112 Jun 21 09:03 input.0.bin
-rw-r--r-- 1 root root 2860548 Jun 21 09:03 input.0.tensor
-rw-r--r-- 1 root root 4946 Jun 21 09:03 io.c
-rw-r--r-- 1 root root 1539 Jun 21 09:03 io.h
-rw-r--r-- 1 root root 7410 Jun 21 09:03 main.c
-rw-r--r-- 1 root root 81352 Jun 21 09:03 main.o
-rw-r--r-- 1 root root 112618 Jun 21 09:03 model.c
-rw-r--r-- 1 root root 791576 Jun 21 09:03 model.o
-rw-r--r-- 1 root root 3546112 Jun 21 09:03 model.params
-rw-r--r-- 1 root root 602112 Jun 21 09:03 persian_cat.jpg.0.bin
-rw-r--r-- 1 root root 9534 Jun 21 09:03 persian_cat.jpg.0.bin_output0_1_1000.txt
-rw-r--r-- 1 root root 20086 Jun 21 09:03 process.c
-rw-r--r-- 1 root root 2040 Jun 21 09:03 process.h
将hhb_out目录拷贝到/mnt,导出到PC, 后续需要使用k230 rtt工具链重新交叉编译。
root@02297217e66d:/home/example/c908/onnx_mobilenetv2# cp -a hhb_out/ /mnt/
3. Demo
3.1 环境搭建
前置条件: 用户已按照 k230_sdk文档编译了docker image
启动k230 docker image
cd /path/to/k230_sdk
docker run -u root -it -v $(pwd):$(pwd) -v $(pwd)/toolchain:/opt/toolchain -w $(pwd) k230_docker /bin/bash
3.2 编译demo
我们在k230_sdk中提供了HHB的demo, 用户只需将HHB编译的c代码拷贝过来即可编译出上板运行的可执行程序。
相关目录说明
目录 | 备注 |
---|---|
/path/to/k230_sdk/src/big/utils/examples/hhb | 用户可修改CMakeLists.txt追加demo |
/path/to/k230_sdk/src/big/utils/lib目录下的csi-nn2和hhb-prebuilt-decode | c代码依赖的预编译库(csi-nn2/jpeg/png/zlib等, 使用musl交叉编译工具链编译) |
准备用例
mbv2_onnx_int8目录就是前面HHB生成的c代码, 用户修改了模型编译参数后, 需要同步更新过来.
用户也可以根据自己的模型,新增demo, 修改CMakeLists.txt即可。
开始编译
root@9d2a450436a7:/home/zhangyang/workspace/k230_sdk# cd src/big/utils/examples/hhb/
root@9d2a450436a7:/home/zhangyang/workspace/k230_sdk/src/big/utils/examples/hhb# ./build_app.sh
最后生成的可执行程序为out/bin/mbv2_onnx_int8.elf
root@9d2a450436a7:/home/zhangyang/workspace/k230_sdk/src/big/utils/examples/hhb# ll out/bin/mbv2_onnx_int8.elf
-rwxr-xr-x 1 root root 1172680 Jun 25 14:37 out/bin/mbv2_onnx_int8.elf*
将mbv2_onnx_int8运行的相关文件传送到小核linux的/sharefs目录
[root@canaan /sharefs/k230/mbv2_onnx_int8 ]#ls -l
total 5560
-rw-r--r-- 1 sshd sshd 3554304 Jun 25 2023 hhb.bm
-rwxr-xr-x 1 sshd sshd 1172680 Jun 25 2023 mbv2_onnx_int8.elf
-rw-r--r-- 1 sshd sshd 359355 Jun 25 2023 persian_cat.jpg
-rw-r--r-- 1 sshd sshd 602112 Jun 25 2023 persian_cat.jpg.0.bin
3.3 运行demo
- 启动k230, 在大核rtt串口下, 执行如下命令
msh />cd /sharefs/k230/mbv2_onnx_int8/
msh /sharefs/k230/mbv2_onnx_int8>./mbv2_onnx_int8.elf hhb.bm persian_cat.jpg.0.bin
Run graph execution time: 64.71648ms, FPS=15.45
=== tensor info ===
shape: 1 3 224 224
data pointer: 0x300170060
=== tensor info ===
shape: 1 1000
data pointer: 0x300194c80
The max_value of output: 15.581656
The min_value of output: -8.026914
The mean_value of output: 0.008405
The std_value of output: 11.703238
============ top5: ===========
283: 15.581656
281: 14.731747
282: 12.559759
285: 11.709850
287: 11.143245
msh /sharefs/k230/mbv2_onnx_int8>./mbv2_onnx_int8.elf hhb.bm persian_cat.jpg
Run graph execution time: 64.67589ms, FPS=15.46
=== tensor info ===
shape: 1 3 224 224
data pointer: 0x300170060
=== tensor info ===
shape: 1 1000
data pointer: 0x300194c80
The max_value of output: 16.053827
The min_value of output: -8.026914
The mean_value of output: 0.009821
The std_value of output: 12.815542
============ top5: ===========
283: 16.053827
281: 15.109484
282: 13.220798
287: 12.087587
285: 11.804284