RKNN 模型转换详解:从 PyTorch 到 RKNN 全流程 RKNN 模型转换详解从 PyTorch 到 RKNN 全流程RK3588 上跑模型必须转成 RKNN 格式才能用 NPU 加速。这篇讲完整的转换流程PyTorch → ONNX → 简化 → RKNN以及量化配置、常见算子问题、转换失败排查。大家好我是黒漂技术佬。RK3588 的 NPU 算力很强但不是随便拿个模型就能跑的——必须转换成瑞芯微自家的 RKNN 格式。转换过程看着简单实际上坑不少算子不支持、量化精度掉、转换报错、推理结果不对……这篇把 RKNN 模型转换的完整流程讲清楚从 PyTorch 训练好的模型到能在 RK3588 上跑的 RKNN 文件一步一步来。一、整体流程PyTorch 模型 (.pt) ↓ 导出 ONNX 模型 (.onnx) ↓ 简化可选但推荐 简化后的 ONNX ↓ RKNN Toolkit 转换 量化 RKNN 模型 (.rknn) ↓ 推送到设备 RK3588 NPU 推理三步导出 ONNX → ONNX 优化 → 转 RKNN 量化。二、第一步PyTorch 导出 ONNX基本导出代码importtorchfromultralyticsimportYOLO# 加载模型modelYOLO(yolov8n.pt)model.eval()# 导出 ONNXmodel.export(formatonnx,imgsz640,opset12,simplifyTrue)Ultralytics 自带导出很方便。手动导出自定义模型importtorchimporttorch.onnx modelYourModel()model.load_state_dict(torch.load(model.pth))model.eval()# 虚拟输入dummy_inputtorch.randn(1,3,640,640)# 导出torch.onnx.export(model,dummy_input,model.onnx,opset_version12,# RKNN 推荐 11/12input_names[images],output_names[output],dynamic_axesNone# RKNN 不支持动态 shape固定尺寸)导出注意事项opset 版本RKNN 推荐 11 或 12太高的版本有些算子不支持固定尺寸RKNN 不支持动态 shape输入尺寸必须固定训练模式关掉一定要 model.eval()不然 dropout、BN 这些推理模式不对不要有控制流if/for 这些动态逻辑 ONNX 导出可能有问题验证 ONNX 正确性导出完先在 PC 上验证 ONNX 的输出和 PyTorch 一致importonnxruntimeasortimportnumpyasnp# PyTorch 输出torch_outmodel(dummy_input).detach().numpy()# ONNX 输出sessionort.InferenceSession(model.onnx)onnx_outsession.run(None,{images:dummy_input.numpy()})[0]# 对比误差print(np.max(np.abs(torch_out-onnx_out)))# 误差应该很小1e-5 级别误差大说明导出有问题先解决再往下走。三、第二步ONNX 简化onnx-simplifier导出的 ONNX 里有很多冗余算子identity、常量折叠等简化一下安装pipinstallonnx-simplifier使用onnxsim model.onnx model_simplified.onnx或者 Python 代码fromonnxsimimportsimplifyimportonnx modelonnx.load(model.onnx)model_simp,checksimplify(model)assertcheck,简化失败onnx.save(model_simp,model_simplified.onnx)简化的好处去掉冗余算子模型更小减少 RKNN 不支持的算子比如一些奇怪的 reshape 组合量化更准确计算更快强烈建议每次都做没什么坏处。四、第三步转 RKNN 量化用 RKNN Toolkit2 来转换。环境准备RKNN Toolkit2 只能在 x86 Ubuntu 上跑或者 WSLWindows 原生不支持。pipinstallrknn-toolkit2完整转换代码fromrknn.apiimportRKNN# 1. 创建 RKNN 对象rknnRKNN(verboseTrue)# 2. 配置rknn.config(mean_values[[0,0,0]],# 归一化均值std_values[[255,255,255]],# 归一化标准差target_platformrk3588,# 目标平台quant_img_RGB2BGRFalse,# 输入是否 BGRoptimization_level3,# 优化等级 0-3single_core_modeFalse,# 单核心模式默认三核)# 3. 加载 ONNXrknn.load_onnx(modelmodel_simplified.onnx)# 4. 构建编译 量化retrknn.build(do_quantizationTrue,# 是否量化datasetdataset.txt,# 校准图片列表rknn_batch_size1,# batch size)ifret!0:print(构建失败)exit(ret)# 5. 保存 RKNN 模型rknn.export_rknn(model.rknn)# 6. 释放rknn.release()dataset.txt 格式校准数据集的图片路径列表每行一个data/calib/0001.jpg data/calib/0002.jpg data/calib/0003.jpg ...一般 200-1000 张就够了要有代表性覆盖各种场景。五、config 关键参数详解mean_values / std_values预处理的归一化参数。RKNN 会把归一化融合到模型里推理时不用手动做。YOLO 的归一化是除以 255所以mean [0, 0, 0]std [255, 255, 255]如果你的预处理是(img - mean) / std对应填进去就行。target_platform目标芯片型号rk3588RK3588rk3568RK3568rk3566RK3566optimization_level优化等级 0-3越高优化越激进0不优化3最高优化默认一般用 3 就行。quantized_dtype量化精度asymmetric_quantized-8非对称 INT8默认推荐dynamic_fixed_point-8对称 INT8w8a16权重 INT8激活 FP16精度高速度慢一点do_quantizationTrueINT8 量化推荐速度快FalseFP16不量化精度高速度慢先试量化版精度不够再考虑 FP16。六、常见算子支持问题RKNN 不是所有 ONNX 算子都支持遇到不支持的算子会回退到 CPU 跑巨慢。支持良好的算子Conv、ConvTransposeBatchNormalization会被融合ReLU、ReLU6、LeakyReLU、SiLUMaxPool、AvgPoolAdd、Mul、ConcatResize最近邻、双线性Sigmoid、TanhReshape、Transpose、Flatten可能有问题的算子复杂的 Upsample 模式Group Normalization各种花式注意力SE、CBAM 等大 kernel 的 Depthwise Conv动态 shape 相关的算子遇到不支持的算子怎么办替换算子把不支持的换成支持的等价实现后处理移到 CPU检测头的 NMS 这些放 CPU 做别塞进模型里自定义算子RKNN 支持自定义算子开发成本高换模型结构选 NPU 友好的结构 经验YOLOv5/v8 的标准结构 RKNN 支持都很好基本不用改。自己设计的模型要注意尽量用标准算子。七、转换后精度验证转完一定要验精度别直接拿到设备上用。方法 1RKNN Toolkit 自带精度分析# 量化误差分析rknn.accuracy_analysis(inputs[test_image.jpg],output_dir./analysis,targetrk3588)会输出每层的量化误差找出误差大的层。方法 2PC 端模拟推理对比RKNN Toolkit 可以在 PC 上模拟 NPU 推理对比 ONNX 和 RKNN 的输出差异# ONNX 输出FP32 基准importonnxruntime sessiononnxruntime.InferenceSession(model.onnx)onnx_outsession.run(None,{images:input_data})[0]# RKNN 模拟输出模拟 INT8 结果rknn.load_rknn(model.rknn)rknn.init_runtime(targetNone)# None 就是 PC 模拟rknn_outrknn.inference(inputs[input_data])[0]# 对比importnumpyasnp diffnp.abs(onnx_out-rknn_out).mean()print(f平均误差:{diff})误差在可接受范围内再上板。方法 3上板实测 mAP最终还是要在真实设备上跑测试集算 mAP和 PC 端对比。掉点 1-2 个点正常掉太多就要调量化了。八、转换常见的坑坑 1输出结果完全不对原因通常是预处理没对齐mean/std 设错了RGB/BGR 搞反了图像缩放方式不一样letterbox 还是直接 resize解决逐个对比预处理步骤确保和训练时完全一致。坑 2转换成功但推理特别慢原因有算子不支持回退到 CPU 跑了。解决看转换日志搜fallback、CPU关键字找到不支持的算子替换掉。坑 3量化后精度掉很多校准数据不具代表性 → 换校准集校准方法不合适 → 调量化参数某些层误差大 → 那层指定不量化模型本身不适合量化 → 考虑 FP16 或 QAT坑 4YOLO 检测头输出乱原因YOLO 的后处理解码、NMS不能直接转要拿原始输出自己在 CPU 做后处理。解决导出时不要把 NMS 塞进模型拿 raw output推理完自己写后处理。坑 5动态 shape 报错RKNN 不支持动态输入尺寸。导出 ONNX 时固定好尺寸不要 dynamic_axes。九、RKNN 文件推送到设备转好的 .rknn 文件拷到 RK3588 开发板上用 RKNN Runtime 推理。C 推理代码大致结构#includerknn_api.h// 1. 初始化rknn_context ctx;rknn_init(ctx,model_data,model_size,0,NULL);// 2. 设置输入rknn_input inputs[1];inputs[0].index0;inputs[0].bufimage_data;inputs[0].sizesize;rknn_inputs_set(ctx,1,inputs);// 3. 推理rknn_run(ctx,NULL);// 4. 拿输出rknn_output outputs[3];rknn_outputs_get(ctx,3,outputs,NULL);// 5. 后处理NMS 等// ...// 6. 释放rknn_outputs_release(ctx,3,outputs);rknn_destroy(ctx);Python 也有对应的 rknnlite 库用法类似。十、本篇小结转换三步导出 ONNX → 简化 → 转 RKNN 量化ONNX 导出注意opset 12、固定尺寸、eval 模式onnx-simplifier 必做减少冗余算子RKNN 配置mean/std、目标平台、量化开关校准集 200-1000 张要有代表性转换后验证精度先 PC 模拟对比再上板测 mAP常见问题算子不支持回退 CPU、预处理不对齐、量化掉点下一篇讲RKNN 量化实战调优量化精度不够怎么办怎么分析误差、怎么调参数。我是黒漂技术佬。