3. ONNX模型转换与量化

任务目标

本案例将完成一个完整的ONNX→RKNN转换与量化闭环:以MobileNetV2分类模型为例,使用RKNN-Toolkit2将ONNX模型转换为RKNN格式,并执行INT8量化。通过本案例,你将掌握量化配置、图像预处理与推理验证的完整流程。

环境依赖

  • RKNN-Toolkit2(版本≥1.6.0),安装方法:pip install rknn-toolkit2
  • Python 3.8+,需安装onnx、numpy、Pillow
  • 模型文件:mobilenetv2.onnx(可从ONNX Model Zoo下载,输入尺寸224×224)
  • 测试图片:任意224×224的猫或狗图片(如cat.jpg)

关键实现

以下代码完成ONNX模型加载、量化配置、转换与单张图片推理验证。量化数据集使用20张图片(代码中通过dataset.txt指定路径列表),RKNN-Toolkit2会自动完成数据预处理与校准。

from rknn.api import RKNN
import numpy as np
from PIL import Image

# 1. 创建RKNN对象并配置量化参数
rknn = RKNN(verbose=True)
rknn.config(
    mean_values=[[123.675, 116.28, 103.53]],
    std_values=[[58.395, 57.12, 57.375]],
    target_platform='rk3588',
    quantized_dtype='asymmetric_quantized-8',  # INT8量化
    quantized_algorithm='normal',               # 默认量化算法
    optimization_level=3
)

# 2. 加载ONNX模型
ret = rknn.load_onnx(model='mobilenetv2.onnx')
assert ret == 0, 'ONNX模型加载失败'

# 3. 构建量化数据集(dataset.txt每行一个图片路径)
# 示例内容:cat.jpg / dog.jpg / ...(共20张)
ret = rknn.build(do_quantization=True, dataset='dataset.txt')
assert ret == 0, '模型转换或量化失败'

# 4. 导出RKNN模型
ret = rknn.export_rknn('mobilenetv2.rknn')
assert ret == 0, 'RKNN模型导出失败'

# 5. 初始化运行时环境并推理验证
ret = rknn.init_runtime(target=None)  # None表示在PC上模拟运行
assert ret == 0, '运行时初始化失败'

# 6. 加载并预处理测试图片
img = Image.open('cat.jpg').resize((224, 224))
img = np.array(img).astype(np.float32)
# 注意:config中已设置mean/std,此处只需做HWC→CHW
img = img.transpose(2, 0, 1)[None, ...]

# 7. 执行推理
outputs = rknn.inference(inputs=[img])
pred = np.argmax(outputs[0])
print(f'预测类别索引: {pred}')

# 8. 释放资源
rknn.release()

运行与验证

  1. 准备dataset.txt,每行一个图片路径(建议20张以上不同类别图片,覆盖常见物体),图片尺寸无需统一,工具会自动缩放至224×224。
  2. 执行脚本:python convert_quantize.py。若转换成功,当前目录生成mobilenetv2.rknn文件。
  3. 验证通过条件:
    - 脚本无报错,build阶段输出量化前后的精度对比(若提供验证集);
    - 推理输出类别索引与测试图片内容相符(如猫图输出282,狗图输出208,对应ImageNet类别);
    - 生成的.rknn文件大小约为原始ONNX的1/4(INT8量化效果)。

常见问题

  • 量化精度下降明显:增加dataset.txt中图片数量至50~100张,或改用quantized_algorithm='mmse'(需安装额外依赖)。
  • ONNX算子不支持:RKNN-Toolkit2对ONNX算子覆盖有限,可先运行rknn.load_onnx后查看警告,必要时简化模型结构。
  • PC模拟与板端差异:init_runtime(target=None)为PC模拟,精度与板端基本一致;若需板端部署,将target改为'rk3588'并通过USB连接设备。