多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

YOLOv11 部署到 Rockchip NPU 完整指南:ONNX 转换与 RKNN 量化实战

YOLOv11 部署到 Rockchip NPU 完整指南:ONNX 转换与 RKNN 量化实战 简介面向边缘智能设备部署需求这款工具包围绕YOLOv11目标检测模型打通了从模型导出到芯片端运行的完整链路。重点解决在瑞芯微平台上将开放神经网络交换格式模型转换为瑞芯微神经网络工具包模型的问题内容覆盖环境配置指南、量化选项与推理加速建议适合嵌入式视觉开发者及算法工程落地人员。压缩包共十五个文件包括转换程序脚本、模型文件、测试图片、结果对比图、说明文档与使用手册模型与文档分类清晰整体体积约十四点二一兆字节。目前已有六十九人学习下载。资料非常注重实战从环境准备、依赖安装到调用转换工具每一步都配有界面截图和文字说明能够显著降低入门门槛。量化部分给出了多种选项对比帮助在精度与速度间取舍附带的测试结果图片可以直观检验转换效果。对于需要在瑞芯微芯片上完成目标检测项目开发的工程师这份资料提供了可复用的操作范式和排错思路。1. 把 YOLOv11 塞进 Rockchip NPU这条路到底卡在哪我去年手头有个边缘巡检项目模型用 YOLOv11 训练完在服务器上 mAP 看着挺漂亮一搬到 RK3588 上跑纯 CPU 推理单帧 700 多毫秒直接把客户劝退。后来把模型导出成 ONNX再走 rknn-toolkit2 转成 RKNN 格式配合 NPU 和 int8 量化单帧掉到 30 毫秒以内——这个量级才是 Rockchip 部署该有的样子。这个标题给的工具实际上就是把 YOLOv11 从 PyTorch 训练环境一路搬到 Rockchip 板子上的完整链路训练好的权重导出 ONNXONNX 转 RKNN期间还要解决环境配置、量化选项、精度损失和各种奇怪的算子报错。它不是那种点一下生成的黑匣子而是需要你理解每一步在干什么、每个参数改了什么。适合谁看准备把检测模型部署到 RK3588、RK3566 这类板子的嵌入式工程师或者被模型能跑但跑不动折磨过的算法工程师。这套流程踩坑不少但走通之后后面换模型换板子都是顺水推舟的事。2. 从 YOLOv11 导出 ONNX转换链路的地基导出格式决定后面顺不顺2.1 为什么不能直接拿 PyTorch 权重转 RKNN非要中间过一道 ONNX很多第一次接触 Rockchip 部署的人第一反应是rknn-toolkit2 能不能直接吃 .pt 文件。官方工具链里确实有 load_pytorch 这类入口但实际用下来我强烈建议你老老实实走 ONNX 中转。原因不复杂rknn-toolkit2 对 ONNX 的算子覆盖最全对 PyTorch 前向图的解析能力弱不少尤其是 YOLOv11 里那些自定义模块、动态 shape、以及训练时带进来的无关节点直接 load 容易在某个不起眼的算子上翻车报错信息还看不懂。ONNX 相当于是把 PyTorch 动态图固化成了静态计算图所有张量的 shape 和算子类型都明确RKNN 解析起来省事出问题也好定位——它报哪个算子不支持你至少能在 Netron 里打开 ONNX 看到那个节点长什么样。另外ONNX 是一个跨平台载体今天你转 RKNN明天想试试 NCNN、OpenVINO 或者 TensorRT同一份 ONNX 都能复用。我自己习惯的做法是PyTorch 权重只作为母版任何部署格式都从 ONNX 派生的那份出发这样模型在哪个平台上的行为差异就能定位到转换工具本身而不是源头就错了。2.2 最小导出命令用 YOLOv11 官方权重导出 ONNX 的三个关键开关常见的做法是直接用 ultralytics 库的 export 接口导出不建议自己手写 torch.onnx.export因为 YOLOv11 的检测头里有不少细节比如多尺度输出、anchor-free 解码逻辑手写容易漏。最小可用的导出脚本如下from ultralytics import YOLO # 加载训练好的权重注意用训练完的 best.pt而不是 last.pt model YOLO(runs/detect/train/weights/best.pt) # 导出 ONNX model.export( formatonnx, # 导出格式 imgsz640, # 输入尺寸必须与训练时一致 opset12, # ONNX opset 版本RKNN 对 12 支持最稳 simplifyTrue, # 用 onnxsim 简化计算图 dynamicFalse, # 固定静态 shapeRKNN 对动态 shape 支持有限 halfFalse, # 导出 FP32量化放到 RKNN 阶段做 )这段代码里我标了几个关键参数逐个说明。imgsz 必须和训练时保持一致如果训练用了 640导出也必须是 640后面转 RKNN 时还要再填一次三处不一致就会出幺蛾子。opset 我固定给 12别看 ultralytics 支持更新版本rknn-toolkit2 对 opset 13 以上的某些算子解析有历史遗留问题opset 12 是保守但稳的选择。simplify 建议打开它会把计算图中的冗余节点折叠掉比如同一算子重复出现、shape 操作链过长这些在 RKNN 转换时都可能变成不支持的报错来源。dynamic 必须设成 FalseRockchip NPU 的输入是固定形状的转出来就是死 shape动态 shape 就算转成功板子上也没法高效跑。half 这里先不开int8 量化的活儿统一放到 RKNN 转换阶段导出时保持 FP32 精度最保险。2.3 导出后必须做的一次体检用 onnxruntime 验证 ONNX 输出和 PyTorch 输出一致导出成功不等于导出正确。我在 RKNN 转换上栽过最大的跟头就是 ONNX 本身就导错了结果后面所有排查都走偏。所以导出 ONNX 之后我习惯先用 onnxruntime 跑一遍推理拿同一张测试图跟 PyTorch 模型的输出对比确认差异在可接受范围内再继续。import onnxruntime as ort import numpy as np import cv2 from ultralytics import YOLO # 用 PyTorch 模型跑一次 pt_model YOLO(runs/detect/train/weights/best.pt) img cv2.imread(test.jpg) img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) results_pt pt_model(img_rgb, imgsz640, verboseFalse) # 用 ONNX 模型跑一次 sess ort.InferenceSession(best.onnx, providers[CPUExecutionProvider]) input_name sess.get_inputs()[0].name input_shape sess.get_inputs()[0].shape # 预处理与 ultralytics 保持一致letterbox 归一化 from ultralytics.data.augment import LetterBox lb LetterBox((640, 640), autoTrue, stride32) img_letterbox lb(imageimg_rgb) img_norm img_letterbox.astype(np.float32) / 255.0 img_tensor np.transpose(img_norm, (2, 0, 1))[None, ...] outputs_onnx sess.run(None, {input_name: img_tensor}) # 对比主要输出 shape 和数值范围 print(PyTorch 输出形状:, len(results_pt[0].boxes)) print(ONNX 输出形状:, [o.shape for o in outputs_onnx])这段脚本的核心逻辑是同一张图分别喂给 PyTorch 模型和 ONNX 模型对比检测结果的数量和整体置信度分布。注意 ultralytics 内部的预处理是 letterbox 归一化到 0~1你手动用 onnxruntime 跑的时候必须复现这套预处理否则数值对不上不是模型转换的问题是你输入的问题。我一般只看两个指标检测框数量是否一致以及最高置信度是否在同一个量级。对比理想情况是检测框数量完全相同置信度差异在 1e-3 量级以内。如果框数量都对不上那不用往下走了回头检查导出参数多半是 imgsz 或 opset 出了问题。3. rknn-toolkit2 环境配置Python 版本、依赖冲突和校准集一个都不能少3.1 版本矩阵先行Python 版本和 rknn-toolkit2 版本怎么对齐rknn-toolkit2 这工具说好听点叫对版本敏感说难听点就是版本强迫症。我见过太多人在环境配置这一步就放弃了报错信息五花八门但根因往往就一个Python 版本不兼容。当前 Rockchip 官方推荐的 rknn-toolkit2 是 1.x 系列它要求 Python 版本通常落在 3.8 到 3.10 之间3.11 以上大概率装不上或者运行时报错。另外它依赖的 onnx、numpy 版本也有讲究onnx 不能装太新1.13 到 1.15 之间比较稳numpy 不要超过 1.24否则会有编译兼容问题。我一般用 conda 单独建一个环境跟项目开发环境隔离避免 rknn-toolkit2 的依赖把训练环境的包搞乱了。建环境的完整流程如下# 创建 Python 3.8 环境rknn-toolkit2 目前最稳的版本 conda create -n rknn_env python3.8 conda activate rknn_env # 安装 rknn-toolkit2 核心包注意指定版本号 pip install rknn-toolkit21.5.2 -i https://pypi.org/simple # 锁定关键依赖版本防止 pip 自动升级 pip install onnx1.14.1 pip install numpy1.24.3 pip install onnxruntime1.15.1 pip install opencv-python4.8.1.78 # 验证安装 python -c from rknn.api import RKNN; print(rknn-toolkit2 OK)版本问题比很多新手想得更致命。rknn-toolkit2 1.5.2 和 1.6.0 的 API 行为就可能有差异比如某些版本的 build 接口多了参数某些版本的 load_onnx 对输入 shape 的处理方式不同。我自己的原则是选定一个版本组合之后用 conda env export 把环境导出一份 yaml 存档下次换机器直接 conda env create -f不要每次都裸 pip install。另外强调一下rknn-toolkit2 本身只负责在 PC 上完成模型转换和模拟推理它不部署到板子上板子上真正跑的是 RKNN Runtime 的 C 库。所以你 PC 上装的 rknn-toolkit2 只要能用就行和板子上的版本不必完全一致但建议尽量对齐后面 5.4 我会专门讲版本不匹配的坑。3.2 校准集准备int8 量化的弹药库不是随便找几张图就完事RKNN 的 int8 量化简单说就是根据一个输入样本集统计每一层激活值的数值分布然后把 FP32 的浮点权重映射到 int8 的 256 个整数值。这个样本集也就是校准集的质量直接决定量化后模型的精度保留程度。这个环节没有硬性保证校准集不够代表真实部署场景模型 quantize 完看起来跑得欢一上真实场景检测框就开始乱飘。准备校准集我有几个硬性要求。第一数量在 50 到 200 张之间太少统计出来的分布不稳定太多转换时间成倍增加收益不显著。第二必须覆盖所有典型场景比如户外巡检模型白天、逆光、黄昏、雨雾各占一部分不要全是同一时段拍的。第三尽量避免用训练集的原图做校准集——模型在训练集上过拟合了激活值分布会偏低偏差不代表真实推理时的分布。我的习惯是从验证集里随机抽一部分再混入少量没见过的实拍图。第四图片尺寸统一缩放到模型的输入尺寸 640x640不需要做精细的预处理rknn-toolkit2 会在 build 时根据你配置的 mean/std 做归一化。还有一个容易被忽略的点校准集不要用压缩率过高的 JPEG。压缩伪影会改变高频区域的像素分布进而影响激活值的统计虽然影响幅度不大但量化本身就在刀尖上跳舞能少一个误差源就少一个。3.3 在 PC 上模拟推理先把模型跑通了再上板省一半调试时间rknn-toolkit2 提供了一套 PC 端模拟推理能力不需要板子也能看到 RKNN 模型对一张输入图给出的推理结果。这个能力在开发阶段极其好用因为板子调试要搭交叉编译环境、传文件、看日志一轮循环十几分钟而在 PC 上模拟只需要几秒钟。我最常干的事情是先转换 RKNN然后立刻在 PC 上做模拟推理把检测框画出来看一眼如果这一步就错了那都不用上板。import numpy as np import cv2 from rknn.api import RKNN rknn RKNN() # 加载 RKNN 模型 rknn.load_rknn(yolov11.rknn) # 初始化运行环境target 为 None 表示 PC 模拟推理 ret rknn.init_runtime(targetNone) assert ret 0, finit_runtime failed: {ret} # 读取并预处理图片 img cv2.imread(test.jpg) img cv2.resize(img, (640, 640)) # 模拟推理 outputs rknn.inference(inputs[img]) print(fInference done, output tensors: {len(outputs)}) for i, out in enumerate(outputs): print(fOutput {i}: shape{out.shape}, dtype{out.dtype}, range[{out.min():.4f}, {out.max():.4f}]) # 记得释放资源 rknn.release()模拟推理这一步能确认两件事一是 RKNN 模型本身没转坏输出数值的范围、形状和 ONNX 输出对得上二是推理速度可以大致评估虽然 PC 模拟跑的是 x86 的 NPU 模拟器和板子真实 AI 性能有关系但不完全等价但数量级上的问题能提前暴露比如模型某些算子导致推理极慢的情况PC 上也会有体现。我用这个流程排过很多问题强烈建议养成转换完先模拟推理再上板的习惯血泪经验告诉我跳过这个阶段直接上板的项目往往会在板子上多花几倍时间。4. ONNX 转 RKNN 核心流程量化选项、目标平台和导出形态一次说透4.1 完整转换脚本从 load_onnx 到 export_rknn 的每一步在干什么环境搭好、ONNX 验证通过、校准集备好之后就可以正式执行转换。下面是一份我用来最顺手的转换脚本骨架注释里写清楚了每个参数的含义import numpy as np from rknn.api import RKNN # 1. 创建 RKNN 对象 rknn RKNN() # 2. 配置模型输入和量化参数 ret rknn.config( mean_values[[0, 0, 0]], # 均值YOLOv11 官方训练时用的是 0~1 归一化所以均值填 0 std_values[[255, 255, 255]], # 标准差除以 255 是归一化关键 target_platformrk3588, # 目标平台后续板子的 NPU 架构 quantized_dtypew8a8, # int8 量化权重和激活都量化为 8bit quantized_algorithmnormal, # 量化算法normal 是融合量化min/max 是逐层量化 quantized_methodlayer, # 量化粒度可选 layer 或 channel推荐 channel ) assert ret 0, fconfig failed: {ret} # 3. 加载 ONNX 模型 ret rknn.load_onnx( modelyolov11.onnx, input_size_list[[1, 3, 640, 640]], # NCHW 格式必须与导出时一致 ) assert ret 0, fload_onnx failed: {ret} # 4. 构建 RKNN 模型这一步会执行量化 ret rknn.build( do_quantizationTrue, # 打开量化开关 dataset./calib_dataset.txt, # 校准集文件列表 pre_compileFalse, # 预编译False 表示生成通用 RKNN跨板型兼容 ) assert ret 0, fbuild failed: {ret} # 5. 导出 RKNN 模型文件 ret rknn.export_rknn(yolov11.rknn) assert ret 0, fexport_rknn failed: {ret} # 6. 释放资源 rknn.release()整个脚本分六步每一步都有明确职责。config 阶段是给 RKNN 编译器交代背景输入图片的像素范围是多少、目标是哪颗芯片、量化到什么精度。这里最容易出错的是 mean_values 和 std_values很多人直接把训练时的归一化参数抄过来但 YOLOv11 官方训练用的归一化就是除以 255并不需要额外减均值所以 mean 填 0、std 填 255 才是对的。如果训练时用了自定义的归一化比如均值 [0.485, 0.456, 0.406]那么在这里也要对应填推理时 RKNN 会自动执行预处理不需要自己在板上再写一次。load_onnx 阶段最关键的是 input_size_list虽然 ONNX 图里本身有 shape 信息但 rknn-toolkit2 仍然要求显式声明。这个列表的形式是 NCHWN 固定为 1C 是 3H 和 W 与 imgsz 一致。如果导出 ONNX 时已经用动态 shape这里填的 shape 就是后续模型运行时的固定输入尺寸后面想改只能重新转换没有后悔药。4.2 量化选项对照什么时候选 normal、什么时候选 min/max什么时候干脆不量化量化是 RKNN 转换里影响最大也最需要理解的一个环节。rknn-toolkit2 提供了 quantized_algorithmnormal 和 min/max 两种量化算法它们的差异在于如何确定每层激活值和权重的数值范围。normal 算法会综合多张校准图的统计信息做一个全局优化对精度保留更友好min/max 则是对每个张量单独取最小值和最大值计算量大一些但对分布不均匀的层更精确。用表格总结一下不同场景的推荐选择量化选项精度表现推理速度推荐场景不量化FP16最接近原模型较 int8 慢 20%-30%精度敏感、模型本身很小normal layer 粒度中等快大多数检测模型首选项normal channel 粒度较好略慢分布差异大的深度模型min/max channel最好最慢小模型、对精度损失零容忍我自己的经验是对 YOLOv11 这类检测模型先试 normal layer这是转换速度最快也最不容易出岔子组合跑完用验证集测 mAP。如果 mAP 掉点超过 2%换成 normal channel 威力加强还是掉再换 min/max channel。一般 YOLOv11 在 int8 量化下 mAP 掉点在 0.5% 到 2% 之间属于正常范围超过这个范围就要检查校准集或模型本身了。另外有两种情况我会选择不量化一是模型在板子上推理时间已经满足需求不需要压榨极致性能二是模型的输出层数值范围异常宽量化后置信度会明显偏低。在这种情况下用 FP16 导出反而是更省事的选择反正 Rockchip NPU 也支持 FP16 推理。4.3 预编译开关 pre_compile 的取舍跨板型兼容性和极致性能怎么平衡build 阶段的 pre_compile 参数最容易被忽略但它的影响很隐蔽。简单说pre_compileFalse 生成的是中间表示板子上的 RKNN Runtime 在加载模型时再针对具体芯片做编译优化pre_compileTrue 则是在 PC 转换阶段就把针对 target_platform 的底层优化做完板子上加载速度更快推理性能也略好代价是生成的 .rknn 文件绑定了特定芯片平台不能跨板型使用。标题里提到适用于 Rockchip 芯片部署所以大部分人会在 rk3568 和 rk3588 之间纠结。我个人的习惯是如果项目用到的板型固定比如已经确定量产用 RK3588那 pre_compile 直接开 True能榨出一点性能是一点如果还在评估阶段手头有 RK3588 实验板、RK3576 评估板那就先 False让同一份 .rknn 在两种板子上都能跑等确定了最终硬件再重新转一份开预编译的版本。4.4 转换后的产物确认rknn 文件、权重文件和推理日志分别代表什么转换完成后你会看到一系列产物除了主产物 .rknn 文件之外build 过程还会生成一些中间文件。常见文件包括文件作用后续是否需要yolov11.rknn最终交付的部署模型是拷贝到板子.weight 文件量化后的权重单独存储仅当 export 时选了分离权重模式log/ 目录转换日志和算子映射报告排错时参考中间失败快照构建失败时的图信息仅排错时使用这里需要特意说明一个常见翻车点rknn.build 的 log 里会显示每个算子的映射情况如果某个算子被标记为 NOT SUPPORT 或者 FALLBACK说明该算子没有跑到 NPU 上而是回退到了 CPU。这种情况模型能转成功、能推理但性能会大打折扣YOLOv11 里如果 head 部分有自定义算子未被 NPU 支持整体推理时间可能翻 3 到 5 倍。所以转换完我必做的一件事是打开 log 目录下的 performance 相关日志用 grep 搜一下 NOT SUPPORT 和 CPU 字样确认所有算子都映射到了 NPU。这一步能省掉后面在板子上抓性能瓶颈的大量时间。5. ONNX 转 RKNN 的 5 个高频翻车点现象、根因和解决路径5.1 转换时报 Unknown layer / Unsupported operatorYOLOv11 里的算子 RKNN 不认现象rknn.build 执行到一半直接抛出一串类似 Unknown layer xxx 或 Not supported operator: xxx 的错误常见出场角色是 HardSigmoid、GridSample、自定义 C2f 模块里的某些操作。根因YOLOv11 的网络结构比老版本复杂引入了新的模块设计而 rknn-toolkit2 对 ONNX 算子的支持列表是有限的某些算子只出现在训练图里对推理没有实际作用但也有个别算子确实承担了核心计算。解决路径第一步先用 onnxsim 已经简化过模型排掉冗余算子。第二步用 Netron 打开 ONNX 图定位报错算子的位置看它在哪个模块里。绝大多数情况下报错发生在模型输出端的后处理部分比如 DFL 解码或 NMS 相关结构这些算子在 RKNN 侧都有等价实现可以直接修改 ONNX 图把不被支持的节点替换成 RKNN 支持的算子组合比如把循环展开成矩阵运算。第三步如果替换不了只能调整导出方式比如把 YOLOv11 的 detect head 拆开只保留 backbone 和 neck 的导出后处理放到板子的 C 代码里写。这一步操作量不小但比陷入算子不支持的死胡同要有效得多。5.2 int8 量化后模型精度崩了检测框全在乱飘现象量化之前 mAP 有 0.85量化之后掉到 0.6 甚至更低检测框位置偏移明显置信度普遍低于正常水平。根因优先级最高的是校准集与真实场景分布不一致。比如巡检项目校准集全是顺光环境部署时碰到逆光场景就开始乱飘其次是校准集数量太少统计出来的激活值范围不具代表性最后是某些层对量化极其敏感比如检测 head 里的最后一层卷积权重分布范围本来就窄量化后信息丢失得最狠。解决路径先把校准集扩充到 100 张以上确保覆盖所有典型场景再用 4.2 的选项对比表换成 channel 粒度量化如果还不行做混合量化——用 rknn.config 里的 custom_quantize_layers 参数指定某些层跳过量化、保持 FP16通常优先保护 head 的最后一两层卷积。这个方法能让精度恢复大半代价是这些层推理稍慢。5.3 模拟推理结果全是零或 NaN模型加载成功但输出不可用现象rknn.inference 正常返回但 outputs 数组里面要么全是 0要么是 nan检测框一支都画不出来。根因常见原因有两个。第一个config 阶段的 mean_values 和 std_values 写反了输入图片进模型前被处理成了错误数值激活值全部饱和或者归零。第二个图片预处理尺寸和 input_size_list 不一致比如脚本里 resize 成了 480x480而 build 时声明的是 640x640导致张量对齐错乱算出来的结果就是垃圾。解决路径先用一张全黑图和一张全白图跑推理观察输出数值范围这能判断输入预处理是否正确再打印一下送入 RKNN 的图片数组的 shape 和 dtype确认是 uint8 还是 float32。排查顺序是预处理 - config - build不要一上来就怀疑模型转换坏了。这是最容易自查的问题但也很容易在忙乱中被忽略建议每一步都打印关键张量的 shape。5.4 板子上加载模型报版本错误换个设备就起不来现象在 PC 上模拟推理一切正常把 .rknn 文件拷到板子上rknn_init 直接返回错误码板子端 log 提示版本不匹配。根因rknn-toolkit2 转换出的模型内部带有版本信息板子上运行的 librknnrt.soRKNN Runtime 库也有自己的版本号两者不兼容时加载就失败。常见场景包括PC 上装了新版 rknn-toolkit2 1.6.0板子系统里的 RKNN Runtime 还是 1.4.0 时代的旧库。解决路径板子上先执行 rknn_server 或查询 librknnrt.so 的版本号确定板端 runtime 版本然后 PC 端安装对应版本的 rknn-toolkit2重新转换一份模型。这条规则我把它当铁律换板子前先查两端版本PC 端 rknn-toolkit2 版本 板端 RKNN Runtime 版本但不要跨大版本。项目文档里固定记录两个环境的版本号能省掉很多玄学排查时间。5.5 模型转换成功、推理正常但比预期慢 3 倍以上现象板端推理时间明显不达标比如 RK3588 上 YOLOv11 预期 20 毫秒实际跑了 60 毫秒甚至更多。根因最常见的是算子回退到 CPU 执行。前面 4.4 提过log 里会标记哪些算子没有映射到 NPU如果你没看 log 就直接部署性能问题早埋下了。第二个常见原因是模型输入尺寸不是 NPU 友好尺寸比如用了 640x672 这种不能被 16 整除的尺寸NPU 做 padding 补齐时产生额外开销。解决路径打开转换时的 log 目录搜索 NOT SUPPORT 或 CPU Partition 关键字逐条解决回退的算子同时检查输入尺寸是否能被 16 整除YOLOv11 输入尺寸通常选 640 或 320都能被 32 整除问题不大但只要改过就确认一下。第三个容易忽略的点是批量大小板端推理时 rknn_inputs 的 batch 设置成 1 不会错但如果模型本身支持 batch 1用 2 或 4 的 batch 往往能提升 NPU 吞吐代价是增加延迟需要权衡。通常我会把性能日志里耗时排名前 10 的层拉出来看一遍心里就对瓶颈有数了。6. 上板前的最后一道工序推理速度验证、批处理调优和端到端自检清单模型转好、量化调完、避坑踩完最后这道工序是上板前的验证闭环。我每次上板前都做三件事第一步写一个最小推理脚本在板子上连续跑 100 帧统计平均耗时特别注意跳过前 5 帧的预热时间——NPU 首次推理会加载模型到内存这个时间和正常推理差一个量级统计进去会显得板子性能很差但实际是自欺欺人。第二步用不同的 batch 做一轮吞吐测试看 batch 从 1 调到 2 甚至 4 时总耗时变化多少、平均每帧耗时是否下降。Rockchip NPU 对批处理的支持是实打实的batch1 时固定开销占比高batch4 时某些层可以并行计算每帧平均耗时常常能再降 20% 左右但这跟具体模型结构有关所以必须实测。第三步把检测输出跟 ONNX 推理的结果叠在一起画图——回传的检测框画出来的覆盖情况直接告诉你量化后模型在真实场景下的行为漂移有多大。我在 RKNN 转换上还有一个习惯性的检查每次转换完都留一份转换时的 config 参数和校准集清单附在项目文档里。这样做最大的好处是三个月后模型要迭代一版重新转 RKNN 时能精确复现上一次的环境、参数和校准集对比新旧模型的精度差异才横得起来。工具链版本变了、校准集换了、量化算法动了任何一个变量都可能影响最终模型没有记录就只能靠回忆排错那是很折磨人的。希望这个从导出到部署的完整链路能帮你在 Rockchip 平台少走几趟弯路把精力留在真正影响业务的调优上。本文还有配套的精品资源点击获取
返回列表