0x00 说明
本文档中RKNN-SDK 位于 ~/rk1808_linux_v1.00_20181227/
RKNN-Toolkit 和 RKNN demo 包位于 ~/rk1808_linux_v1.00_20181227/external/rknpu/
其中 rknn 文件夹为 RKNN demo,用于生成可在开发板上运行的可执行文件,rknn-toolkit 用于将其他模型转换成 rknn 模型并在 PC 上进行性能测试。
0x01 环境配置
OS: Ubuntu 16.04 x64 以上
Python: 3.5/3.6
Tensorflow: >= 1.11.0
使用 Anaconda3 安装: Anaconda3-2019.03-Linux-x86_64.sh
安装 ADB
apt install android-tools-adb
安装后配置:
由于 conda 镜像中处理 Tensorflow 1.11.0 依赖时会降低其他库的版本,这里使用 Tensorflow 1.13.1。
conda install python=3.7
conda install tensorflow=1.13.1
conda install opencv=3.4.1
pip install ~/rk1808_linux_v1.00_20181227/external/rknpu/rknn-toolkit/packages/rknn_toolkit-0.9.8-cp36-cp36m-linux_x86_64.whl
0x02 转换模型
转换模型使用 RKNN-Toolkit,SDK 中提供了三种基于 MobileNet 的转换工具,位于 ~/rk1808_linux_v1.00_20181227/external/rknpu/rknn-toolkit/example
目录下,本文档以使用 mobilenet-ssd 转换 Tensorflow 的 .pb
模型为例。
进入 mobilenet-ssd
目录下,运行 ssd.py
cd ~/rk1808_linux_v1.00_20181227/external/rknpu/rknn-toolkit/example/mobilenet-ssd
python ssd.py
转换成功后输出如下:
--> Loading model
done
--> Building model
done
--> Init runtime environment
done
--> Running model
done
inference resule: [array([[ 0.89453125, 0.18859863, -3.0390625 , ..., -0.0308075 ,
-2.4863281 , -0.10644531]], dtype=float32), array([[ 2.4785156, -4.7382812, -7.9335938, ..., -10.0859375,
-9.625 , -10.4140625]], dtype=float32)]
========================================================================
Performance
========================================================================
Layer Id Name Time(us)
0 convolution.relu.pooling.layer2_3 1005
1 activation.layer_3 510
2 convolution.relu.pooling.layer2_2 774
3 activation.layer_3 510
''''''
91 fullyconnected.relu.layer_3 17
92 tensor.ranspose_3 4
93 tensor.ranspose_3 5
Total Time(us): 165830
FPS(800MHz): 6.03
========================================================================
转换其他模型:
修改 ssd.py
中 rknn.load_tensorflow
,tf_pb
为 .pb
模型文件的路径;input
为模型输入节点;output
为模型输出节点;input_size_list
为输入节点对应的图片尺寸和通道数。
rknn.config
方法中 channel_mean_value
为模型均值;reorder_channel
为通道顺序,0 1 2
为 RGB,2 1 0
为 BGR。
rknn.build
方法中 do_quantization
为生成 rknn 模型是否进行量化的控制参数,dataset
为进行量化时使用的图片,建议大于 200 张。
如果将 do_quantization
设置为 True
,根据情况(可能报错)需要在 rknn.config
方法中添加参数 batch_size
和 epochs
,如果性能足够可以设置 batch_size=200,epochs=1
,如果显存不足可以设置为 batch_size=1,epochs=200
。
rknn.export_rknn
方法用于设置 rknn 模型输出路径及文件名称。
rknn.export_rknn
方法后面的代码可以对导出的 rknn 模型进行性能评估。
注意:如果在性能评估或检测时发生检测出目标数量过多的情况,请检查 rknn_inference
方法输出的数组元素顺序是否需要调换,例如:
outputs = rknn.inference(inputs=[img])
predoctions = outputs[1].reshape((1, NUM_RESULTS, 4))
outputClasses = outputs[0].reshape((1, NUM_RESULTS, NUM_CLASSES))
其中 predictions
在 SDK 提供的模型中使用 outputs[0]
中的值,而在自行转换的模型中需要使用 outputs[1]
,的值,outputClasses
同理。
如果在转换模型时发现了这个问题,在 demo 的 main.cc
中也需要修改 outputs
数组顺序,例如:
postProcessSSD((float *)(outputs[1].buf), (float *)(outputs[0].buf). orig_img.cols, orig_img.rows, &detect_result_group);
如果出现了上述错误,应尝试将这段代码修改为:
postProcessSSD((float *)(outputs[0].buf), (float *)(outputs[1].buf). orig_img.cols, orig_img.rows, &detect_result_group);
0x03 在开发板上运行 demo
SDK 中提供了三种基于 MobileNet 的 demo
位于 ~/rk1808_linux_v1.00_20181227/external/rknpu/rknn/examples
目录下,本文档以调用由 MobileNet-SSD Tensorflow pb 模型转换的 rknn 模型使用 rknn_ssd_demo 对 road.bmp
进行目标检测为例。
过程如下:
进入 demo 目录,建立 build
文件夹
cd ~/rk1808_linux_v1.00_20181227/external/rknpu/rknn/examples/rknn_ssd_demo
mkdir build
cd build
编译
cmake ..
make
make install
cd ..
此时 demo 目录下应出现 install
文件夹,如果没有请检查环境是否符合要求
将生成的 rknn 模型放入 install/rknn_ssd_demo
文件夹
例如生成的 rknn 模型位于 ~/rk1808_linux_v1.00_20181227/external/rknpu/rknn-toolkit/examples/mobilenet-ssd
模型名称为 ssd_mobilenet_v1_coco.rknn
cp ../../../rknn-toolkit/example/mobilenet-ssd/ssd_mobilenet_v1_coco.rknn ./install/rknn_ssd_demo
测试 adb 连接
adb devices
如果返回类似如下的数据,则连接成功,否则请检查设备与开发机的连接
List of devices attached
0123456789ABCDEF device
在设备中建立 /userdata/rknn_ssd_demo
目录并将 install
下的 rknn_ssd_demo
文件夹 push 进创建的目录中
adb shell mkdir /userdata/rknn_ssd_demo
adb push ./install/rknn_ssd_demo/* /userdata/rknn_ssd_demo
进入设备终端并进行检测
adb shell
cd /userdata/rknn_ssd_demo
./rknn_ssd_demo ssd_mobilenet_v1_coco.rknn road.bmp
检测成功后输出如下:
Loading model ...
model input num: 1, output num: 2
input tensors:
index=0 name = n_dims=4 dims=[1 3 300 300] n_elems=270000 size=540000 fmt=0 type=1 qnt_type=0 fl=-84 zp=-1311164756 scale=0.000000
output tensors:
index=0 name = n_dims=4 dims=[1 1917 1 4] n_elems=7668 size=15336 fmt=0 type=1 qnt_type=0 fl=-84 zp=-1311164756 scale=0.000000
index=1 name = n_dims=3 dims=[0 1 1917 91] n_elems=174447 size=348894 fmt=0 type=1 qnt_type=0 fl=-84 zp=-1311164756 scale=0.000000
rknn_run
loadLabelName
ssd - loadLabelNameloadBoxPriors
ValidCount: 25
person @ (15 127 55 209) 0.984575
bicycle @ (170 158 283 233) @ 0.958382
person @ (107 119 152 192) 0.948155
car @ (148 134 215 173) 0.930078
person @ (207 112 256 218) 0.838812
person @ (50 135 58 158) 0.470782
person @ (83 133 92 156) 0.433082
退出设备终端并将检测后生成的 out.jpg 拉回本地
exit
adb pull /userdata/rknn_ssd_demo/out.jpg ./
0x04 自动化脚本
该部分中所有操作均在 demo 目录下进行
在设备中检测
建立 adb_run_rknn_ssd
文件,并写入如下命令,用于在开发机中直接导入设备终端的命令。
cd /userdata/rknn_ssd_demo
./rknn_ssd_demo ssd_mobilenet_v1_coco.rknn road.bmp
exit
在设备中执行检测并将 out.jpg
拉到本地
$ adb shell < adb_run_rknn_ssd && \
> adb pull /userdata/rknn_ssd_demo/out.jpg ./
重新编译代码,在设备中执行检测,并将 out.jpg
拉到本地
cd build/ && \
rm -rf * && \
cmake .. && \
make && \
make install && \
cd .. && \
adb shell mkdir rknn_ssd_demo && \
adb push ./install/rknn_ssd_demo/* /userdata/rknn_ssd_demo/ && \
adb shell < adb_run_rknn_ssd && \
adb pull /userdata/rknn_ssd_demo/out.jpg ./