ARTICLE DETAIL

资讯详情

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

RK3566/RK3588 NPU部署实战:RKNN模型转换与推理验证指南

RK3566/RK3588 NPU部署实战:RKNN模型转换与推理验证指南 1. 为什么要在 RK3566/RK3568/RK3588 上折腾 RKNN NPU手里攥着一块 RK3566 或者 RK3588 的板子看着规格书里那个 0.8 TOPS 或者 6 TOPS 的 NPU 算力第一反应肯定是想跑个模型试试。但真到动手的时候很多人会卡在第一步环境怎么搭工具链从哪来模型怎么转板子上跑起来为什么报错这一套流程我前前后后在三块板子上走过好几遍从 RK3566 的轻量场景到 RK3588 的多核 NPU 调度踩过的坑足够写一本小册子。这篇内容就是把这套流程完整地摊开从宿主机环境准备、RKNN-Toolkit2 安装、模型转换、板端运行时部署一直到第一个模型推理验证跑通。不管你是刚拿到板子的新手还是已经在调设备树但还没碰过 NPU 的老手都能从这里找到能直接抄的步骤。先明确几个概念避免后面混淆。RKNN是瑞芯微这套 NPU 工具链的名字包含两大部分跑在 PC 上的RKNN-Toolkit2负责模型转换和仿真和跑在板子上的RKNN Runtime负责实际推理。NPU就是板子上的神经网络加速单元RK3566/RK3568 是单核 0.8 TOPSRK3588 是三核 6 TOPS 且支持多核协同。这三个芯片的 NPU 架构同源工具链基本通用但 RK3588 多了多核调度和更大的内存带宽实际部署时有些参数需要区别对待。我见过太多人一上来就去搞模型量化、算子优化结果连rknn_server都没跑起来。所以这篇的路线是先把最小闭环跑通再谈优化。一个最简单的 MobileNet 或者 YOLOv5n能在板子上出结果比什么都重要。2. 宿主机环境搭建别在版本上栽跟头2.1 系统选择与 Python 版本陷阱RKNN-Toolkit2 对系统环境有明确要求官方推荐 Ubuntu 20.04 或 22.04。我实测下来Ubuntu 22.04 Python 3.8 到 3.10是最稳的组合。为什么强调这个因为 Toolkit2 的 wheel 包是按 Python 版本编译的你用 Python 3.11 或者 3.12大概率找不到对应的包或者装上了但 import 就报错。有个细节很多人忽略conda 环境和系统 Python 的冲突。如果你用 conda 建了虚拟环境装完 Toolkit2 后跑模型转换可能会遇到libstdc.so.6版本不匹配的问题。原因是 conda 自带的 libstdc 版本比系统的高而 Toolkit2 依赖系统库。解决办法要么用系统 Python 加 venv要么在 conda 环境里手动指定库路径。我个人的习惯是直接用系统 Python 建 venv省去这层麻烦。# 确认系统版本 lsb_release -a # 安装基础依赖 sudo apt update sudo apt install -y python3-pip python3-venv python3-dev sudo apt install -y libgl1 libglib2.0-0 libsm6 libxext6 libxrender-dev # 创建虚拟环境 python3 -m venv rknn_env source rknn_env/bin/activate pip install --upgrade pip注意如果你用的是 WSL2USB 设备透传会有问题板子连接可能不稳定。建议要么用原生 Ubuntu要么在 WSL2 里只做模型转换板端调试换到 Windows 或者另一台 Linux 机器。2.2 RKNN-Toolkit2 安装与验证Toolkit2 的包从瑞芯微的 GitHub 仓库或者官方下载站获取。截至我写这篇的时候稳定版本在 1.6 到 2.0 之间。版本选择有个原则板端 Runtime 的版本要和 Toolkit2 版本匹配否则模型转换出来的 rknn 文件在板子上加载会报版本不兼容。# 下载对应版本的 wheel 包以 2.0.0b0 为例 pip install rknn_toolkit2-2.0.0b09bab5682-cp38-cp38-linux_x86_64.whl # 验证安装 python3 -c from rknn.api import RKNN; print(RKNN Toolkit2 loaded)如果这行命令没报错说明基础环境 OK。接下来验证一下 Toolkit2 能不能正常连接板子。这里需要板子已经烧录好固件并且通过 USB 或者网络和宿主机连通。from rknn.api import RKNN rknn RKNN() # 通过 adb 连接板子需要开启 adb ret rknn.init_runtime(targetrk3588) print(Runtime init:, ret) rknn.release()init_runtime返回 0 表示连接成功。如果返回非零先检查adb devices能不能看到板子。RK3588 的板子有些默认 adb 是关闭的需要在串口终端里执行setprop persist.adb.tcp.port 5555然后adb connect。2.3 板端 Runtime 环境确认板子这边固件里通常已经带了librknnrt.so和rknn_server。你可以通过以下命令确认# 在板子上执行 ls /usr/lib/librknnrt.so ls /usr/bin/rknn_server # 查看版本 strings /usr/lib/librknnrt.so | grep -i version如果固件里没有需要从 SDK 里编译或者从官方仓库下载对应架构的库。RK3566/RK3568 是 32 位还是 64 位取决于你的 rootfsRK3588 基本都是 64 位。库的架构必须和 rootfs 匹配否则加载会报wrong ELF class。3. 模型转换从 ONNX 到 RKNN 的关键步骤3.1 模型准备与算子兼容性检查拿一个训练好的模型来转第一步不是直接跑转换脚本而是先检查算子支持情况。RKNN 对算子的支持是有限制的尤其是自定义算子或者一些新出的激活函数。我一般会先用 Toolkit2 的load_onnx加载模型然后看日志里有没有unsupported op的警告。以 YOLOv5n 为例从 PyTorch 导出 ONNX 的时候opset_version建议用 11 或者 12。太高了 RKNN 可能不认太低了某些算子表达不了。导出命令import torch model torch.hub.load(ultralytics/yolov5, yolov5n) dummy torch.randn(1, 3, 640, 640) torch.onnx.export(model, dummy, yolov5n.onnx, opset_version12, input_names[images], output_names[output])导出后用 Netron 看一眼结构确认没有奇怪的算子。然后进 RKNN 转换from rknn.api import RKNN rknn RKNN(verboseTrue) # 配置 rknn.config( mean_values[[0, 0, 0]], std_values[[255, 255, 255]], target_platformrk3588, quantized_dtypeasymmetric_quantized-8, optimization_level3 ) # 加载 ONNX ret rknn.load_onnx(modelyolov5n.onnx) if ret ! 0: print(Load ONNX failed) exit(ret) # 构建需要量化数据集 ret rknn.build(do_quantizationTrue, dataset./dataset.txt) if ret ! 0: print(Build failed) exit(ret) # 导出 ret rknn.export_rknn(yolov5n.rknn) rknn.release()这里有几个关键参数需要解释。mean_values和std_values是预处理参数必须和训练时的归一化方式一致否则精度会崩。quantized_dtype选asymmetric_quantized-8是 INT8 量化RK3588 的 NPU 对 INT8 支持最好。optimization_level3会做一些算子融合但有时候融合后精度下降可以降到 2 试试。3.2 量化数据集制作与精度调优量化数据集是 INT8 转换的核心。数据集不需要标注只需要一批有代表性的输入图片通常 100 到 300 张就够。图片要覆盖实际场景的各种情况比如光照变化、目标大小变化。如果只用几张图量化参数估计不准精度会掉得很厉害。dataset.txt的格式很简单每行一个图片路径./images/001.jpg ./images/002.jpg ...我一般会从训练集里随机抽 200 张resize 到模型输入尺寸放到一个文件夹里。注意不要用训练时增强过的图用原图就行。量化完之后Toolkit2 会输出每层的量化误差。如果某层误差特别大可以考虑把这层设为不量化或者调整量化算法。不过对于大多数常规模型默认配置就能到可用的精度。3.3 RK3588 多核配置与 RK3566 的差异RK3588 的 NPU 有三个核转换的时候可以通过target_platform指定但多核调度是在板端运行时决定的。Toolkit2 里有个npu_core参数可以设成0、1、2或者auto。auto会让 Runtime 自动分配适合多模型并行或者单模型多核加速。RK3566 和 RK3568 只有单核所以这个参数设不设都一样。但 RK3588 上如果你跑的是大模型比如 ResNet50 或者 YOLOv8m开多核能明显提升帧率。实测 YOLOv8n 在 RK3588 上单核大概 30 FPS三核能到 70 FPS 左右当然这也取决于模型结构和输入尺寸。提示多核不是万能的。如果模型本身很小多核调度的开销可能反而拖慢速度。建议先用单核跑个基准再试多核对比。4. 板端部署与首个推理验证4.1 交叉编译与板端程序编写板端推理程序可以用 C 或者 Python。Python 版依赖rknn_toolkit_lite2C 版直接链接librknnrt.so。我一般先用 Python 快速验证确认模型没问题再上 C 做性能优化。Python 版在板子上的安装# 板子上执行注意架构匹配 pip install rknn_toolkit_lite2-2.0.0b0-cp38-cp38-linux_aarch64.whl然后写一个最小的推理脚本from rknnlite.api import RKNNLite import numpy as np import cv2 rknn_lite RKNNLite() ret rknn_lite.load_rknn(yolov5n.rknn) ret rknn_lite.init_runtime(core_maskRKNNLite.NPU_CORE_0) img cv2.imread(test.jpg) img cv2.resize(img, (640, 640)) img img[:, :, ::-1] # BGR to RGB img np.expand_dims(img, axis0) outputs rknn_lite.inference(inputs[img]) print(Output shape:, outputs[0].shape) rknn_lite.release()core_mask参数在 RK3588 上可以指定用哪个核NPU_CORE_0、NPU_CORE_1、NPU_CORE_2或者NPU_CORE_AUTO。RK3566/RK3568 上这个参数无效但写上也不报错。4.2 推理结果验证与常见报错第一次跑推理最常见的报错是输入尺寸不匹配和数据类型不对。RKNN 模型对输入的要求很严格NHWC 格式UINT8 或者 FP32 取决于量化配置。如果你传进去的是 FP32 但模型是 INT8 量化的Runtime 会自动转换但速度会慢。另一个高频问题是内存不足。RK3588 跑大模型的时候如果 rootfs 的 CMA 内存不够会报malloc failed。解决办法是在设备树里调大 CMA 预留或者用rknn_lite.init_runtime的时候指定perf_mode为RKNNLite.NPU_FULL_PERF来优化内存分配。我整理了一个常见报错速查表报错信息可能原因解决办法load_rknn failed模型文件损坏或版本不匹配重新转换确认 Toolkit2 和 Runtime 版本一致init_runtime failedNPU 驱动未加载或权限不足检查/dev/rknpu是否存在用 root 运行inference failed输入尺寸或格式不对打印输入 shape确认 NHWC 和量化类型malloc failedCMA 内存不足调大设备树 CMA或减小模型输入尺寸unsupported op模型含不支持算子替换算子或改用 CPU 推理该层4.3 性能基准测试与优化方向跑通之后下一步是测性能。RKNN Runtime 提供了eval_perf接口可以输出每层的耗时。C 版里用rknn_query查RKNN_QUERY_PERF_DETAIL。# Python 版性能测试 rknn_lite.init_runtime(core_maskRKNNLite.NPU_CORE_AUTO) # 跑 100 次取平均 import time start time.time() for _ in range(100): rknn_lite.inference(inputs[img]) end time.time() print(Average latency:, (end - start) / 100 * 1000, ms)优化方向主要有几个输入尺寸320 比 640 快一倍以上、量化精度INT8 比 FP16 快、多核调度RK3588 专属、算子融合转换时开 optimization_level。但要注意优化不能牺牲精度我一般会先跑一个精度基准优化后再对比 mAP 或者 Top-1 准确率。5. 实操心得与避坑指南5.1 版本匹配是最大的坑我遇到过最折腾的问题就是版本不匹配。Toolkit2 是 1.6板子上的 Runtime 是 1.4转换出来的模型加载直接报version mismatch。解决办法只有一个统一版本。要么升级板端 Runtime要么降级 Toolkit2。升级 Runtime 需要重新编译或者替换librknnrt.so降级 Toolkit2 相对简单直接 pip 装旧版本。还有一个隐藏的坑RKNN 模型文件不向下兼容。用 2.0 转换的模型1.6 的 Runtime 加载不了。所以团队协作的时候一定要把 Toolkit2 版本写进文档别让同事用不同版本转模型。5.2 量化数据集的代表性决定精度上限很多人量化完发现精度掉得厉害第一反应是量化算法不行。其实大部分时候是数据集没选好。我试过用 50 张同一场景的图做量化结果模型在别的场景下完全不能用。后来换成 200 张覆盖各种光照和角度的图精度就回来了。量化数据集的选取原则覆盖实际部署场景的所有变化。如果是安防场景白天黑夜、晴天雨天都要有如果是工业质检不同批次的产品图都要有。数量上 100 到 300 张足够但质量比数量重要。5.3 RK3588 多核调度的实际表现RK3588 的三核 NPU 听起来很美好但实际用起来有几个限制。首先多核只对单模型推理有效如果你同时跑多个模型Runtime 会自动分配核但每个模型只能用一个核。其次多核加速比不是线性的三核大概能到 2 到 2.5 倍因为内存带宽和调度有开销。我实测过一个 YOLOv8s 模型输入 640x640单核 25 FPS三核 55 FPS。但换成 YOLOv8n单核 60 FPS三核 80 FPS提升就没那么明显。所以小模型没必要开多核大模型才值得。5.4 板端调试的实用技巧板子上调试没有宿主机方便我一般会做几件事把日志级别调高RKNN Runtime 支持RKNN_LOG_LEVEL环境变量设成debug能看到详细的加载和推理信息用strace跟踪系统调用排查库加载问题保留一个最小可复现的测试程序出问题的时候先跑这个排除业务代码的干扰。还有一个细节板子的散热。RK3588 跑 NPU 满载的时候发热很大如果散热不好会降频性能直接掉一半。我一般会加个风扇或者至少贴个散热片。RK3566 发热小一些但长时间跑也要注意。6. 从首个模型到实际项目跑通第一个模型只是起点。实际项目里还会遇到多模型串联、视频流推理、结果后处理等问题。比如做目标检测NPU 输出的是原始张量还需要在 CPU 上做 NMS 和后处理。这部分如果优化不好可能比推理本身还耗时。我的建议是先用 Python 把整个 pipeline 跑通再逐步把耗时模块移到 C 或者用 RGA 加速。RK3588 有 RGA 硬件加速器可以做图像缩放和格式转换比 CPU 快很多。MPP 则负责视频编解码和 NPU 配合能实现完整的视频分析 pipeline。另外模型转换这块现在社区里有一些自动化工具比如把 ONNX 直接转 RKNN 的脚本但我建议还是手动走一遍 Toolkit2 的流程因为自动化工具隐藏了太多细节出问题的时候不好排查。手动走一遍你知道每一步在做什么调优的时候才有方向。最后分享一个我常用的调试方法在宿主机上用 Toolkit2 的仿真模式先跑一遍。init_runtime的时候不指定targetToolkit2 会用 CPU 仿真 NPU 的行为。虽然速度慢但能快速验证模型转换是否正确不用每次都烧到板子上。仿真通过了再上板子效率高很多。
返回列表