书接上回…
第七步, 把PaddlePaddle的模型, 转成onnx模型, 因为最重要转成rknn, 而onnx是所有转模型的一个中间点.yolo的pt也是要先转onnx再转rknn的.
这一步坑挺多.
首先PaddleOCR有一个专门的工具, 很好用, 叫paddle2onnx, 顾名思义, 直接就能转, 用pip就可以安装.
装好之后
paddle2onnx --model_dir cell_screen_0625_inference --model_filename inference.pdmodel --params_filename inference.pdiparams --save_file first_det_0625.onnx --enable_dev_version True --opset_version 13 --enable_onnx_checker True
你要在刚才转好的推理模型的output目录下面运行这个命令, 第一个参数是你推理模型的文件夹, 然后只需要修改你要保存的的.onnx文件名.
就是把推理的三个文件, 转成了下面的这个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表示正确
你也可以考虑下载这个onnx文件下来用netron.app看看长啥样.
接下来坑就来了, 因为OCR的模型, 它的输入图片大小是不固定的, 而rknn模型必须使用固定的输入图片大小, 所以需要对模型稍作修改, 先从github下载一下Paddle2Onnx的仓库, 然后在仓库外面, 记住是外面(不然会报找不到version模块错误), 运行:
python -m paddle2onnx.optimize --input_model first_det_0625.onnx --output_model static_model_0625.onnx --input_shape_dict "{'x':[1,3,640,640]}"
意思就是把是first_det_0625.onnx, 从动态输入修改为固定大小输入, 固定为1,3,640,640.
然后你用nettron.app可以看到onnx头部长这样, 之前可能是个?表示动态输入.
最后一步, 就是在本地的ubuntu环境, 安装rknn-toolkit 1.7.3 ,必须是1.7.3, 方法是在github找到1.7.3的wheel文件压缩包, pip安装wheel, 然后安装requirement.txt, 安装好rknn-toolkit, 具体方法可以看看rk的官方github.
接着把你的rv1126插到ubuntu上, 运行转模型的py脚本(这个脚本是来自上一篇的提到的大佬的博客):
import os
from rknn.api import RKNN
import numpy as np
import onnxruntime as ort
onnx_model = 'model/static_model_0625.onnx' #onnx路径
save_rknn_dir = 'model/static_model_0625.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()
修改一下输入输出的模型文件的位置, 然后建一个coco_dataset_1.txt文件, 里面放一个图片的文件名
用来做量化用, 然后pre_compile用True或者False都可以, 如果用False模型加载大概需要30秒到1分钟.
另外修改一下你1126的adb device_id.
ret = rknn.init_runtime(target='rv1126',device_id="a9d00ab1f032c17a")
顺利的话, 就会生成一个rknn文件, 放到板子上就可以推理了, 具体推理用的代码, 去我github搜一下即可.