RKNN 模型转换详解:从 PyTorch 到 RKNN 全流程
2026/7/13 2:48:11 网站建设 项目流程

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# 加载模型model=YOLO('yolov8n.pt')model.eval()# 导出 ONNXmodel.export(format='onnx',imgsz=640,opset=12,simplify=True)

Ultralytics 自带导出,很方便。

手动导出(自定义模型)

importtorchimporttorch.onnx model=YourModel()model.load_state_dict(torch.load('model.pth'))model.eval()# 虚拟输入dummy_input=torch.randn(1,3,640,640)# 导出torch.onnx.export(model,dummy_input,'model.onnx',opset_version=12,# RKNN 推荐 11/12input_names=['images'],output_names=['output'],dynamic_axes=None# RKNN 不支持动态 shape,固定尺寸)

导出注意事项

  1. opset 版本:RKNN 推荐 11 或 12,太高的版本有些算子不支持
  2. 固定尺寸:RKNN 不支持动态 shape,输入尺寸必须固定
  3. 训练模式关掉:一定要 model.eval(),不然 dropout、BN 这些推理模式不对
  4. 不要有控制流:if/for 这些动态逻辑 ONNX 导出可能有问题

验证 ONNX 正确性

导出完先在 PC 上验证 ONNX 的输出和 PyTorch 一致:

importonnxruntimeasortimportnumpyasnp# PyTorch 输出torch_out=model(dummy_input).detach().numpy()# ONNX 输出session=ort.InferenceSession('model.onnx')onnx_out=session.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 model=onnx.load('model.onnx')model_simp,check=simplify(model)assertcheck,"简化失败"onnx.save(model_simp,'model_simplified.onnx')

简化的好处

  1. 去掉冗余算子,模型更小
  2. 减少 RKNN 不支持的算子(比如一些奇怪的 reshape 组合)
  3. 量化更准确,计算更快

强烈建议每次都做,没什么坏处。


四、第三步:转 RKNN + 量化

用 RKNN Toolkit2 来转换。

环境准备

RKNN Toolkit2 只能在 x86 Ubuntu 上跑(或者 WSL),Windows 原生不支持。

pipinstallrknn-toolkit2

完整转换代码

fromrknn.apiimportRKNN# 1. 创建 RKNN 对象rknn=RKNN(verbose=True)# 2. 配置rknn.config(mean_values=[[0,0,0]],# 归一化均值std_values=[[255,255,255]],# 归一化标准差target_platform='rk3588',# 目标平台quant_img_RGB2BGR=False,# 输入是否 BGRoptimization_level=3,# 优化等级 0-3single_core_mode=False,# 单核心模式(默认三核))# 3. 加载 ONNXrknn.load_onnx(model='model_simplified.onnx')# 4. 构建(编译 + 量化)ret=rknn.build(do_quantization=True,# 是否量化dataset='dataset.txt',# 校准图片列表rknn_batch_size=1,# 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

目标芯片型号:

  • rk3588:RK3588
  • rk3568:RK3568
  • rk3566:RK3566

optimization_level

优化等级 0-3,越高优化越激进:

  • 0:不优化
  • 3:最高优化(默认)

一般用 3 就行。

quantized_dtype

量化精度:

  • asymmetric_quantized-8:非对称 INT8(默认,推荐)
  • dynamic_fixed_point-8:对称 INT8
  • w8a16:权重 INT8,激活 FP16(精度高,速度慢一点)

do_quantization

  • True:INT8 量化(推荐,速度快)
  • False:FP16,不量化(精度高,速度慢)

先试量化版,精度不够再考虑 FP16。


六、常见算子支持问题

RKNN 不是所有 ONNX 算子都支持,遇到不支持的算子会回退到 CPU 跑,巨慢。

