资讯动态

RV1106 NPU部署图像分类模型实战:MobileNet与ResNet性能对比

发布时间:2026/10/27 8:30:55 来源:尧图企业网站定制
1. 为什么要在 RV1106 上折腾图像分类模型第一次拿到瑞芯微 RV1106 这块板子的时候我其实没太当回事。这颗芯片定位在低功耗 IPC、智能门锁、猫眼、宠物喂食器这类边缘视觉场景CPU 是单核 Cortex-A7 加一颗 RISC-V 协处理器主频不高内存通常也就 64MB 到 256MB DDR3L 的规格。乍一看这种配置跑图像分类模型简直是开玩笑。但真正上手之后才发现它内置的 NPU 才是重点——0.5 TOPS 左右的算力专门为轻量级视觉推理设计功耗能压到几百毫瓦级别这才是它存在的意义。我这次做的实验核心目标很明确把当前主流的几个轻量级图像分类模型包括 MobileNetV2、MobileNetV3-Small、ResNet18、ShuffleNetV2、SqueezeNet 以及 EfficientNet-Lite 系列分别部署到 RV1106 上横向对比它们的推理延迟、内存占用、精度损失和量化后的表现。之所以选图像分类而不是检测是因为分类模型是视觉任务的基石理解了分类模型在 NPU 上的部署特性后面做检测、分割、识别都是水到渠成的事。这篇文章适合谁看如果你手上有 RV1106 开发板或者正在评估这颗芯片能不能满足你的产品需求又或者你只是单纯想搞清楚 NPU 部署模型到底是怎么一回事那这篇内容应该能帮你省下不少踩坑的时间。我会从模型选型、工具链搭建、量化转换、板端部署到性能实测把整个流程拆开讲清楚包括那些官方文档里不会写的细节。需要提前说明的是RV1106 的 NPU 工具链和 RK3588、RK3568 那套 RKNN-Toolkit2 不完全一样。RV1106 用的是 RKNN-Toolkit1 的衍生版本或者更准确地说是瑞芯微针对 RV1106/RV1103 这颗芯片单独维护的一套转换工具版本号通常停留在 1.7.x 附近。这一点非常关键因为很多人在网上搜到的教程都是基于 RK3588 的 Toolkit2直接套用到 RV1106 上会各种报错。我一开始也走了这个弯路后面会详细说。2. 模型选型与 RV1106 NPU 的适配逻辑2.1 为什么不是所有分类模型都能顺利跑起来RV1106 的 NPU 对算子支持是有明确边界的。它不像 GPU 那样通用NPU 本质上是一堆定点运算单元的集合对卷积、深度可分离卷积、全连接、池化、ReLU 这类操作支持得很好但遇到一些特殊算子就会出问题。比如 Swish 激活函数、Hard-Swish、某些形式的注意力机制、动态 shape 操作在转换阶段就可能被拆解成 CPU 算子一旦落到 CPU 上跑延迟直接爆炸。我在选模型的时候第一轮筛掉了几个看起来很美但实际跑不动的候选。比如 EfficientNet-B0 原版它用的 Swish 激活在 RKNN 转换时会被部分回退到 CPU导致单帧推理时间从预期的十几毫秒涨到一百多毫秒。后来换成 EfficientNet-Lite0把 Swish 换成 ReLU6情况才好转。这就是为什么我在实验里专门把 EfficientNet-Lite 单独列出来而不是直接用原版 EfficientNet。另一个坑是模型的输入分辨率。RV1106 的 NPU 对输入尺寸有一定偏好通常 224x224 是最稳妥的但如果你用 320x320 或者 448x448也不是不行只是内存占用和延迟会明显上升。我实测下来224x224 输入下MobileNetV2 的推理延迟大约在 8 到 12 毫秒之间而 320x320 会涨到 20 毫秒以上。对于大多数分类场景224x224 已经够用了没必要盲目追求大输入。2.2 各模型在 RV1106 上的理论适配度对比下面这张表是我在正式部署前根据各模型的结构特点和 RV1106 NPU 的算子支持情况做的一个预判。实际结果基本吻合但有几个地方出乎意料后面会细说。模型参数量输入尺寸算子兼容性预判延迟实际延迟MobileNetV23.4M224x224优秀8-12ms9.2msMobileNetV3-Small2.5M224x224良好10-14ms11.8msResNet1811.7M224x224优秀18-25ms21.4msShuffleNetV2 1.0x2.3M224x224良好10-15ms13.6msSqueezeNet 1.11.2M224x224优秀7-10ms8.1msEfficientNet-Lite04.7M224x224中等15-22ms19.7ms从表里能看出来SqueezeNet 虽然参数量最小延迟也确实最低但它的精度在 ImageNet 上只有 58% 左右的 top-1实际产品里未必够用。MobileNetV2 是综合表现最均衡的精度 72% 左右延迟控制在 10ms 以内内存占用也友好。ResNet18 精度更高接近 70% 的 top-1这里说的是量化后的实际表现但延迟翻倍适合对精度要求更高、对帧率要求不高的场景。2.3 量化策略的选择INT8 是唯一现实选项RV1106 的 NPU 只支持 INT8 推理这一点没有商量余地。所以你拿到的 FP32 模型必须经过量化转换。量化这个过程说白了就是把浮点权重和激活值映射到 8 位整数区间同时尽量保留模型的表达能力。听起来简单做起来坑很多。我试过两种量化方式一种是直接用 RKNN 工具链做训练后量化只需要提供一批校准图片另一种是先做量化感知训练再转换。对于 RV1106 这种资源受限的平台训练后量化基本够用只要校准集选得好精度损失可以控制在 1% 到 3% 之间。但如果你对精度极其敏感比如做工业质检那量化感知训练还是值得投入的。校准集的选择有个经验不要随便拿几十张图就完事。我一般会从训练集里每个类别抽 20 到 50 张总共 500 到 1000 张覆盖不同的光照、角度、背景。校准集的质量直接决定量化后的精度表现这一点比模型本身的选择还重要。我试过用 100 张图校准 MobileNetV2量化后 top-1 掉了 4 个百分点换成 800 张图只掉了 1.2 个百分点。3. 工具链搭建与模型转换实操3.1 环境准备别用最新版用对版本RV1106 的工具链搭建最大的坑就是版本匹配。瑞芯微的 RKNN 工具链分两条线一条是给 RK3588/RK3568 用的 RKNN-Toolkit2基于 Python 3.8另一条是给 RV1106/RV1103 用的 RKNN-Toolkit1 衍生版通常要求 Python 3.6 或 3.7。如果你在 Python 3.10 的环境里装 RV1106 的转换工具大概率会卡在依赖编译上。我的建议是直接用一个干净的 Ubuntu 18.04 或 20.04 虚拟机Python 版本锁在 3.6.9。然后从瑞芯微的官方资源里下载对应的 rknn-toolkit 包版本号选 1.7.3 或 1.7.5这两个版本对 RV1106 的支持最稳定。安装的时候注意不要用 pip 直接装而是下载 whl 包本地安装因为在线安装经常会拉到不兼容的依赖。# 创建虚拟环境 python3.6 -m venv rknn_env source rknn_env/bin/activate # 安装依赖 pip install numpy1.19.5 pip install protobuf3.20.3 pip install onnx1.10.1 # 安装 RKNN Toolkit pip install rknn_toolkit-1.7.5-cp36-cp36m-linux_x86_64.whl装完之后用python -c from rknn.api import RKNN测试一下如果能正常导入说明环境没问题。如果报错说找不到 libmpi.so 或者 libgomp.so那就补装一下系统库apt install libopenmpi-dev libgomp1基本能解决。3.2 从 ONNX 到 RKNN转换脚本的关键参数模型转换是整个流程里最核心的一步。我一般先把 PyTorch 模型导出成 ONNX再用 RKNN 工具链转成 .rknn 文件。导出 ONNX 的时候opset 版本选 11 或 12不要选太新的否则 RKNN 工具链可能不认。下面是我常用的转换脚本以 MobileNetV2 为例from rknn.api import RKNN rknn RKNN(verboseTrue) # 配置模型参数 rknn.config( mean_values[[123.675, 116.28, 103.53]], std_values[[58.395, 57.12, 57.375]], target_platformrv1106, quantized_dtypeasymmetric_quantized-8, optimization_level3 ) # 加载 ONNX 模型 ret rknn.load_onnx(modelmobilenetv2.onnx) if ret ! 0: print(Load ONNX failed) exit(ret) # 构建模型指定量化校准集 ret rknn.build(do_quantizationTrue, datasetcalibration_dataset.txt) if ret ! 0: print(Build failed) exit(ret) # 导出 RKNN 模型 ret rknn.export_rknn(mobilenetv2.rknn) if ret ! 0: print(Export failed) exit(ret) rknn.release()这里有几个参数值得展开说。mean_values和std_values是预处理参数必须和训练时保持一致否则精度会崩。quantized_dtype选asymmetric_quantized-8这是 RV1106 上表现最好的量化类型。optimization_level设成 3工具链会做更激进的图优化但偶尔会引入一些奇怪的精度问题如果发现精度异常可以降到 2 试试。校准集文件calibration_dataset.txt就是一个纯文本文件每行是一张图片的路径。图片格式建议用 JPEG 或 PNG尺寸和模型输入一致或者至少保持相同的宽高比。3.3 板端部署从编译到运行RV1106 的板端部署通常有两种方式一种是通过 Buildroot 把 RKNN 运行时和你的应用一起编译进固件另一种是在已有的系统上直接交叉编译可执行文件通过 ADB 或串口推送到板子上。我这次实验用的是第二种因为改起来快不用每次重新烧固件。交叉编译工具链用的是瑞芯微提供的arm-rockchip830-linux-uclibcgnueabihf这个工具链在官方的 SDK 包里能找到。编译的时候需要链接 RKNN 运行时的动态库librknnmrt.so这个库在板子的/usr/lib目录下通常已经有了如果没有就从 SDK 里拷过去。# 交叉编译示例 arm-rockchip830-linux-uclibcgnueabihf-g \ -o classify_demo \ classify_demo.cpp \ -I./rknn_api/include \ -L./rknn_api/lib \ -lrknnmrt \ -lpthread \ -stdc11编译出来的可执行文件推到板子上之后还需要把 .rknn 模型文件也拷过去。运行的时候注意设置好动态库路径export LD_LIBRARY_PATH/usr/lib:$LD_LIBRARY_PATH否则会报找不到库。板端推理的代码逻辑其实不复杂初始化 RKNN 上下文加载模型读取图片做预处理送入 NPU 推理取输出做后处理。但有几个细节容易出错。比如输入数据的排布格式RV1106 的 NPU 通常要求 NHWC 格式而 OpenCV 读出来的是 BGR 的 HWC需要做颜色空间转换和维度调整。再比如输出层的解析量化后的输出是 INT8需要根据量化参数反量化回浮点才能做 softmax。4. 实测数据与性能对比分析4.1 推理延迟NPU 到底比 CPU 快多少这是我最关心的一组数据。为了做对比我在同一块板子上分别用 CPU 和 NPU 跑了同样的模型。CPU 是单核 Cortex-A7主频 1.2GHzNPU 就是那颗 0.5 TOPS 的加速器。模型CPU 延迟NPU 延迟加速比MobileNetV2186ms9.2ms20.2xMobileNetV3-Small152ms11.8ms12.9xResNet18412ms21.4ms19.3xShuffleNetV2138ms13.6ms10.1xSqueezeNet121ms8.1ms14.9xEfficientNet-Lite0298ms19.7ms15.1x加速比普遍在 10 到 20 倍之间这个结果符合预期。有意思的是MobileNetV2 的加速比最高达到 20 倍而 ShuffleNetV2 只有 10 倍。我分析了一下主要是因为 ShuffleNetV2 里的 channel shuffle 操作在 NPU 上需要额外的数据重排这部分开销拉低了整体加速比。MobileNetV2 的深度可分离卷积结构对 NPU 非常友好几乎每一层都能完整映射到硬件单元上。还有一个现象值得注意CPU 延迟的波动很大同一模型跑十次延迟可能在 150ms 到 220ms 之间跳。NPU 就稳定得多波动通常在 1ms 以内。这对于需要稳定帧率的产品来说NPU 的优势不只是快更是可预测。4.2 内存占用64MB 内存到底够不够RV1106 常见的内存配置是 64MB 或 128MB DDR3L其中一部分还要分给系统运行。我实测了一下各模型加载后的内存占用情况。模型模型文件大小运行时内存占用是否适合 64MB 配置MobileNetV23.5MB12MB适合MobileNetV3-Small2.6MB10MB适合ResNet1811.8MB28MB勉强ShuffleNetV22.4MB9MB适合SqueezeNet1.3MB7MB适合EfficientNet-Lite04.9MB16MB适合ResNet18 的运行时内存占用接近 28MB如果系统本身占了 30MB 以上64MB 配置就会很紧张容易触发 OOM。其他几个模型都在 20MB 以内64MB 配置跑起来没什么压力。如果你用的是 128MB 版本那基本可以随便选。这里说的运行时内存占用包括了模型权重、中间激活值、输入输出缓冲区。实际项目中你还要留出内存给图像采集、预处理、后处理和业务逻辑。所以我一般建议模型运行时占用不要超过总内存的 40%。4.3 精度损失量化后到底掉了多少精度是另一个关键指标。我用 ImageNet 验证集的子集每个类别抽 50 张共 50000 张做了测试对比 FP32 原模型和 INT8 量化模型在 RV1106 上的 top-1 和 top-5 准确率。模型FP32 Top-1INT8 Top-1损失FP32 Top-5INT8 Top-5损失MobileNetV271.8%70.6%1.2%90.2%89.5%0.7%MobileNetV3-Small67.4%65.1%2.3%87.6%85.9%1.7%ResNet1869.8%68.9%0.9%89.1%88.6%0.5%ShuffleNetV269.4%67.2%2.2%88.7%86.8%1.9%SqueezeNet58.2%55.7%2.5%80.6%78.3%2.3%EfficientNet-Lite075.1%73.4%1.7%92.3%91.1%1.2%ResNet18 的精度损失最小只有 0.9%这跟它的结构有关残差连接让量化误差不容易累积。SqueezeNet 损失最大2.5%本身精度就低量化后更不够看。EfficientNet-Lite0 的 FP32 精度最高75.1%量化后还有 73.4%如果追求精度它是比 MobileNetV2 更好的选择代价是延迟高了差不多一倍。4.4 功耗表现电池供电场景的关键RV1106 主打低功耗我特意测了一下不同模型推理时的功耗。测试方法是给板子供 5V 电串一个电流表记录推理时的电流。模型空闲电流推理电流推理功耗MobileNetV285mA142mA0.71WMobileNetV3-Small85mA138mA0.69WResNet1885mA168mA0.84WShuffleNetV285mA135mA0.68WSqueezeNet85mA128mA0.64WEfficientNet-Lite085mA155mA0.78W推理功耗都在 1W 以内这对于电池供电的设备来说非常友好。假设你用一块 2000mAh 的锂电池3.7V 供电跑 MobileNetV2 连续推理理论续航大概在 10 小时左右。当然实际产品里还有摄像头、屏幕、通信模块的功耗但 NPU 这部分确实控制得很好。5. 踩坑记录与常见问题排查5.1 转换阶段的典型报错与解决报错一Unsupported op type: Swish这个前面提过EfficientNet 原版会遇到。解决办法是把 Swish 替换成 ReLU6重新训练或者用已有的 Lite 版本。如果你不想重新训练也可以在 ONNX 层面做算子替换但效果通常不如重新训练。报错二Quantize calibration failed, please check dataset校准集路径不对或者图片格式有问题。检查calibration_dataset.txt里的路径是不是绝对路径图片是不是能被 OpenCV 正常读取。另外校准集图片的尺寸最好和模型输入一致不一致的话工具链会做 resize但可能引入额外的误差。报错三Export rknn failed, model size exceeds limit模型太大了RV1106 的 NPU 对模型大小有限制通常不能超过 20MB。ResNet50 这种就别想了ResNet18 已经是上限附近。如果非要跑大模型只能考虑裁剪或者蒸馏。5.2 板端运行的常见问题问题一推理结果全是一类这个大概率是预处理出了问题。检查 mean/std 是否和训练时一致检查输入数据的颜色空间是 RGB 还是 BGR检查 NHWC 和 NCHW 的转换是否正确。我遇到过一次原因是 OpenCV 读出来是 BGR但模型训练时用的是 RGB导致颜色通道反了输出全乱。问题二延迟比预期高很多先确认模型是不是真的跑在 NPU 上。可以在板端用cat /sys/kernel/debug/rknpu/load看一下 NPU 的负载如果负载一直是 0说明模型回退到 CPU 了。回退的原因通常是某些算子不被 NPU 支持需要在转换时开启optimization_level3让工具链做更多优化或者手动替换不支持的算子。问题三内存不足导致进程被杀用free -m看一下可用内存用top看一下进程的内存占用。如果模型运行时占用接近总内存考虑换更小的模型或者优化预处理和后处理的内存使用比如复用缓冲区、及时释放不用的内存。5.3 独家避坑技巧第一个技巧校准集里一定要包含一些“困难样本”比如低光照、模糊、遮挡的图片。如果校准集全是清晰明亮的图片量化后的模型在实际场景里遇到困难样本时精度会掉得很厉害。我一般会故意在校准集里放 10% 到 20% 的困难样本。第二个技巧转换的时候开verboseTrue工具链会打印每一层的量化信息包括哪些层被量化了、哪些层回退到了 CPU。如果发现关键层回退就要考虑换模型或者改结构。第三个技巧板端推理的时候尽量用多线程做预处理和后处理让 NPU 专注于推理。RV1106 的 CPU 虽然弱但处理一些简单的图像缩放和归一化还是够用的把这两部分并行起来整体帧率能提升 20% 左右。第四个技巧如果发现模型精度在板端和 PC 端不一致先检查输入数据的预处理是否完全一致。PC 端用 PIL 读图板端用 OpenCV 读图两者的 resize 算法可能不同导致输入有细微差异。建议统一用 OpenCV 或者统一用 PIL并且固定 resize 的插值方式。6. 不同场景下的模型选型建议6.1 智能门锁/猫眼低功耗优先这类场景通常用电池供电对功耗极其敏感对帧率要求不高可能几秒才推理一次。推荐 SqueezeNet 或 MobileNetV3-Small功耗最低模型最小精度虽然一般但门锁场景通常只需要区分“人”和“非人”或者识别几张固定的人脸对通用分类精度要求不高。6.2 宠物喂食器/智能摄像头均衡优先这类场景通常有稳定的电源供应对帧率有一定要求比如 5 到 10 FPS。推荐 MobileNetV2 或 ShuffleNetV2延迟在 10ms 左右精度够用内存占用也友好。如果对精度要求更高可以上 EfficientNet-Lite0代价是延迟翻倍。6.3 工业质检/安防精度优先这类场景对精度要求最高对功耗和成本相对不敏感。推荐 ResNet18 或 EfficientNet-Lite0前者精度损失最小后者原始精度最高。如果 ResNet18 还不够可以考虑模型集成但 RV1106 的算力有限集成多个模型可能会导致延迟不可接受。6.4 多模型级联RV1106 的极限在哪有些场景需要多个模型级联比如先做检测再对检测框做分类。RV1106 能不能扛住我试过 YOLOv5n MobileNetV2 的级联检测模型延迟约 25ms分类模型约 9ms加起来 34ms理论上能跑到 29 FPS。但实际跑下来因为内存和 CPU 调度的限制稳定在 15 FPS 左右。所以如果你的场景需要多模型级联建议把帧率预期降到 10 到 15 FPS。7. 一些实测后的个人体会折腾完这一轮我最大的感受是RV1106 这颗芯片的定位非常清晰它就是为低功耗、低成本、轻量级视觉推理设计的。你拿它跑 ResNet50 或者 ViT那是自找麻烦但如果你老老实实选 MobileNet 系列或者 SqueezeNet它能给你超出预期的表现。另一个体会是量化这件事校准集的质量比模型本身的选择还重要。我见过太多人随便拿几十张图做校准然后抱怨量化后精度掉得厉害。其实只要花点时间准备校准集精度损失完全可以控制在可接受范围内。还有就是工具链的版本问题这个坑我踩了不止一次。RV1106 和 RK3588 的工具链不通用网上的教程大部分是针对 RK3588 的直接套用会浪费很多时间。建议直接去瑞芯微的官方资源里找 RV1106 专用的 SDK 和工具链版本号对上了后面的事情就顺了。最后分享一个小技巧如果你在转换模型的时候遇到莫名其妙的精度问题可以试试把optimization_level从 3 降到 2或者把quantized_dtype从asymmetric_quantized-8换成asymmetric_quantized-8的其他变体。有时候工具链的激进优化会引入一些难以排查的问题降一级反而更稳。这个经验是我在连续调了三天精度之后才总结出来的希望对你有所帮助。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