
简介基于YOLOv11目标检测模型的跨平台转换工具包面向需要在瑞芯微Rockchip芯片上部署目标检测模型的开发者与嵌入式AI工程师。工具聚焦ONNX到RKNN格式转换内置量化选项用于优化推理速度并配备从RKNN-Toolkit2环境安装、模型转换到精度验证的完整指南可帮助用户规避常见坑点、缩短调试周期。压缩包为zip格式约14.21MB共15个文件以Python转换脚本、ONNX与RKNN模型文件、测试图片、Markdown说明文档和附赠Word资料为主环境截图与结果对比图覆盖安装与推理关键环节便于按文档逐步复现。已有69人学习浏览适合正在尝试NPU加速或需要将YOLOv11迁移到瑞芯微平台的算法部署人员。通过附带的测试图片与转换前后模型文件读者可直接验证推理效果并参照说明完成自定义模型替换、量化参数调整与后续调优。1. 为什么要在 YOLOv11 与 Rockchip 之间多走一条 ONNX 到 RKNN 的转换路在 Rockchip 板卡上跑 YOLOv11绕不开 ONNX 到 RKNN 这一段。常见误区是直接拿 ultralytics 训练出的 .pt 权重喂给板端实际会卡在第一步rknn-toolkit2 对 TorchScript 的解析支持远不如 ONNX 完整把 YOLOv11 先导成 ONNX 再转 RKNN是转换成功率最高的路径。这类跨平台转换工具的核心价值不是把文件换个后缀而是把 ONNX 里的算子逐个映射到 RKNPU 支持的算子集上同时把 int8 量化误差控制在目标场景能接受的范围内。适合正在做边端部署、手里有 RK3566/RK3588 等开发板想把 YOLOv11 跑进 NPU 的工程师。要记住一点转换通过不代表板上检测可用后面一半工作量在量化校准和算子验证上。2. 环境配置按芯片型号对齐 RKNN-Toolkit2、驱动和 Python 虚拟环境2.1 主机与板端的角色划分为什么要先在 x86_64 上做转换环境配置的第一个原则RKNN 的模型转换和模型部署发生在两个不同环境里。转换端是一台 x86_64 主机通常装全套 rknn-toolkit2它承担 ONNX 解析、算子优化和 int8 量化板端是 Rockchip 设备只装运行库 rknn-toolkit-lite 或 librknnrt。转换工具要支持跨平台大多数封装实现里都会把这两段分开转换脚本跑在主机推理脚本跑在板子。所以安装环境前先确认三个版本rknn-toolkit2 版本、目标芯片型号、板端 NPU 驱动版本。三者不匹配时最常见的结果是模型转换成功但板端init_runtime报版本错误。版本对齐不是玄学。Rockchip 官方会为每代芯片发布配套的 NPU 驱动和工具链比如 RK3588 系列和 RK3566 系列需要的 rknn-toolkit2 版本区间不同。具体版本号会随固件更新建议以板卡厂商提供的固件 release note 为准。我一般会在主机上维护多个 Python venv每个 venv 对应一个目标板固件版本避免换板卡就重装环境。转换工具本身的封装形式可以不同但底层依赖始终是 rknn-toolkit2所以学会看它的版本号比记任何命令都重要。2.2 用 Python 虚拟环境安装跨平台转换工具依赖无论工具本身是命令行还是 GUI 封装底层都依赖 rknn-toolkit2。最小安装步骤可以归纳为四步。python3 -m venv rknn-env # 创建独立虚拟环境 source rknn-env/bin/activate # 激活环境 pip install --upgrade pip pip install rknn-toolkit2 # 也可以使用离线 whl 安装安装后先做一次导入验证确认依赖没有冲突。python -c from rknn.api import RKNN; rknn RKNN(); print(rknn-toolkit2 loaded)逻辑说明第一条命令创建独立环境避免 rknn-toolkit2 依赖的 numpy 版本和 ultralytics 冲突。第三条是常规升级但要注意 rknn-toolkit2 对 numpy 版本有明确约束升级过新反而装不上。离线安装时pip 会从 whl 文件读取依赖元数据自动拉取需要的轮子。参数说明虚拟环境目录名 rknn-env 可自定义如果主机同时跑 YOLOv11 训练环境建议把 ultralytics 也装进同一个环境这样导出 ONNX 和转换 RKNN 可以复用同一套 numpy 和 opencv 版本减少环境切换。不需要在主机上安装板端运行库那些库是部署阶段的事。2.3 校验安装结果与版本匹配度安装完成后不能只看到一个 loaded 就收工。还要确认工具链能否在模拟器上完成一次空转推理。rknn-toolkit2 自带 x86 模拟器可以在没有开发板的情况下跑通 rknn 计算图这对转换脚本的调试很有用。常见失败现象是ModuleNotFoundError: rknn原因通常是安装到了系统 Python 而不是 venv或者导入时 numpy 版本冲突报_ARRAY_API not found这种问题把 numpy 降到工具要求的版本即可。下表是环境检查时我看的对应关系。检查项转换主机板端部署环境工具库rknn-toolkit2rknn-toolkit-lite 或 librknnrtPython 环境3.8~3.10 较常见由板上系统决定驱动/固件不需要必须匹配芯片型号模拟器可用于验证计算图不参与板端运行提示验证部署端是否与转换端匹配用一条命令在板上查询 NPU 驱动版本例如cat /sys/kernel/debug/rknpu/version。主机转换端的工具链版本与这个输出保持一致才能避免部署阶段出现算子不兼容。3. 导出 YOLOv11 的 ONNX 并配置 RKNN 转换量化参数3.1 用 ultralytics 导出静态尺寸 ONNXYOLOv11 模型的来源通常是 ultralytics 训练产物导出命令比较固定。yolo export modelyolov11n.pt formatonnx imgsz640 opset12 simplifyTrue说明指定imgsz640是为了让导出的 ONNX 拥有固定输入尺寸RKNN 转换和板端推理都需要静态 shape。opset建议控制在 12 到 14 之间过高版本的部分算子会落在 RKNPU 的不支持列表里转换工具会报警告。simplifyTrue交给 onnxsim 剔除冗余节点可以减小后续映射的工作量。如果用 Python 代码导出可以用下面方式便于和转换脚本放在同一个流程里。from ultralytics import YOLO model YOLO(yolov11n.pt) model.export(formatonnx, imgsz640, opset12, simplifyTrue, dynamicFalse)导出后建议用 Netron 打开生成的 onnx 文件看输出节点名称和 shape。YOLOv11 常见输出是output0shape 是[1, 84, 8400]其中 8400 是 640 输入下三个尺度特征图的总 anchor 数84 对应 4 个边界框坐标加 80 类类别。转换工具在解析 ONNX 时通常只认输出节点名如果你的模型经过重新训练或改了分类数这个数字会变比如你自己训练的数据集类别数是 5那么 84 要换成 9。3.2 写一个可复用的 RKNN 转换脚本量化开关与目标平台参数这是整个转换工具的核心参数集中在config和build两个调用上。from rknn.api import RKNN rknn RKNN(verboseTrue) rknn.config( mean_values[[0, 0, 0]], # 与训练预处理保持一致 std_values[[255, 255, 255]], # 输入归一化的除数 target_platformrk3588, # 目标芯片型号 quantized_dtypew8a8, # 权重和激活均为 int8 ) rknn.load_onnx(modelyolov11.onnx) rknn.build( do_quantizationTrue, # 开启 int8 量化 datasetdataset.txt, # 校准集列表 ) rknn.export_rknn(yolov11.rknn)这段代码做完四件事加载 RKNN 句柄、配置预处理参数和平台、从 ONNX 构建计算图、导出 rknn 文件。mean_values和std_values必须和推理时输入图像的归一化方式一致。例如 YOLOv11 训练时经常只用 0-255 归一化不做减均值处理那就写 0 和 255。如果训练时用了 ImageNet 的 mean/std这里也要跟着改否则量化校准采集到的数据分布就不是模型见过的分布int8 精度会明显掉。do_quantization开关决定是否量化。量化只影响权重和激活的表示精度不影响输入图像的归一化方式。dataset.txt是校准集列表每行一张图片路径默认用 100 张左右即可。校准集不要用训练集也不要只放纯背景图要有物体多样性否则模型对目标类别的敏感度在量化后下降。target_platform填错型号时rknn-toolkit2 通常不会立刻报错而是在板端推理时报算子不支持所以这里不能随手填。3.3 量化选项的取舍int8 与 fp16 的选择参数表格式地过一遍常见选项方便直接抄参数。选项推荐值作用坑do_quantizationTrue开启 int8 量化关闭后体积大且板端速度差quantized_dtypew8a8 / fp16指定权重和激活量化位宽fp16 无精度收益但内存翻倍dataset100 张贴近场景的图片校准激活范围图片过少会数值偏置target_platformrk3588 等算子映射目标填错型号可能导致算子兼容问题optimization_level不参与精度调优控制编译耗时与速度调试精度时不要动它补充说明如果验证发现 int8 量化后检测框位置明显偏移优先检查的不是量化选项而是dataset.txt里图片是否包含和你实际场景接近的物体尺度和亮度分布。另一个常见问题是输出数值不动即量化后模型输出全为同一常数原因是校准集里图片全部为黑图或空白图激活范围统计不到有效信号。这类问题在工具封装里通常表现为转换成功但板上检测不到任何目标。注意rknn.config 和 rknn.build 里的量化参数在某些工具版本中命名有差异。封装成跨平台转换工具后通常会把上述参数透传成命令行选项例如--quantized_dtype w8a8。遇到版本差异时直接看help输出不要按旧博客的参数硬套。4. 在 Rockchip 板端部署 RKNN推理脚本编写与 YOLOv11 后处理对齐4.1 板端环境准备运行库与算子支持检查在板端部署时可以选择使用 rknn-toolkit-lite 的 Python API也可以使用 C API 集成到业务代码里。对于 YOLOv11 这类典型的检测模型Python 接口足够用于验证下面说明以 Python 为例。安装运行库后第一步不是跑推理而是用一个小模型验证 NPU 初始化。常见命令如下。pip install rknn-toolkit-lite # 在板端安装轻量推理库然后初始化一个 RKNNLite 实例并加载模型。注意板和主机上的 Python API 不能混用转换环境用rknn.api.RKNN板端推理用rknnlite.api.RKNNLite。两者都叫 RKNN但底层依赖不同。如果板端误装了 rknn-toolkit2 而不是 lite会报运行时库缺失。C API 集成时则需要链接 librknnrt.so并对照 rknn-toolkit2 的 C 头文件完成版本匹配这里的重点仍是芯片型号而不是示例代码本身。4.2 最小推理代码输入预处理与输出重排import cv2 import numpy as np from rknnlite.api import RKNNLite rknn RKNNLite() rknn.load_rknn(yolov11.rknn) rknn.init_runtime(core_maskRKNNLite.NPU_CORE_0_1_2) # 使用全部 NPU 核心 img cv2.imread(test.jpg) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img_640 cv2.resize(img, (640, 640)) img_input np.expand_dims(img_640.astype(np.float32) / 255.0, axis0) outputs rknn.inference(inputs[img_input]) print(outputs[0].shape) # 打印输出维度确认是 [1,84,8400] 或 [1,8400,84]这段代码里RKNNLite.NPU_CORE_0_1_2表示让 NPU 的三个核心都参与推理如果板卡资源紧张也可以改成只用一个核。输入必须保持NCHW还是NHWC取决于转换时config里如何设置。这里示范的是NHWC的常见写法但 rknn-toolkit2 在转换时会按照模型的输入定义处理所以最稳妥的判断方式是打印outputs[0].shape后对照导出 ONNX 时的输出 shape。inference返回的是列表每个元素对应一个输出张量。YOLOv11 输出 shape 如果是[1, 84, 8400]那它是通道在前做后处理前要转成[1, 8400, 84]。很多板端程序掉进这个坑检测框全部画错不是模型没转换好而是 dim 没有重排。后处理时还要注意把输出值经过 sigmoid 后再做阈值过滤这一点和 PyTorch 端原模型的后处理需要保持一致。4.3 输出数值异常时的定位框架板端推理出现问题时先做三个判断。python -c from rknnlite.api import RKNNLite; print(RKNNLite ok)如果打印正常说明运行库安装没问题。接着看init_runtime是否报错报错多半是板端驱动与模型转换时的 target_platform 不匹配。最后用固定输入对比 ONNX 输出把同一张图分别喂给 onnxruntime 和 rknn 推理比较二者输出均值差异。若差异在 0.01 量级量化精度正常若输出为全零或常量则检查预处理和校准集。现象可能原因处理顺序推理崩溃板端驱动版本不兼容更新固件到对应版本输出数值为 NaN输入包含非法像素值检查 float16 溢出输出数值不动校准集无效或预处理偏移重新生成 dataset.txt检测框偏移输出 dim 未转置对照 onnx 输出做逐值对比这一章的量化精度排查思路对后续任意模型的部署都适用。注意每轮只改一个变量不要同时调整量化开关和预处理否则定位不到原因。比如先固定输入 float32再打开 int8先固定 CPU 后处理再上 NPU 推理这样对比出来的差异才可解释。5. 进阶用附带测.zip 组织量化校准与部署验收5.1 把测.zip 里的样本整理成量化数据集与验收集拿到测.zip 后不要一次性全部塞进 dataset.txt。我一般会把它拆成两部分一部分作为量化校准集另一部分作为验收集。校准集要挑选亮度、目标尺度、类别分布都有代表性的图片数量控制在 100 到 200 张。验收集则要模拟真实运行环境包含模糊、遮挡、低照度的样本用来观察转换工具在量化后是否仍然保持可用精度。unzip test.zip -d ./rknn_assets mkdir -p ./rknn_assets/calib ./rknn_assets/eval # 手工把代表性图片放到 calib把真实场景放到 eval find ./rknn_assets/calib -name *.jpg dataset.txt这里的 dataset.txt 直接喂给 build 阶段的dataset参数。放图片时注意不要包含中文路径rknn-toolkit2 在读取路径上对非 ASCII 支持并不好转换脚本容易出现文件找不到但路径明明存在的错。路径用相对路径写入 dataset.txt 时需要保证转换脚本的工作目录和列表里的前缀一致。5.2 用 ONNX 推理做量化回退对比验收时最有价值的操作不是直接看检测框而是先比较 ONNX 和 RKNN 的输出差异。建议用 onnxruntime 做一次基准推理。import onnxruntime as ort sess ort.InferenceSession(yolov11.onnx, providers[CPUExecutionProvider]) y_onnx sess.run(None, {sess.get_inputs()[0].name: img_input})[0]然后把 RKNN 输出与y_onnx对齐计算余弦相似度或者逐通道的最大绝对误差。这个步骤能区分出量化误差和业务逻辑错误如果相似度在 0.98 以上检测框画错是后处理问题如果相似度掉到 0.8 以下就要回头动量化参数。对比时注意 RKNN 输出的 shape 可能和 ONNX 不一致先把两个张量都 reshape 成同一维度再计算。5.3 量化精度回退的三个具体调参技巧第一个技巧先在build中关闭量化跑一遍 fp16确认计算图本身正确第二个技巧开启逐通道量化让每个输出通道的缩放因子独立对 YOLOv11 尾巴上的小目标恢复更明显第三个技巧把校准集里增加 3%~5% 的困难样本尤其是目标在角落里或重叠度高的图。三个技巧里成本最低的是第三个改 dataset.txt 即可。如果做完这些int8 精度仍然不能接受最后再退回混合量化关键层保持 fp16其余层用 int8。这种方法对推理速度影响大约在 5% 以内但能明显改善检测小目标时的漏检。把测.zip 当作验收素材而不是直接测通过的凭据才能把量化选项优化到接近 ONNX 精度的水平。本文还有配套的精品资源点击获取