支持良好的算子

  • Conv、ConvTranspose
  • BatchNormalization(会被融合)
  • ReLU、ReLU6、LeakyReLU、SiLU
  • MaxPool、AvgPool
  • Add、Mul、Concat
  • Resize(最近邻、双线性)
  • Sigmoid、Tanh
  • Reshape、Transpose、Flatten

可能有问题的算子

  • 复杂的 Upsample 模式
  • Group Normalization
  • 各种花式注意力(SE、CBAM 等)
  • 大 kernel 的 Depthwise Conv
  • 动态 shape 相关的算子

遇到不支持的算子怎么办?

  1. 替换算子:把不支持的换成支持的等价实现
  2. 后处理移到 CPU:检测头的 NMS 这些放 CPU 做,别塞进模型里
  3. 自定义算子:RKNN 支持自定义算子,开发成本高
  4. 换模型结构:选 NPU 友好的结构

💡 经验:YOLOv5/v8 的标准结构 RKNN 支持都很好,基本不用改。自己设计的模型要注意尽量用标准算子。


七、转换后精度验证

转完一定要验精度,别直接拿到设备上用。

方法 1:RKNN Toolkit 自带精度分析

# 量化误差分析rknn.accuracy_analysis(inputs=['test_image.jpg'],output_dir='./analysis',target='rk3588')

会输出每层的量化误差,找出误差大的层。

方法 2:PC 端模拟推理对比

RKNN Toolkit 可以在 PC 上模拟 NPU 推理,对比 ONNX 和 RKNN 的输出差异:

# ONNX 输出(FP32 基准)importonnxruntime session=onnxruntime.InferenceSession('model.onnx')onnx_out=session.run(None,{'images':input_data})[0]# RKNN 模拟输出(模拟 INT8 结果)rknn.load_rknn('model.rknn')rknn.init_runtime(target=None)# None 就是 PC 模拟rknn_out=rknn.inference(inputs=[input_data])[0]# 对比importnumpyasnp diff=np.abs(onnx_out-rknn_out).mean()print(f"平均误差:{diff}")

误差在可接受范围内再上板。

方法 3:上板实测 mAP

最终还是要在真实设备上跑测试集,算 mAP,和 PC 端对比。

掉点 1-2 个点正常,掉太多就要调量化了。


八、转换常见的坑

坑 1:输出结果完全不对

原因通常是预处理没对齐:

  • mean/std 设错了
  • RGB/BGR 搞反了
  • 图像缩放方式不一样(letterbox 还是直接 resize)

解决:逐个对比预处理步骤,确保和训练时完全一致。

坑 2:转换成功但推理特别慢

原因:有算子不支持,回退到 CPU 跑了。

解决:看转换日志,搜fallbackCPU关键字,找到不支持的算子替换掉。

坑 3:量化后精度掉很多

  • 校准数据不具代表性 → 换校准集
  • 校准方法不合适 → 调量化参数
  • 某些层误差大 → 那层指定不量化
  • 模型本身不适合量化 → 考虑 FP16 或 QAT

坑 4:YOLO 检测头输出乱

原因:YOLO 的后处理(解码、NMS)不能直接转,要拿原始输出自己在 CPU 做后处理。

解决:导出时不要把 NMS 塞进模型,拿 raw output,推理完自己写后处理。

坑 5:动态 shape 报错

RKNN 不支持动态输入尺寸。导出 ONNX 时固定好尺寸,不要 dynamic_axes。


九、RKNN 文件推送到设备

转好的 .rknn 文件拷到 RK3588 开发板上,用 RKNN Runtime 推理。

C++ 推理代码大致结构

#include<rknn_api.h>// 1. 初始化rknn_context ctx;rknn_init(&ctx,model_data,model_size,0,NULL);// 2. 设置输入rknn_input inputs[1];inputs[0].index=0;inputs[0].buf=image_data;inputs[0].size=size;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 量化实战调优:量化精度不够怎么办,怎么分析误差、怎么调参数。

我是黒漂技术佬。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询