若该文为原创文章,转载请注明原文出处。
一、环境
1、硬件:正点原子RV1126开发板
2、环境:ubuntu16.04
二、模型转换
训练后的模型不能直接使用在RV1126,需要转换一下模型
1、PaddlePaddle的模型转成推理模型
在前面有提过了;
训练模型保存为用于部署的推理模型
保存路径:output文件夹内
python tools/export_model.py -c "./configs/det/ch_ppocr_v2.0/ch_det_mv3_db_v2.0.yml_car_plate.yml" -o Global.pretrained_model="./output/ch_db_mv3/latest" Global.save_inference_dir="./output/"
2、转成onnx模型
PaddleOCR有一个专门的工具 paddle2onnx,
更多详情请参考Paddle2ONNX的Github主页
安装方法有两种:
# PIP 安装
$ pip install paddle2onnx
# 源码安装
$ git clone https://github.com/paddlepaddle/paddle2onnx
$ cd paddle2onnx
$ python setup.py install
安装后把推理模型转成onnx
paddle2onnx --model_dir cell_screen_inference --model_filename inference.pdmodel --params_filename inference.pdiparams --save_file first_det.onnx --enable_dev_version True --opset_version 13 --enable_onnx_checker True
3、验证onnx模型
写一个简单的脚本, 验证一下这个onnx文件有没有问题:
# 导入 ONNX 库
import onnx
# 载入 ONNX 模型
onnx_model = onnx.load("model.onnx")
# 使用 ONNX 库检查 ONNX 模型是否合理
check = onnx.checker.check_model(onnx_model)
# 打印检查结果
print('check: ', check)
输出check none表示正确
4、转成静态模型
OCR的模型, 它的输入图片大小是不固定的, 而rknn模型必须使用固定的输入图片大小
转换命令为
python -m paddle2onnx.optimize --input_model first_det.onnx --output_model static_model.onnx --input_shape_dict "{'x':[1,3,640,640]}"
三、RKNN NPU驱动升级
正点提供的rknn toolkit版本是1.7.1,这里需要升级成1.7.3
1、升级rknn toolkit
安装最新版本的rknn toolkit
https://github.com/rockchip-linux/rknn-toolkit/releases
我使用的是ubuntu版本,python使用3.8的版本,
解包之后, 使用pip install wheel, 然后 install requirement。
2、升级npu驱动
升级npu的驱动, clong rknn的npu仓库: GitHub - rockchip-linux/rknpu
README写得很清楚,要注意的是有些是软链接,这个要注意。
四、转成RKNN模型
有两种方式转化:
一、使用py脚本转换
(大佬博客提供的)
import os
from rknn.api import RKNN
import numpy as np
import onnxruntime as ort
onnx_model = 'model/static_model.onnx' #onnx路径
save_rknn_dir = 'model/static_model.rknn'#rknn保存路径
def norm(img):
mean = 0.5
std = 0.5
img_data = (img.astype(np.float32)/255 - mean) / std
return img_data
if __name__ == '__main__':
# Create RKNN object
rknn = RKNN(verbose=True)
# image = np.random.randn(1,3,32,448).astype(np.float32)
image = np.random.randn(1,3,640,640).astype(np.float32)
# image = np.random.randn(640,640,3,1).astype(np.float32)
# 创建一个np数组,分别用onnx和rknn推理看转换后的输出差异,检测模型输入是1,3,640,640 ,识别模型输入是1,3,32,448
onnx_net = ort.InferenceSession(onnx_model) # onnx推理
onnx_infer = onnx_net.run(None, {'x': norm(image)}) # 如果是paddle2onnx转出来的模型输入名字默认是 "x"
# pre-process config
print('--> Config model')
rknn.config(mean_values=[[127.5, 127.5, 127.5]], std_values=[[127.5, 127.5, 127.5]], reorder_channel='2 1 0', target_platform=['rv1126'], batch_size=4,quantized_dtype='asymmetric_quantized-u8') # 需要输入为RGB#####需要转化一下均值和归一化的值
# rknn.config(mean_values=[[0.0, 0.0, 0.0]], std_values=[[255, 255, 255]], reorder_channel='2 1 0', target_platform=['rv1126'], batch_size=1) # 需要输入为RGB
print('done')
# model_name = onnx_model[onnx_model.rfind('/') + 1:]
# Load ONNX model
print('--> Loading model %s' % onnx_model)
ret = rknn.load_onnx(model=onnx_model)
if ret != 0:
print('Load %s failed!' % onnx_model)
exit(ret)
print('done')
# Build model
print('--> Building model')
# rknn.build(do_quantization=False)
ret = rknn.build(do_quantization=True, dataset='coco_dataset_1.txt', pre_compile=True)
# do_quantization是否对模型进行量化,datase量化校正数据集,pre_compil模型预编译开关,预编译 RKNN 模型可以减少模型初始化时间,
# 但是无法通过模拟器进行推理或性能评估
if ret != 0:
print('Build net failed!')
exit(ret)
print('done')
# Export RKNN model
print('--> Export RKNN model')
ret = rknn.export_rknn(save_rknn_dir)
if ret != 0:
print('Export rknn failed!')
exit(ret)
ret = rknn.init_runtime(target='rv1126',device_id="a9d00ab1f032c17a")
# 两个参数分别是板子型号和device_id,device_id在双头usb线连接后通过 adb devices查看
if ret != 0:
print('init runtime failed.')
exit(ret)
print('done')
# Inference
print('--> Running model')
outputs = rknn.inference(inputs=[image])
# perf
print('--> Begin evaluate model performance')
perf_results = rknn.eval_perf(inputs=[image]) # 模型评估
print('done')
print()
print("->>模型前向对比!")
print("--------------rknn outputs--------------------")
print(outputs[0])
print()
print("--------------onnx outputs--------------------")
print(onnx_infer[0])
print()
std = np.std(outputs[0]-onnx_infer[0])
print(std) # 如果这个值比较大的话,说明模型转换后不太理想
rknn.release()
需要修改的地方有两个:
一:模型路径(onnx路径和rknn路径)
二:设备ID,ID为板子的ID,需要先查询出来,具体yolov5有提及。
二、使用rknn_model_zoo转换模型
下载最新版本的rknn_model_zoo,并把onnx转成RKNN,这个没测试过,具体自行测试。
测试在前面已经有测试过了,不在过多描述,代码git上有大佬开源,请自行去下载测试。
如有侵权,或需要完整代码,请及时联系博主。