ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RK3568边缘AI部署实战:PC端模型转换工具与三层分工详解

RK3568边缘AI部署实战:PC端模型转换工具与三层分工详解 RK3568 边缘 AI 从零上手(三):PC 端装转换工具,搞懂“三层分工”与 15 条命令RK3568 的 AI 部署链路光靠一块开发板是跑不完整的。模型训练、模型转换、目标板推理这三个环节各干各的活很多人一上来就急着在板子上敲命令结果卡在模型格式不对、量化报错、推理结果全是乱码。这一篇我专门讲 PC 端该装什么、三端之间怎么分工以及我日常用得最顺手的 15 条命令。先说清楚这篇文章适合谁。如果你已经能点亮 RK3568 开发板、能跑通 Linux 系统但还没碰过 RKNN-Toolkit2不知道 modelzoo 里的模型怎么变成 .rknn 文件也不知道 PC 端和开发板各自该装哪些东西那这篇就是给你准备的。我会尽量把每一层职责讲透命令也给全你照着敲就能把环境跑起来。1. 内容整体设计与思路拆解1.1 “三层分工”到底分的是哪三层RK3568 的边缘 AI 部署我习惯把它拆成三个逻辑层理解这三层比记住任何一条命令都重要。第一层是训练端。这一层跑的是 TensorFlow、PyTorch、ONNX 这类框架负责训练出模型权重。训练端一般不需要跟 RK3568 有任何直接关系甚至可以在没有 RK3568 的纯 x86 服务器上完成。你只需要保证训练出来的模型能导出成 ONNX 格式这是后续转换的前提。第二层是转换端。这是 RK3568 AI 部署里最容易被忽略、也最容易出问题的一环。它运行在 PC 上负责把训练端导出的 ONNX、TensorFlow 等模型通过瑞芯微官方的 RKNN-Toolkit2 工具链转换成 RK3568 NPU 能识别的 RKNN 格式同时还能做量化、剪枝、精度分析。转换结束后会生成一个 .rknn 文件这个文件才是最终要丢到开发板上跑的模型。第三层是推理端。这一层就是 RK3568 开发板本身。板子上跑着 Linux 系统通过 RKNPU2 的运行时库librknnmrt.so来加载并执行 .rknn 模型。推理端不需要安装完整的 RKNN-Toolkit2只需要装 runtime 库和对应的 Python API 即可。这三层的关系可以理解为训练端生产原料转换端加工成半成品推理端负责使用。很多人把转换工具直接装在开发板上这是不推荐的因为 RKNN-Toolkit2 对 x86 平台支持最完善而且模型转换和量化非常吃 CPU 和内存在 RK3568 上跑转换既慢又容易 OOM。1.2 为什么转换工具要装在 PC 端而不是开发板这是新手最容易犯的迷糊。RK3568 自己就是一个带 NPU 的 SoC为什么不能在板子上直接把 ONNX 转成 RKNN技术上并不是完全不行但实际工程里没人这么干。原因有三个。第一RKNN-Toolkit2 最稳定的运行环境是 x86_64 的 Ubuntu。官方提供了完整的 pip 包、conda 环境配置和 Docker 镜像而在 RK3568 的 arm64 环境下虽然也有对应版本但依赖项处理麻烦性能也差很多。模型转换过程涉及大量的数值计算、量化校准、图优化这些在 x86 上几秒钟能完成的事在板子上可能要几分钟。第二量化校准需要跑数据集。RKNN-Toolkit2 在做 INT8 量化时需要输入一批校准图片通常是几百张让工具去统计每一层的激活值分布。这个过程的计算量不小放在 PC 上做会舒服得多也方便把校准数据准备好再一次性喂进去。第三开发和调试的便利性。你在 PC 上可以随时修改脚本、换模型、对比不同量化策略的效果甚至可以把 RKNN 模型放到 PC 上的模拟器里先跑一遍确认精度没问题再部署到开发板。如果在板子上做转换调试起来非常痛苦改一个参数就要重新上传、重新执行整个迭代周期被拉长好几倍。所以实践上PC 端x86 Ubuntu是转换的主战场开发板只负责最终推理。1.3 整体部署方案选型与预期效果我的推荐方案是这样的PC 端装 Ubuntu 20.04 或 22.04用 conda 管理 Python 环境安装 RKNN-Toolkit2 的 x86 版本开发板保持官方系统镜像不动只需要 push 一个 rknn-toolkit2 runtime 的 arm64 版本进去。模型训练端用什么框架无所谓只要最终导出成 ONNX 就行。这套方案跑起来之后整个部署流程是线性的训练/导出 ONNX → PC 端 RKNN-Toolkit2 转换并量化 → 生成 .rknn → 拷贝到开发板 → 用 RKNN Python API 加载推理。每一层都可以独立验证出了问题也知道该查哪一段。2. 核心细节解析与实操要点2.1 认识 RKNN-Toolkit2 的整体组件RKNN-Toolkit2 并不是一个单一的工具它是一整套工具链的集合各自分工明确。我列几个最核心的组件你会经常跟它们打交道。rknn-toolkit2这是主工具包提供 Python API用来加载原始模型、量化、转换、导出 .rknn 文件还包含模拟器功能可以在 PC 上先验证转换结果。rknn-toolkit-lite2这是轻量版 Python API运行在开发板上用于加载 .rknn 模型并执行推理。它依赖 librknnmrt.so 运行时库。librknnmrt.soNPU 的运行时库是连接应用层与 NPU 驱动之间的桥梁。你写的 Python 或 C 程序最终都是通过它来调用 NPU 的。rknn_model_zoo瑞芯微官方的模型仓库里面有大量现成模型的定义、转换脚本和部署示例是最重要的参考和学习资料。这里有个需要特别强调的小点rknn-toolkit2 和 rknn-toolkit-lite2 的 API 几乎相同但底层定位完全不同。前者跑在 x86 上做转换和模拟后者跑在板子上做真实推理。你如果在 PC 上装的是完整版不能直接拿它去板子上用模型格式虽然都是 .rknn但运行环境是两套东西。2.2 RKNN 模型格式与跨平台特性RKNN 是瑞芯微自定义的模型格式经过加密和优化专门针对自家 NPU 的指令集设计。它不像 ONNX 那样是个通用格式而是和芯片绑定的——同一个 .rknn 文件不能拿去跑 RK3588 或者 RV1126必须针对具体芯片平台单独转换。这一点新手经常踩坑。你如果用 RK3588 的 rknn-toolkit2 转换出来的模型放到 RK3568 上跑会直接报错说模型平台不匹配。所以在转换时target_platform 参数一定要明确指定为 rk3568。另一个特性是 RKNN 模型会把量化参数、权重、图结构全部打包在一起部署时只需要一个文件就行不需要把原始权重和结构分开管理。这在工程上非常友好拷贝、升级、回滚都方便。2.3 转换前的模型准备与格式要求RKNN-Toolkit2 支持的输入格式包括 PyTorch、ONNX、TensorFlow、Caffe、TFLite 等但我强烈建议你统一走 ONNX 这条路。原因有几点ONNX 是开放的中间表示格式几乎主流框架都能导出RKNN-Toolkit2 对 ONNX 的支持最稳定文档和示例也最全排查问题的时候ONNX 可以用 Netron 可视化非常直观。PyTorch 模型导出 ONNX 时要特别注意动态轴的问题。比如你的模型输入是 [1, 3, 224, 224]导出时如果 batch 维度是动态的RKNN-Toolkit2 在解析时可能会报错。我一般都在导出 ONNX 时固定 batch1反正边缘设备推理本来就是单张图片一来的场景不需要动态 batch。TensorFlow 模型转 ONNX 需要用到 tf2onnxCaffe 模型现在用得少了但如果你手头有老的 Caffe 模型RKNN-Toolkit2 也支持直接转换只是某些算子的兼容性需要额外留意。2.4 量化原理与校准数据集RK3568 的 NPU 对 INT8 支持最好INT8 模型的推理速度通常是 FP16 的 2 到 3 倍内存占用也小得多。所以实际部署时几乎都是 INT8 量化模型。量化的本质是把浮点权重和激活值映射到 8bit 的整数范围。比如某层输出的分布是 [-3.2, 7.5]那么量化就是要找到合适的 scale 和 zero-point把这个范围映射到 [-128, 127]。RKNN-Toolkit2 做量化时需要提供一个 calibration dataset一般就是几百张有代表性的图片。工具会把这些图片逐张喂给模型统计每一层激活值的 min/max 或者直方图分布从而确定 scale 和 zero-point。这里有个实操要点校准集不需要有标注label只需要是真实场景下的图片即可。校准集里的图片不要跟训练集完全一样但分布要接近推理时的真实场景。如果你想做目标检测就放一些目标出现在不同位置的图片如果是做分类就放各类别均衡的图片。校准集数量我一般控制在 200 到 500 张之间太多会影响转换时间太少则量化精度可能不够。2.5 RKNPU2 运行时的工作机制RKNPU2 是瑞芯微 NPU 的二代运行时架构对应 RK3568、RK3588 这一代芯片。它的工作机制可以理解为应用 CPU跑应用逻辑和 NPU跑模型计算通过共享内存进行数据交互。具体到流程上应用先把输入图片通常是 NV12 或 RGB 格式写入内存然后调用 librknnmrt.so 的接口把内存地址、模型输入尺寸、通道信息告诉 NPUNPU 完成计算后把结果写回内存应用再从内存里取出来做后处理。整个过程是异步流水线式的高吞吐场景下可以同时有多个输入在排队。理解这个机制对性能调优非常关键。比如你要提升推理吞吐不是简单地换个更快模型而是要减少 CPU 和 NPU 之间的数据拷贝次数尽量让输入数据直接指向共享内存避免不必要的 memcpy。3. 实操过程与核心环节实现3.1 PC 端环境准备与 RKNN-Toolkit2 安装我先讲 PC 端怎么部署转换环境。推荐使用 Ubuntu 20.04 或 22.04Python 用 3.8 到 3.11 均可我实测 3.8 和 3.10 都没问题。环境准备分三步走。第一步是安装 conda如果你已经有 conda 就跳过这一步。用 Miniconda 最省事下载安装脚本后直接执行即可。装完后创建一个独立的 Python 环境避免跟系统 Python 打架污染全局环境。conda create -n rknn python3.8 conda activate rknn第二步是安装 RKNN-Toolkit2。瑞芯微官方提供了 pip wheels 文件和完整的依赖清单。我这里贴出最干净的安装方式注意安装的是 x86_64 版本如果你用的是 M 系列 Mac 或者树莓派这条链路就不适用。# 安装系统依赖 sudo apt-get install libxslt1-dev zlib1g-dev libglib2.0-dev \ libsm6 libxext6 libxrender-dev libgstreamer1.0-dev \ libgstreamer-plugins-base1.0-dev gcc g # 安装 Python 依赖 pip install numpy1.24.4 onnx1.13.1 \ onnxoptimizer0.3.6 onnxruntime1.14.1 \ torch2.0.1 torchvision0.15.2 \ opencv-python4.8.1.78 protobuf3.20.2 \ psutil5.9.5 ruamel.yaml0.17.21 \ flatbuffers23.5.26 requests2.31.0 # 安装 RKNN-Toolkit2 主包 pip install rknn_toolkit2-2.0.0b0-py3-none-any.whlwheel 文件要从瑞芯微官方的 rknn-toolkit2 仓库下载具体路径一般是在 GitHub 的 airockchip/rknn-toolkit2 的 releases 页面里。下载时注意区分版本号和你本机的 Python 版本别下错。第三步是验证安装是否成功。这一步非常重要很多人装完就以为万事大吉结果 import 都报错后面转换的时候才发现环境有问题。python -c from rknn.api import RKNN; print(OK)如果输出 OK说明环境就绪。如果报错绝大多数情况是某个 Python 依赖版本不对或者系统库缺失。我建议先看报错信息里缺哪个 so 文件用 apt 装上对应的系统库就行。3.2 准备 ONNX 模型与校准图片拿到环境之后先别急着转换大模型。我建议新手先用一个小模型把整个链路跑通比如官方 modelzoo 里的 mobilenet_v2 或者 resnet18这些模型转换速度快、问题少适合用来验证环境。模型准备我通常这样处理。如果你手头有 PyTorch 模型先导出 ONNX。下面这条命令是 PyTorch 导出的标准姿势。import torch model torch.load(./yolov5s.pt)[model].float() model.eval() dummy_input torch.randn(1, 3, 640, 640) torch.onnx.export( model, dummy_input, ./yolov5s.onnx, opset_version11, input_names[images], output_names[output] ) print(ONNX exported)导出 ONNX 时有两个点要特别留意。第一个是opset_version。RKNN-Toolkit2 对 opset 版本有兼容范围过高或过低都可能解析失败。我实测 opset 11 是兼容性最好的yolov5 导出时默认也是 11 或 12如果导出时版本更高建议显式指定低一点。第二个是模型输入尺寸需要固定。RKNN-Toolkit2 虽然支持动态输入但解析和优化效果都不如静态输入好。你在导出 ONNX 时一定要用具体的 shape 生成 dummy input这样导出的 ONNX 就带上了固定 shape。校准图片的准备就简单了。你找一个真实场景的图片文件夹用 Python 读取并 resize 到模型输入尺寸逐个保存为 npy 或者由转换脚本直接读取。RKNN-Toolkit2 支持传入图片路径列表也支持传入 numpy 数组列表我一般用后者因为读取和预处理都在同一份代码里可控。3.3 15 条高频命令与对应功能拆解这条条命令是我在 RK3568 部署中反复使用的按功能分组说明。第 1 条查看 RKNN-Toolkit2 版本python -c from rknn.api import RKNN; print(RKNN().get_sdk_version())这条命令能输出当前环境中 RKNN-Toolkit2 的版本。为什么重要因为不同版本对模型算子支持、量化算法、runtime 兼容性都不一样。你开发板上装的 runtime 库版本必须和 PC 端转换工具版本匹配否则会出现模型能转换但板子跑不了的情况。每次开始新项目前先敲一下这条命令确认版本。第 2 条全量导出 ONNX 模型结构python -m onnxruntime.tools.make_dynamic_shape_fixed --input_names images --input_shapes 1,3,640,640 model.onnx model_fixed.onnx这条命令的作用是把 ONNX 里的动态轴全部固定下来。很多模型导出时 batch 维度是动态的RKNN-Toolkit2 解析时可能报错或者生成的 RKNN 模型在推理时行为异常。用这条命令先固定 shape再从 model_fixed.onnx 继续转换可以省掉很多坑。第 3 条查看 ONNX 模型算子列表python -c import onnx; modelonnx.load(model.onnx); print(sorted(set(node.op_type for node in model.graph.node)))这条命令用来列出模型里用到的所有算子类型。转 RKNN 之前先扫一眼算子列表能快速判断模型是否适合部署。比如看到自定义算子或者某些不常见的算子就要提前查一下 RKNN 是否支持避免转换到一半才报错。第 4 条初始化 RKNN 对象python -c from rknn.api import RKNN; rknnRKNN(); print(init ok)这是 RKNN 转换流程的第一步。后面所有操作都基于这个 RKNN 对象来调用包括配置、加载模型、转换、导出。第 5 条模型转换全流程脚本包含配置、加载、构建、导出python convert.py这条代表的是一段完整脚本内容如下。convert.py 是转换的骨架你以后所有模型转换都可以基于它改。from rknn.api import RKNN rknn RKNN() ret rknn.config( mean_values[[0, 0, 0]], std_values[[255, 255, 255]], target_platformrk3568 ) assert ret 0, config failed ret rknn.load_onnx(model./model.onnx) assert ret 0, load onnx failed ret rknn.build(do_quantizationTrue, dataset./dataset.txt) assert ret 0, build failed ret rknn.export_rknn(./model.rknn) assert ret 0, export failed print(convert done)这里有三个参数值得解释。mean_values 和 std_values这两个是输入图像的归一化参数。RKNN 在 NPU 上做推理时会先按这些值对输入图像做归一化。如果你训练模型时用的是 ImageNet 的 mean[0.485, 0.456, 0.406]、std[0.229, 0.224, 0.225]那你需要在 config 里设置对应的 RGB 通道均值和标准差。如果训练时用的是简单的 0~255 映射到 0~1那 mean_values 就是 [0,0,0]、std_values 是 [255,255,255]。归一化参数错误会导致推理结果完全不对但不会报错这是非常隐蔽的坑。target_platform必须指定为 rk3568。不写或者写错比如用默认值 rk3588生成的模型在 RK3568 上跑不了。dataset.txt这个文件里每一行是一个校准图片的路径。构建时 do_quantizationTrue 会走量化流程读取这些图片来统计激活值分布。第 6 条查看生成的 RKNN 模型信息python -c import os; print(os.path.getsize(model.rknn))模型大小是判断模型是否符合预期的最快方式。比如 FCOS 类的检测模型INT8 量化后应该在 10 到 20 MB 之间。如果模型过大、过小或者出现异常往往说明转换过程有问题需要回查。第 7 条用自带模拟器验证 RKNN 模型python run_simulator.py这条代表脚本 run_simulator.py内容如下from rknn.api import RKNN rknn RKNN() rknn.load_rknn(./model.rknn) rknn.init_runtime(targetNone) img preprocess(./test.jpg) # 自行实现预处理 outputs rknn.inference(inputs[img]) print(outputs)这里的 targetNone 表示在 PC 上使用模拟器进行推理不需要连接开发板。模拟器的意义在于模型转换后、部署到板子前先在 PC 端跑通一次推理确认输出结果合理再上板。这个测试环节很关键能省下大量上板调试的时间。模拟器的精度与真实 NPU 的精度有细微差异但不会差太多。第 8 条init_runtime 指定连接开发板rknn.init_runtime(targetrk3568, device_idadb)当你要在真实开发板上跑推理验证时init_runtime 需要指定 target 为 rk3568并且通过 adb 连接。连接成功后后面的 inference 就会在开发板的 NPU 上执行。注意这里的 device_id 是你 adb devices 里看到的设备序列号如果只有一个设备连接可以省略。第 9 条批量精度评估脚本python eval_accuracy.py这条代表的是一段精度评估脚本作用是拿原始模型和量化模型在测试集上分别跑一遍对比精度差异。内容大概是加载同一个测试集分别调用原始模型和 RKNN 模型的推理接口计算 mAP、accuracy 等指标最后打印差值。如果量化后精度下降超过可接受范围就需要考虑改用量化感知训练或者混合量化。第 10 条查看开发板 NPU 进程和占用adb shell cat /sys/kernel/debug/rknpu/loadRK3568 的 NPU 驱动提供了实时负载查询接口。这条命令会输出各核心的占用率百分比。当你在板子上跑模型推理时用这个命令可以确认 NPU 是否真的在工作占用率是否正常。如果占用率很低说明模型可能被 CPU 模拟执行了或者推理调用失败降级了需要排查 runtime 配置。第 11 条查看开发板上 runtime 库版本adb shell strings /usr/lib/librknnmrt.so | grep -i version开发板上装的 runtime 库版本直接决定了它能跑哪个版本的 RKNN 模型。如果 PC 端转换工具是 2.0.0b0而开发板上 runtime 库是 1.6.0那基本没法跑。用这条命令确认两端版本匹配是排查问题的第一动作。第 12 条向开发板推送模型文件adb push model.rknn /userdata/这个命令把 PC 端生成的模型拷贝到开发板的 /userdata 目录。注意开发板路径要选择可写的分区系统分区一般是只读的传上去重启就丢了。我一般统一放到 /userdata 或者 /oem 下工程上方便管理。第 13 条在开发板用 lite2 推理验证python test_rknn_lite.py这条对应的脚本内容如下运行在开发板上使用 rknn-toolkit-lite2 加载模型并推理from rknnlite.api import RKNNLite rknn_lite RKNNLite() rknn_lite.load_rknn(./model.rknn) rknn_lite.init_runtime() img preprocess(./test.jpg) outputs rknn_lite.inference(inputs[img]) print(outputs)注意这里 import 的是 rknnlite.api 而不是 rknn.api这是开发板上的专属接口不要搞混。第 14 条查看开发板 CPU 与内存状态adb shell top -d 1 -n 3板子推理性能不仅取决于 NPU还跟 CPU 预处理、内存带宽有关。用 top 可以实时观察 CPU 占用和内存使用情况。如果 CPU 占用率一直是 100%说明预处理或后处理代码可能把 NPU 的提速全抵消了需要优化图片的 resize、格式转换或后处理的效率。第 15 条清理板子上无用的临时文件adb shell rm -rf /userdata/*.tmp调试过程中会反复推送模型和测试图片板子空间本来就有限养成顺手清理的习惯能避免奇怪的磁盘写满问题。这 15 条命令覆盖了从环境验证、模型转换、量化、模拟器验证、板上推理、性能分析到清理的完整链路。每条命令背后的逻辑比命令本身更重要——要知道自己每一步在做什么。3.4 一次完整的模型转换实操演示我拿一个实际例子完整走一遍转换流程。假设你有一个训练好的 yolov5s.onnx输入尺寸是 640x640。第一步先看模型算子列表确认没有冷门算子。python -c import onnx; modelonnx.load(yolov5s.onnx); print(sorted(set(node.op_type for node in model.graph.node)))第二步打开 convert.py 脚本填入模型路径、校准数据路径和相关参数。注意这里 mean_values 和 std_values 要和训练时保持一致。yolov5 训练时一般是对 RGB 图像做 /255 归一化因此 mean[0,0,0]、std[255,255,255]。dataset.txt 里每行一个校准图片路径./calib/000001.jpg ./calib/000002.jpg ./calib/000003.jpg ...校准图片 200 张左右就够。不需要对应的标注文件只要图片是接近真实场景的。第三步执行转换。python convert.py如果一切顺利你会看到日志依次输出 config ok、load onnx ok、build ok、export rknn ok。最后目录下会出现 yolov5s.rknn文件大小大概 14 MB 左右。第四步先在 PC 上用模拟器验证一次。python run_simulator.py输入一张测试图片检查输出 shape 是否和预期一致数值范围是否合理。如果你对模型的输出格式有了解可以简单检查一下是否有目标框坐标和置信度出现。第五步push 到板子用 lite2 推理验证。到这一步整个链路就算彻底跑通了。3.5 板上推理代码骨架与性能调优要点开发板上的推理代码骨架比转换脚本要简单得多。核心就三件事加载模型、预处理输入、推理并解析输出。我贴一段常用的代码结构。import cv2 import numpy as np from rknnlite.api import RKNNLite # 初始化 rknn_lite RKNNLite() rknn_lite.load_rknn(./yolov5s.rknn) rknn_lite.init_runtime(core_maskRKNNLite.NPU_CORE_0_1_2) # 读取并预处理 img cv2.imread(./test.jpg) img cv2.resize(img, (640, 640)) # 推理 outputs rknn_lite.inference(inputs[img]) # 后处理 boxes postprocess(outputs[0]) print(boxes) rknn_lite.release()性能调优主要看三个参数。一个是core_maskRK3568 有 3 个 NPU 核心可以通过 core_mask 指定使用哪些核心。默认是 NPU_CORE_AUTO系统会自动调度但如果你想独占所有核心跑单个模型可以显式指定 NPU_CORE_0_1_2。对于单模型场景三个核一起上能最大化吞吐。另一个是inference 的异步模式。RKNNLite 的 inference 默认是同步的即调用后阻塞等待 NPU 完成计算。如果你的应用是视频流处理建议开启异步模式通过轮询或者回调来获取结果这样可以同时做下一帧的预处理隐藏掉 NPU 的计算延迟。还有一个是内存复用。对于连续帧的处理尽量复用同一块输入内存避免每一帧都重新分配和释放。这在 C 接口下尤其明显Python 的 numpy 数组复用也不难实现。3.6 常见报错与排查方法我在 RK3568 部署中遇到过各种报错挑几个典型的说说。报错一E build failed because ops not supported这个报错说明模型里有 RKNN 不支持的算子。常见的解决思路是先在 PC 上查一下是哪个算子不兼容找到之后如果是 YOLO 系模型通常可以把部分后处理算子如 NMS从模型里摘除改到 CPU 上用 Python 实现如果是自定义算子需要重写网络结构用支持的算子替代。报错二E load rknn model failed, check if target_platform is correct这个报错通常因为你用 RK3588 的转换工具生成了模型或者 target_platform 没写 rk3568跑去板子上加载。解决方法是回到 PC 端重新转换把 target_platform 明确指定为 rk3568确认两端的 SDK 版本匹配。报错三E init runtime failed, please check NPU driver version这个报错和系统镜像里的 NPU 驱动版本有关。RK3568 的驱动和 runtime 库需要配套升级了系统镜像之后原来 push 的 librknnmrt.so 旧版本可能就失效了。解决方法是回读官方文档里的版本对照表要么把升级系统镜像要么下载对应版本的 runtime 库重新替换。报错四推理输出的结果全是 0 或者全 NaN这个报错八成不是转换的问题而是输入数据的预处理和训练时不匹配。比如训练时用的是 BGR 顺序你推理时传了 RGB或者训练时是 /255 归一化而你在 config 里写的 std_values 不是 255又或者图像 resize 的方式不一样。这类问题不会报错但输出彻底不对排查起来很费时间。我的习惯是转换前就把预处理逻辑和 config 参数反复对几遍确保一致。报错五板子上 runtime 库缺失有些精简版系统镜像不带 librknnmrt.so需要手动拷贝。解决方法是把 PC 端 rknn-toolkit2 包里的 runtime 目录一般是 rknpu2/runtime/Linux/librknn_api/aarch64/下的 librknnmrt.so 推到板子的 /usr/lib 目录并设置好可执行权限。4. 常见问题与排查技巧实录4.1 问题速查表现象可能原因解决方向import rknn 报错Python 依赖版本冲突用 conda 重新建环境按官方 requirements 逐一装转换时算子不支持模型包含 RKNN 无法解析的算子摘除后处理算子或查找替代实现量化后精度下降严重校准图片分布不合理换更贴近真实场景的校准集增加数量板子加载模型提示平台错误target_platform 设置不对重新转换并指定 rk3568NPU 占用率一直是 0runtime 库不匹配或推理降级到 CPU检查 librknnmrt.so 版本确认 init_runtime 正常推理结果全是 NaN输入预处理与训练不一致核对 mean_values、std_values、颜色通道顺序4.2 排查效率提升技巧排查 RKNN 问题我总结了一个最有效率的手段隔离变量。每次只改一个变量。比如先固定 PC 端转换参数不变只测板子上的 runtime 是不是好的确认 runtime 没问题后再动转换参数。如果同时改了好几个东西再测一出问题根本定位不了。另外要学会看日志。RKNN-Toolkit2 的日志级别可以通过 config 或者环境变量控制把日志打到 DEBUG 级别能看到每一步的详细输出。转化模型时如果卡住或者报错DEBUG 日志里通常会有具体到算子层面的信息。还有一个技巧多利用官方 modelzoo 作为对照组。当你自己的模型转换失败时找 modelzoo 里结构相似的标准模型先按官方脚本跑一遍。如果官方模型可以成功转换和推理说明工具链本身没坏问题出在你自己的模型上如果官方模型也报错那就要检查环境或版本了。4.3 版本兼容性RKNN 工具链的版本对应关系比较敏感我在实践中形成了一个保险策略PC 端全量工具、开发板 runtime、系统镜像里预装的驱动官方推荐什么版本就用什么版本。别自作主张去升级某个单独的组件。具体来说以 rknn-toolkit2 2.0.0b0 为例开发板上对应的 runtime 是 2.0.0b0对应的系统镜像驱动要求一般在发布说明里写清楚了。如果你手头的板子刷的是较老的系统而 PC 端工具是新版本转换出来的模型上板可能会报兼容性错误。这时候最简单的做法是降低 PC 端工具版本去适配旧的驱动而不是硬着头皮升级整个系统。4.4 个人心得体会走了几轮从零到部署的流程我想把最想告诉你的经验浓缩成几句话。环境准备阶段花半天时间把 PC 端 RKNN-Toolkit2 装顺、跑通一个官方示例模型是最划算的投资。这一步做扎实后面对所有项目都是通用的不会白费。模型转换阶段每次只改一个变量。把 target_platform、mean_values、std_values、量化开关这些参数当成实验变量来处理量化精度不达标时优先换校准集再考虑混合量化最后才想换模型结构。部署阶段先在 PC 模拟器上跑通再上板这个顺序能省一大半调试时间。真正到了板子上多数问题都出在预处理和后处理的细节上而不是模型本身。另外我强烈建议你养成记录的好习惯。每次转换成功的模型连同它的原始模型版本、onnx 导出参数、RKNN 转换配置、校准集位置、runtime 版本全部记录到一个文档里。换模型、升级工具链、复现结果的时候这份记录能帮你省下无数时间。5. 推理性能分析与硬件协同优化5.1 RK3568 NPU 性能边界RK3568 的 NPU 算力标称是 0.8 TOPSINT8在 AI 芯片里算入门级别。它跟 RK3588 的 6 TOPS 相比有明显差距所以你不能指望在 RK3568 上跑大模型。yolov5s INT8 模型在 640x640 输入下实测 NPU 推理耗时大约 80 到 100 毫秒单帧也就是 10 到 12 FPS 左右。如果是 yolov5n 这种更小的模型输入缩到 320x320推理耗时可以降到 30 毫秒左右能到 30 FPS。这个性能边界决定了你的模型选型策略。在 RK3568 上目标检测首选 yolov5n 或 yolov6n 这类 lightweight 模型分类模型要控制在 10 MB 以内分割模型尽量选 lightweight 结构别碰那些动辄上百 MB 的模型。5.2 减少 CPU 与 NPU 数据拷贝RKNN 推理链路里耗时不仅在 NPU 计算本身更在数据搬运。图片从摄像头采集到内存再从内存拷贝到 NPU 可访问的内存这个过程如果效率低会大幅度拉低整体帧率。一种常见优化是直接用 shared memory 或者 DMA 映射的方式让摄像头驱动把帧数据直接写到 NPU 可以访问的内存区域避免额外的 memcpy。这种方法需要用 C/C 写代码Python 接口下不容易直接操作但如果你做的是工业级部署这个优化能带来明显收益。还有一种优化是减少预处理开销。opencv 的 cv2.resize 和颜色转换在 CPU 上跑如果你在板子上用 Python 逐帧处理 1080p 的图像CPU 占用可能直接飙到 80% 以上。这时可以考虑用板载的 RGA 硬件加速做图像缩放和格式转换RK3568 的 RGA 支持 NV12/RGB 转换和缩放能大幅降低 CPU 负载。5.3 多线程与流水线设计边缘 AI 应用往往是多路视频流或者连续帧处理。RKNNLite 在多线程下的表现我实测过单模型多线程推理是可以的但线程数并不是越多越好。比核心数多一点点的线程数目能达到峰值继续增加反而会引入调度开销和内存带宽竞争。更推荐的方案是流水线设计。把整个链路拆成采集、预处理、推理、后处理四个阶段用生产者-消费者模式连接让每个阶段都在独立的线程里跑。这样即使 NPU 推理速度只有 10 FPS整体系统的吞吐也会比串行处理高不少因为采集和预处理可以重叠在推理时间内完成。具体到 RKNNLite 接口上要注意 inference 的异步模式。开启异步后inference 函数会立即返回你可以继续做后面的事在下一帧需要结果时再调用等待完成。这套机制配合多线程预处理能把帧率再提一个台阶。5.4 模型层面的加速策略如果 NPU 推理时间已经压不下去那就从模型层面想办法。一个方向是减小输入分辨率。例如目标检测640 降到 480推理时间可能从 100 毫秒降到 50 毫秒但 mAP 会掉一些。这个取舍必须根据实际场景评估。另一个方向是模型剪枝和蒸馏。在 PC 上先把模型做结构化剪枝剪掉冗余的通道再蒸馏恢复精度最后导出 ONNX 并转换。这种做法通常能让模型体积和推理时间同时压缩 20% 到 50%但需要你对训练有一定的驾驭能力。还有一个方向是更换更高效的模型结构。比如用 RK3568 上实测高效的 ghost 结构、mobilenetv3 的 bottleneck或者 center 这类不需要 NMS 的检测头它们在 NPU 上的表现往往比传统结构更友好因为用到的算子类型更少NPU 流水线更容易满负荷运行。5.5 端到端性能评估方法我自己在做性能评估时不看单次推理时间而是看端到端的帧率。因为板上推理通常还有采集、预处理、后处理单看 NPU 时间并不能反映真实性能。评估方法很简单跑一个循环处理 200 帧统计总耗时得出平均 FPS。过程中同时用 rknpu 的 load 接口记录 NPU 占用率。如果 NPU 占用率很高说明瓶颈在 NPU优化模型结构优先如果 NPU 占用率不高但整体帧率上不去瓶颈可能在 CPU 预处理或数据拷贝优先优化代码效率。这套评估方法能帮你快速找到短板避免盲目调参浪费精力。6. 进阶探索与我的踩坑经验6.1 从模拟器到真实 NPU 的差异RKNN-Toolkit2 的模拟器适合快速验证转换是否正确但输出结果跟真实 NPU 有细微差别。主要来源是量化后的数值精度在不同硬件上的表现不太一样以及 NPU 的算子实现和模拟器有所差异。我碰到过一次情况模拟器上推理一切正常检测框也很准但上了板之后发现某个类别的置信度明显偏低。排查了半天发现问题出在模型里某个算子在真实 NPU 上的数值稳定性和模拟器不一致导致后续输出偏差被放大。最后通过调整量化策略改用混合量化问题才解决。所以我的建议是模拟器只做基本检查一切以板上实测为准。如果板上精度跟预期差距较大优先考虑重新做量化。6.2 量化感知训练值得做吗如果你有训练数据而且时间允许量化感知训练是提升 RK3568 部署精度最有效的方法。普通的后训练量化PTQ丢精度是常态特别是在小模型上。QAT 在训练阶段就把量化误差纳入考虑模型权重会自适应调整最后部署时的精度损失往往能控制在 1% 以内。我在实际项目中做过对比同样是 yolov5s用 PTQ 转 INT8 后 mAP 下降了 3% 左右而用 QAT 训练的模型再转换mAP 只下降 0.5% 左右。对于检测类任务3% 的 mAP 降幅可能会造成漏检率上升很多QAT 的优势非常明显。不过 QAT 的复杂度也摆在面前。PyTorch 的 QAT 需要改训练代码要加入伪量化节点训练时间也变长。如果不是精度敏感型场景PTQ 加几轮校准集优化已经够用如果精度要求高投入 QAT 是值得的。6.3 多模型同时调度注意事项有些场景需要同时跑多个模型比如行人检测加车牌识别。RK3568 的 NPU 是支持多模型并行的多个模型可以分配到不同的核心上。多模型并行部署时要特别注意内存占用。每个模型都要加载到内存里加上内部中间结果的缓冲几个模型加起来很容易吃光内存。我建议先估算每个模型占用的内存再决定同时加载多少个模型。如果内存不够就按需动态加载模型切换时从存储加载到内存推理完释放避免全部常驻。另外多模型并行会争抢 NPU 的带宽和内存带宽导致单个模型的推理时间可能变长。实测下来两个小模型并行跑的吞吐通常优于串行跑两个模型但三个以上就得慎重了收益很可能被调度开销抵消。6.4 部署现场容易忽略的细节真实项目部署时有一个细节容易被忽略板子系统的时间同步。如果板子的系统时间不准日志的时间戳就不可靠排查问题时会对不上。建议在部署初始化时加上 NTP 同步或者手动校准。还有一个细节是存储空间。RK3568 的 eMMC 一般不大在调试阶段模型和测试数据会堆积建议定期清理。我会写一个清理脚本把 /userdata 下的临时文件、旧的 test.jpg、转换日志定期归档或删除。最后是电源的稳定性。RK3568 在满负载推理时功耗波动明显供电不足会导致 NPU 计算错误出现偶发的推理失败。这不是软件 bug但会让你排查到怀疑人生。建议用质量可靠的电源适配器并且不要在同一个电源上挂太多外设。6.5 基于 RK3568 的下一步扩展方向打通了模型转换、部署、推理的整条链路之后很多方向都可以继续深入。嵌入式端的实时视频流分析是一个很自然的扩展方向结合 RTSP 拉流、V4L2 采集和 RKNN 推理可以做一个完整的边缘智能盒子的原型。工业质检方向上可以把异常检测模型部署上去配合工业相机做缺陷检测。在智能家居、闸机安防等场景的双目摄像头、多路视频拼接、行为识别等也都能在 RK3568 上落地只是模型和工程复杂度要合理把控。我个人在实际操作中体会最深的一件事是RK3568 的这套工具链虽然前期配置有一点门槛但一旦把 PC 端转换环境和板上 runtime 打通后面做不同项目的效率会高很多。只要你会训练模型、会基础 Linux 操作照着这套流程走基本不会卡在方向上。最后再分享一个小技巧每次拿到新的模型或者新的需求先跑通最小可行性验证也就是一个最简单模型从转换到板上推理再在这个基础上迭代功能这样可以尽早暴露工具链层面的坑而不是等项目做到一半才发现环境有问题。
返回列表