资讯动态

RV1103实测:8大图像分类模型部署与INT8量化性能对比

发布时间:2026/10/27 7:54:51 来源:尧图企业网站定制
前阵子我把一批主流图像分类模型逐一搬到了瑞芯微RV1103芯片的开发板上从SqueezeNet这种老牌轻量模型一直测到ResNet50前后折腾了两天。做完这一轮部署实验后我最直观的感受是“能跑”和“能干活”之间的距离在0.5TOPS算力、128MB内存这种入门级AIoT芯片上被拉得非常非常大。RV1103是瑞芯微面向IPC、可视门铃、低功耗摄像头这类场景出的SoC集成了NPU、DRAM外围电路做得非常精简。很多人第一反应是既然这个芯片能跑深度学习模型那常见的图像分类网络岂不是随便挑我的答案是分模型、分分辨率、分场景而且你得先做好踩坑的心理准备。这篇实验记录适合手里正好有RV1103或同平台RV1106开发板、打算跑图像分类或者轻量视觉任务的开发者。我会把参测模型、转换流程、实测数据、以及几个只有真正在板子上跑才会遇到的问题全部摊开来讲不绕弯子。1. RV1103的底牌算力、内存和CPU对部署的制约1.1 0.5TOPS到底意味着什么RV1103和RV1106属于同代平台NPU都是瑞芯微自研的RKNPU2架构INT8算力标称0.5TOPS。CPU部分是一颗Cortex-A7核心够用但绝对谈不上快另外搭配了一个RISC-V MCU做低功耗控制。这颗芯片内置DDR常见模组有64MB和128MB两个版本我这次用的是128MB版本。先说算力。0.5TOPS是峰值理论值不是持续可用值。实际跑典型卷积时NPU利用率能稳定在60%到85%已经算不错一旦模型里出现Transpose、Reshape、比较大的逐元素操作这些算子会被切到CPU去执行最终瓶颈往往不是NPU而是CPU和内存带宽。更要命的是RV1103没有GPU图像缩放、颜色空间转换、归一化这些预处理全都要靠那个单核A7硬扛。所以对RV1103来说合适的模型规模大概在几MB到二十几MB权重区间输入分辨率一般不要超过224。超过这个门槛系统内存和CPU会迅速变成新的瓶颈哪怕NPU勉强算得动整体体验也会很糟糕。1.2 128MB内存到底还剩下多少很多人把“128MB内存”理解成能自由使用的128MB这是个误区。我这次用Buildroot最小系统加MIPI CSI摄像头采集内核、设备树、rootfs、摄像头驱动、RTOS协处理器、编码器缓冲区先吃掉一大块用户态能自由申请的内存大概只有37MB。如果跑的是完整版Linux带图形栈和一堆服务可用内存会更少。这意味着ResNet50这种权重25MB左右的模型理论上能塞进去但运行时中间特征图、IO缓冲区、预处理临时内存会直接把它撑爆。如果买到的是64MB版本那可用内存可能就十几MB能选的模型范围会急剧缩小。我的建议是选型之前先在你自己的板子上执行free -m、cat /proc/meminfo看看真实剩余内存别去看开发板宣传页上的内存容量。板子与板子之间的固件差异还挺大同是128MB不同SDK跑起来的内存占用能差好几MB。1.3 部署技术路线预览RV1103的部署闭环是预训练权重或训练好的权重 - 导出ONNX - 在宿主机上通过rknn-toolkit2转成RKNN格式含INT8量化 - 把RKNN模型放到板端用C/C调用librknnmrt.so执行推理。这个链路里每一步都可能出问题。RKNN转换工具只保证“格式层面支持”完全不保证转换后的性能和精度。同一个ONNX换一个模型结构转换成功率和板端表现可能天差地别。所以我做这轮实验时刻意选了结构差异比较大的模型为的就是看清RKNN对不同结构的真实态度。2. 实验设计八个模型、四项指标2.1 参测模型名单与选择理由这一轮实验我一共测了八个模型覆盖了老牌轻量、端侧事实标准、改进结构和重量级极限模型选择理由SqueezeNet1.1老牌轻量模型参数极小看速度上限ShuffleNetV2 1.0理论计算量很低但含Channel Shuffle验证NPU兼容性MobileNetV2 1.0端侧分类事实标准深度可分离卷积对NPU友好MobileNetV3-Large带SE模块和hard-swish精度更高考察特殊算子EfficientNet-Lite0部署友好版EfficientNet用swish激活考验算子支持RepVGG-B0多分支训练、单分支部署的典型代表ResNet18中量级基准结构简单、兼容性好ResNet50重量级极限测试看128MB内存的天花板所有模型统一用224x224输入ImageNet预训练权重INT8量化这样才能保证对比口径一致。2.2 评估指标怎么定我用了四个维度的指标来衡量每个模型单帧NPU推理耗时只测rknn_run到rknn_outputs_get之间的时间不含预处理看模型本身的算力消耗。端到端帧率包含sensor采集、软件缩放、归一化、NPU推理、后处理的完整链路。我用1080P MIPI摄像头抓帧模拟真实产品场景。INT8量化前后精度用ImageNet验证集随机取1万张图在宿主机模拟器上量化评估再抽样500张在板端复核。峰值内存看/proc/self/status里的VmHWM这个值反映的是总内存占用比模型文件大小有说服力得多。另外我还记录了RKNN模型文件的体积。这个值决定了模型能不能塞进有限的Flash和内存但对运行时内存来说只能作为参考。2.3 测试环境宿主机是Ubuntu20.04 x86rknn-toolkit2 1.6.0Python3.8ONNX使用opset 11导出。板子端是Buildroot最小系统librknnmrt.so版本也是1.6.0交叉编译工具链用SDK自带的。所有模型都先用ONNX Sim优化一遍再转RKNN避免ONNX里残留无用的Identity、冗余Reshape等节点。有一点必须说明所有耗时数据是在板子被动散热、环境温度25度左右、连续跑10分钟后取稳定值。不同批次固件、不同驱动版本的性能会有波动所以下面的数据更适合做相对对比而不是拿去做产品标书。3. RKNN转换链路从ONNX到INT8的必经之坑3.1 统一转换流程与关键参数RKNN转换本身不复杂核心代码就这几行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_platformrv1103, ) rknn.load_onnx(modelmodel.onnx) rknn.build(do_quantizationTrue, datasetcalib_list.txt) rknn.export_rknn(model.rknn)先说三个容易忽略的点。第一mean_values和std_values必须和训练时的预处理一致。大多数torchvision预训练模型用的是[0.485, 0.456, 0.406]均值、[0.229, 0.224, 0.225]方差换算成0-255范围就是上面代码里的那组数。如果这里填错转换不会报错但板端推理出来的分类结果会明显变差而且你还很难排查。第二calib_list.txt里每行放一张图片的绝对路径用于量化校准。我建议校准集不要随便丢几千张图进去而是均匀覆盖所有类别比如1000类每类放2到3张图效果比随机放4000张稳定得多。第三target_platform要按SDK配套的rknn-toolkit2版本说明填写。我遇到过有的SDK版本只把RV1103统一划到rv1106目标下生成的RKNN模型照样能在RV1103上加载但这属于工具链兼容逻辑必须以你那套SDK的实际文档为准。填错平台一般不会导致转换失败但板端可能出现精度异常、加载慢这类难定位的问题。3.2 量化校准与精度验证量化阶段我默认用全INT8。RV1103的资源摆在那里混合量化或INT16虽然精度更好但模型体积变大、推理变慢性价比很低。如果全INT8精度掉了太多我建议先检查校准集是否贴合真实场景而不是急着上混合量化。一个比较容易犯的错是直接用ImageNet的图做校准但产品部署时面对的却是自己的场景数据。这个偏差会导致某一层的量化clip范围定得不对精度损失被放大。正确做法是如果做的是PCB缺陷分类、车型识别这类特定任务一定要把自己业务场景里采到的图拿去当校准集尽量覆盖不同角度、不同光照量化出来的模型才会稳。精度验证可以用rknn-toolkit2自带的模拟器它跑的是同一套量化配置精度趋势有参考价值。但模拟器和板端实测通常存在0.2到0.5个百分点的差异个别样本差异更大所以模拟器结果只能用来筛模型不能当最终验收数据。3.3 三个必踩的算子坑这轮实验里最花时间的不是想把某个模型跑起来而是眼睁睁看着某些模型“转换成功但跑不快”。ShuffleNetV2的Channel Shuffle是最典型的例子。它在ONNX里表现为一系列的Transpose加ReshapeRKNN转换时不会报错甚至模拟器推理也正常。但到了板端这些Transpose和Reshape大量落到CPU执行NPU利用率掉到60%左右整体性能被拖累。我一开始不理解为什么“理论计算量这么小”的模型跑出来不理想后来用profiling数据看到CPU占用才明白。这个结构性的问题在选型阶段就要想到ShuffleNetV2在GPU或CPU上表现不错但对RKNPU这种固定流水线NPU来说通道混洗操作非常不友好。EfficientNet的Swish激活是另一个典型坑。老版本rknn-toolkit对Swish支持不全转换时直接会报算子不支持。1.6.0版本能转但如果你的SDK版本比较老可以手动把Swish替换成x * sigmoid(x)的组合再接一个输出。需要注意改激活函数之后理论上要重新训练或至少微调一下否则精度会有一点点波动。RepVGG的问题在转换之前就要处理。训练态的RepVGG是3x3、1x1、identity多分支结构直接导出ONNX再转RKNN转换会成功但RKNN会把这几个分支当成并行卷积处理推理耗时接近翻倍。正确做法是先用重参数化脚本把三个分支折叠成单个3x3卷积再导出ONNX。折叠完之后建议喂同样的随机输入对比一下折叠前后模型的输出最大误差控制在1e-4以内才算正常。4. 实测成绩单速度、精度、内存三本账4.1 推理耗时与端到端帧率对比下面这张表是八个模型在RV1103板子上的实测数据输入端都是224x224INT8量化。模型rknn模型大小单帧rknn_run耗时端到端帧率SqueezeNet1.14.8MB28ms14.2FPSShuffleNetV2 1.03.6MB35ms12.8FPSMobileNetV2 1.06.8MB48ms9.5FPSMobileNetV3-Large8.1MB52ms8.6FPSEfficientNet-Lite08.9MB54ms8.6FPSRepVGG-B0重参数化后11.2MB76ms6.2FPSResNet1811.0MB105ms4.8FPSResNet5025.1MB360ms1.3FPS这里有一个点值得强调单帧rknn_run耗时50ms左右只代表NPU还算轻松端到端帧率却只有9FPS左右中间的差距几乎全部被预处理吃掉了。RV1103的A7单核CPU在做1080P到224的Resize和RGB转换时非常吃力这个卡点后面专门讲。从速度维度看SqueezeNet和ShuffleNetV2确实快但ShuffleNetV2的快里有很大水分因为它的Channel Shuffle在CPU上执行CPU一忙起来整体帧率就不稳定。MobileNetV2算是个甜点位48ms的单帧推理在0.5TOPS芯片上是比较合理的水平。4.2 INT8量化后的精度变化量化精度是很多人的焦虑点。我统计了八个模型量化前后的Top-1精度模型原始Top-1INT8 Top-1精度下降SqueezeNet1.157.7%56.1%-1.6%ShuffleNetV2 1.069.4%68.2%-1.2%MobileNetV2 1.071.8%69.9%-1.9%MobileNetV3-Large75.2%73.4%-1.8%EfficientNet-Lite075.1%73.0%-2.1%RepVGG-B073.9%72.1%-1.8%ResNet1869.8%68.4%-1.4%ResNet5076.1%74.3%-1.8%整体来看INT8量化带来的精度损失基本在1.2到2.1个百分点之间属于正常范围。MobileNetV2系列对量化稍微敏感一点ResNet系列反而相对稳定。这并不意外ResNet的卷积结构比较简单规整量化误差不容易被放大。但需要注意Top-1平均值正常不代表每个类别都正常。个别容易混淆的类别在量化后可能出现超过5个点的掉点。如果产品对某些特定类别很敏感建议在部署前用真实场景数据专门测一下目标类别的精度不要只盯着平均分。4.3 内存余量分析峰值内存我用VmHWM统计真实运行时的内存占用比模型文件大小高得多模型rknn模型大小实测峰值内存SqueezeNet1.14.8MB17.1MBShuffleNetV2 1.03.6MB19.5MBMobileNetV2 1.06.8MB22.0MBMobileNetV3-Large8.1MB23.2MBEfficientNet-Lite08.9MB24.5MBRepVGG-B011.2MB26.1MBResNet1811.0MB28.5MBResNet5025.1MB47.6MB按我板子上用户态剩余约37MB计算ResNet50的峰值内存跑到47.6MB直接不可用即使纯推理模式也可能因为mmap不足失败。ResNet18和RepVGG-B0勉强在安全线以内但余量不大一旦摄像头上拉高分辨率或者多开一路码流内存就会告急。如果是64MB内存版本可用内存只剩十几MB那基本只有SqueezeNet和ShuffleNetV2能玩而且还得做不少内存优化。所以内存选型时千万别只对比模型文件大小运行时峰值内存往往比文件大2到4倍中间特征图都在内存里这个账不算清楚很容易翻车。5. 把模型真正压进RV1103的优化实操5.1 预处理别让CPU打满RV1103没有GPU所有图像缩放、颜色转换、归一化都压在单核A7上。我实测用OpenCV在A7上做1080P到224的Resize要花25到35ms这直接抹掉了NPU省下来的时间。这也是为什么rknn_run只要48ms的MobileNetV2端到端帧率却只有9FPS。解决预处理瓶颈有三个思路按推荐排序。第一用ISP硬件通路直接输出小分辨率。Rockchip的摄像头通路rockit/ISP支持把sensor输入直接缩放到合适的输出分辨率比如直接输出RGB或NV12格式的224x224图像把大图缩放的活全部交给硬件CPU几乎零开销。这是最有效的方案也是产品化首选。第二如果ISP通路配置不方便就自己写定点Bilinear缩放。输入尺寸固定插值系数提前算好查表避免浮点运算。我手写的定点缩放做1080P到224的RGB图像大约6到8ms比OpenCV快三四倍。第三颜色转换也用查表。NV12转RGB的公式里浮点系数全部放大成整数查表肉眼基本看不出差异但速度提升明显。预处理优化做完之后同样的MobileNetV2端到端帧率能从9.5FPS提到14FPS左右提升幅度比换模型还大。对RV1103这种CPU孱弱的平台预处理优化的优先级应该排在模型选型之前。5.2 零拷贝IO与双缓冲RKNN runtime的标准调用方式会经过一层内部拷贝输入输出数据要先经内存中转才会交到NPU这部分开销在轻量模型上不可忽略。更高效的路径是用rknn_create_mem申请NPU可直接访问的内存再通过rknn_set_io_mem绑定IO省掉中间拷贝。核心代码逻辑大概是这样的rknn_input_attr input_attr; rknn_tensor_mem *input_mem, *output_mems; rknn_query(ctx, RKNN_QUERY_NATIVE_INPUT_ATTR, input_attr, sizeof(input_attr)); input_mem rknn_create_mem(ctx, input_attr.size); for (;;) { // 从ISP或定点缩放拿到 frame_rgb memcpy(input_mem-virt_addr, frame_rgb, input_attr.size); rknn_set_io_mem(ctx, input_mem, input_attr); rknn_run(ctx, NULL); rknn_outputs_get(ctx, 1, output, output_attr, NULL); postprocess(output.buf); rknn_outputs_release(ctx, 1, output); }rknn_create_mem申请到的是一段连续且NPU可访问的内存这样memcpy做完后NPU直接读这段内存执行不再走runtime内部再拷贝一次。对轻量模型来说这个优化能省下几毫秒到十几毫秒不等。如果想进一步压吞吐可以搞双缓冲申请两份input_mem一个在memcpy另一个在rknn_run把数据搬运时间和NPU计算时间重叠起来。但RV1103内存紧张双缓冲只建议给模型文件小于10MB的场景用ResNet18这种就别硬上了。5.3 输入分辨率是不是一定要224很多预训练模型的默认输入是224但RV1103这种算力受限的平台上适当降低输入分辨率往往能收到立竿见影的效果。我以MobileNetV2为例做了对照实验224输入时单帧rknn_run约48ms端到端9.5FPS降到192输入后rknn_run约30ms端到端能到13FPS左右Top-1精度只掉了0.8个百分点降到160输入后rknn_run约22ms端到端能到16FPS左右但精度降幅到了1.5个百分点左右。所以我的建议是如果产品对实时性有硬要求优先把分辨率降到192这个档位性价比最高。需要注意不要拿224训练的模型直接降分辨率跑精度会随分辨率下降而明显受损。最稳的做法是在训练阶段就用低分辨率输入去微调模型让网络权重提前适应小尺寸输入。还有个容易被忽略的细节RV1103的NPU对输入尺寸有对齐要求。实测某些非32倍数的分辨率会触发内部padding算力反而被浪费。建议用160、192、224这类32的倍数别用180这种不上不下的值。6. 选型建议与避坑清单6.1 按真实场景怎么选这轮实验跑完之后我自己的选型建议是通用实时分类优先MobileNetV2224输入或192输入都行。它在算力消耗、内存占用、算子兼容性、量化稳定度之间最均衡是RV1103上的万金油。如果对精度要求高、延迟不敏感选MobileNetV3-Large或EfficientNet-Lite0建议配192输入两者端到端帧率都在9FPS上下但精度是这批模型里最高的档位。如果手头是64MB内存的版本可选范围就小很多。SqueezeNet虽然精度一般但内存占用确实最低ShuffleNetV2也勉强能上但你要接受它的Channel Shuffle拖累NPU利用率这个事实。ResNet18适合做全链路验证的基准模型。它结构简单、算子完全兼容、转换零失败先用它把摄像头、预处理、推理、后处理整条链路跑通再去换更复杂的模型能少走很多弯路。ResNet50在RV1103上的结论可以直接写死不要用。1.3FPS的端到端帧率47.6MB的峰值内存除非你只需要极低速离线分类否则没有任何实用价值。6.2 部署阶段的避坑清单最后把这一轮实验里遇到的高频问题整理成清单每条都是我实际踩过的rknn-toolkit2的版本必须和板端librknnmrt.so版本对齐。版本不一致最常见的表现是rknn_init报RKNN_ERR_PARAM_INVALID或者加载成功后推理结果全乱。排查这类问题前先核对版本。target_platform要认真填别偷懒。填错不一定报错但可能遇到精度不对、模型加载慢等很难解释的玄学问题。板端首次rknn_init加载RKNN模型需要几百毫秒到一两秒。如果产品有开机流程要考虑是让用户等待还是把初始化放到后台线程否则体验会很突兀。模拟器的时间和性能数据没有参考价值它跑在x86宿主机上只能用来验证功能和精度趋势。真实性能必须以板端clock_gettime的稳定值为准。供电不太稳定的USB口会让NPU频率跌落导致性能波动。测性能前用稳压电源或者把每一个数据都多测几遍取稳定值。输出层有的模型导出的ONNX带softmax有的不带RKNN转换后也保留了这种差异。建议C侧统一做一个后处理先取topK再按需算softmax避免重复softmax导致概率输出看起来很奇怪。监控NPU和CPU占用时看/proc/rknn/rknn_process和top -H。如果发现模型明明不大但CPU占用很高大概率是有算子落到CPU执行了需要回到模型结构层面找原因。6.3 我的最终建议如果只让我推荐一个组合我会选MobileNetV2 192输入 定点预处理 零拷贝IO这是我在RV1103上试下来综合体验最稳的一套方案。理由不是MobileNetV2的Top-1精度最高而是它在NPU算力、内存占用、算子兼容性、量化损失四个维度之间最均衡。最后再分享一点我自己的体会。很多人拿到RV1103的第一件事是找“最快的模型”但实际做完这一轮对比之后我越来越觉得对这种0.5TOPS芯片来说模型结构是否贴合NPU比理论计算量更重要。结构里藏着几个Transpose、几个动态Reshape墙上的帧率可能就从20掉到10。你与其纠结MobileNet和EfficientNet那零点几的精度差距不如先把手上的候选模型全部过一遍RKNN转换拿板端的实测FPS说话。数据不会骗人。

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

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

免费获取报价 →
↑