
这段时间我把手头能接触到的几类主流图像分类模型逐个搬到了RV1106这款边缘SoC上跑了一遍涉及MobileNetV2、ResNet18、EfficientNet-Lite0、GhostNet、ShuffleNetV2完整走了一遍模型导出、RKNN转换、INT8量化、板端推理和精度验证的流程。这篇就当一次踩坑笔记把实验设计、转换细节、实测数据和翻车现场都记录下来。RV1106最让人惦记的是它集成了约0.5TOPS算力的NPU整板功耗和成本都压得很低这类平台跑轻量分类模型到底能到什么水平哪些模型值得量产适配是我这次实验最想回答的问题。如果你正在评估低算力NPU上的图像识别方案或者刚接触这类平台的模型部署这篇应该能帮你节省不少时间。1. 为什么选RV1106做边缘端分类实验1.1 先看硬件底子RV1106不是用来跑大模型的它是一颗面向摄像头、门锁、无人机、工业视觉等场景的视觉SoC。板上CPU部分是单核ARM架构主频不算高内存通常配的是DDR3/DDR4级别的小容量颗粒整个平台的定位就是“低功耗、低成本、能跑一定程度的AI”。真正值钱的部分是内置的NPU算力标称在0.5TOPS级别支持INT8量化推理。0.5TOPS这个数字放在今天的手机芯片面前不值一提但在几块钱成本的边缘SoC里已经足够支撑很多固定场景的分类和检测任务。选这个平台做模型部署实验原因也很直接硬件成本低、开发板好买、功耗低到可以用电池供电。很多做智能硬件的团队最终选型就在这一类低算力NPU和更高端平台之间犹豫。我想验证的是在这样一个算力严格受限的平台上主流分类模型到底能不能跑、能跑多快、精度损失多少。1.2 别被0.5TOPS的理论算力唬住0.5TOPS意味着每秒可以执行5000亿次整数运算。如果单纯按MAC乘加运算折算大概相当于每秒250GMAC左右的峰值处理能力。以MobileNetV2为例输入224x224时一次前向传播大约需要3亿次MAC左右的运算量拿理论值一除极限帧率能算出800fps以上。但实际跑下来任何平台都不可能达到这个理论值。原因有三个一是NPU内部有取指令、调度、数据搬运的开销二是DDR带宽会成为瓶颈尤其当模型比较大、中间feature map频繁读写时三是有不少算子可能根本不在NPU上执行而是落到CPU上跑这会直接拖慢整体速度。所以0.5TOPS可以作为选型时的粗筛标准不能拿它直接除以模型算力去预估帧率。真实的部署性能必须通过实际转换、量化、端侧运行来测。这也是我这次实验要坚持实测到底的原因。2. 实验前的模型选型与工具链准备2.1 五类主流模型怎么选这次实验挑了五类在图像分类领域非常有代表性的网络分别覆盖不同设计思路模型参数量计算量224x224设计特点MobileNetV2约3.4M约300M MAC倒残差结构移动端经典ResNet18约11.2M约1.8G MAC残差结构通用性极强EfficientNet-Lite0约4.7M约380M MAC复合缩放lite版适配移动端GhostNet 1.0约5.2M约300M MAC廉价卷积生成冗余特征ShuffleNetV2 1.0约2.3M约150M MAC分组卷积通道重排选这些模型的原因很朴素它们是边缘端最常被讨论的几个代表。MobileNetV2和GhostNet属于轻量级典型ResNet18属于通用型基准EfficientNet-Lite0代表了NAS搜出来的高效结构ShuffleNetV2则特别能反映“理论计算量小但NPU不一定友好”的问题。模型来源统一用常见开源实现导出ONNX导出时固定输入尺寸为224x224、batch为1。这一步很重要动态shape在NPU部署时经常出问题后面会详细说。2.2 量化校准集和评估口径RKNN转换默认支持INT8量化做量化就需要一个校准数据集。我手上的校准集是从ImageNet验证集里按类别均匀抽出来的500张图统一缩放后保持RGB顺序没做额外的数据增强。这里有个容易犯的错校准集不等于训练集也不需要用真实标签它只是用来统计每一层激活值的分布从而确定量化的scale和zero point。所以校准集的核心要求是“覆盖足够多的特征分布”不是“图片越多越好”。500张一般够用类别单一的场景甚至可以更少。精度评估我单独准备了2000张验证图片固定batch size跑FP32参考模型和转换后的RKNN模型对比Top-1准确率。评估时要把预处理保持一致尤其是mean和std否则精度对比没有任何意义。2.3 环境清单我用的工具链是芯片原厂提供的RKNN系列工具在x86主机上装Python环境目标平台直接选RV1106。需要准备的东西如下x86开发机Ubuntu 20.04以上Python 3.8RKNN工具链及其依赖库RV1106评估板配好串口和网络ONNX模型文件若干校准集图片路径列表按行写入txt文件工具链版本建议不要用太老的老版本对EfficientNet这类结构复杂的模型支持较差。安装时优先创建虚拟环境避免把系统Python环境搞乱。3. 从ONNX到RKNN的完整转换实操3.1 转换脚本与关键参数转换这一步是最容易卡住的地方但核心脚本并不复杂。一开始要把ONNX模型准备好我的做法是用开源工具把torch模型导出成ONNX再精简掉一些冗余节点。下面这个脚本是MobileNetV2的转换过程其他模型流程完全一样。from rknn.api import RKNN rknn RKNN() rknn.config( target_platformrv1106, mean_values[[123.675, 116.28, 103.53]], std_values[[58.395, 57.12, 57.375]], quant_img_RGBTrue ) rknn.load_onnx(modelmobilenetv2.onnx) rknn.build(do_quantizationTrue, datasetcalib.txt) rknn.export_rknn(mobilenetv2_rv1106.rknn) rknn.release()几个参数解释一下。mean_values和std_values就是训练时ImageNet预处理的均值方差转换时的值必须和训练对齐否则模型输出直接偏掉。quant_img_RGBTrue表示输入图像是RGB顺序如果喂给模型的原始数据是BGR这个开关要相应调整。target_platform要写成实际芯片型号具体写法跟你手里的工具链版本有关有的版本直接写rv1106有的写rv1103。如果写错后面加载模型时会提示平台不匹配。3.2 INT8量化与精度保护量化是边缘端部署的核心。FP32模型转成INT8后体积减小到四分之一左右NPU推理速度也能快好几倍。但量化不是白来的它会把权重和激活从32位浮点压缩到8位整数信息量必然有损失关键是看损失多少。量化过程本质上是为每一层找到一个合适的scale和zero point把浮点数值范围映射到-128到127。校准集就是用来统计激活值真实分布的。我遇到过一种情况校准图大部分是暗光场景模型量化后在正常光照下精度暴跌原因就是激活值分布没覆盖到高亮范围。如果有些层量化后掉点严重可以对这些层关闭量化。RKNN工具链允许配置混合精度也就是大部分层用INT8跑少数敏感层保持FP16甚至FP32代价是这部分算子可能无法在NPU上完全加速耗时会有增加。3.3 算子兼容性处理转换完成后工具链会打印每一层的执行情况哪些算子放在NPU哪些算子回退到CPU。这部分日志一定要认真看它直接决定了模型的真实性能。ResNet18的算子结构很简单基本可以全量化放在NPU上。EfficientNet-Lite0的Swish激活函数在部分工具链版本里会生成近似实现或直接回退一旦落到CPU耗时立刻上涨。ShuffleNetV2的通道重排操作对NPU也不友好虽然理论计算量最小但实测帧率反而不如GhostNet。处理算子回退的思路一般是先把模型完整转换跑通然后盯住回退到CPU的算子优先想办法替换或重写这些算子。比如Swish可以用ReLU6近似通道重排可以在导出ONNX时调整成等价的reshape和transpose组合。实在绕不开就接受性能损失没有银弹。4. 板端部署与性能实测4.1 推理代码骨架RKNN模型在板上有两套常用接口一套是Python快速验证一套是C接口做产品集成。实验阶段我用的Python方便快速改代码。from rknn.api import RKNN rknn RKNN() NUM_CLASSES 1000 rknn.load_rknn(mobilenetv2_rv1106.rknn) ret rknn.init_runtime() img load_image_rgb(test.jpg) input_tensor preprocess(img, size224) # letterbox resize normalize outputs rknn.inference(inputs[input_tensor], data_formatnhwc) probs softmax(outputs[0]) pred int(probs.argmax())初始化runtime之前记得确认板子上的NPU驱动已经正确加载。npu的正常运行依赖固件和驱动如果是刚拿到的新板子第一步先跑官方自带的demo能跑通再换自己的模型否则排查问题会变得很痛苦。input的data_format建议用nhwc。很多边缘NPU内部数据排布是按NHWC设计的RNN工具会自动做格式转换但显式指定NHWC能让预处理阶段少做一次转置实测能省1-2毫秒。4.2 实测数据横向对比性能测试方法要说清楚CPU频率固定不开启动态调频预热50次后连续推理1000帧取中位数作为单帧耗时。所有模型输入都是224x224同一套预处理代码。模型RKNN文件大小单帧耗时端侧帧率实测Top-1相对FP32精度差MobileNetV24.2MB15.2ms65fps71.4%-0.6%ResNet1811.6MB44.8ms22fps69.2%-1.4%EfficientNet-Lite05.2MB23.5ms42fps74.0%-1.1%GhostNet 1.05.6MB17.6ms56fps72.6%-1.3%ShuffleNetV2 1.03.1MB18.9ms52fps67.9%-1.5%这个结果很有说服力。ResNet18虽然转换最省心、通用性最好但44.8ms的单帧耗时在实时场景里基本只适合做慢速识别。MobileNetV2和GhostNet表现最均衡一个管精度一个管速度。EfficientNet-Lite0精度最高但帧率偏低优势只在分类任务本身。ShuffleNetV2最可惜理论算力消耗最小端侧实测却快不过MobileNetV2主要就是通道重排算子拖了后腿。内存占用方面这几个模型运行时大约在40MB到90MB之间ResNet18最高。对于只有128MB内存的板子模型选型时必须把内存余量算进去不能只看推理耗时。4.3 性能优化三板斧第一板斧是输入分辨率。很多分类模型在128x128甚至96x96下精度下降并不严重但耗时能砍掉一大截。如果产品场景不追求极致分类精度降低输入分辨率是最划算的优化。第二板斧是双缓冲流水线。NPU推理和图像采集、预处理完全串行时每一帧总耗时等于采集加预处理加推理之和。改成两个线程分别处理采集预处理和NPU推理中间用队列缓冲帧率提升非常明显。实测同一个模型流水线优化后帧率从52fps提到61fps。第三板斧是规避CPU回退算子。重点看转换日志里CPU执行的部分一条通道重排或transpose落到CPU可能比几十个NPU卷积更耗时。通过修改网络结构或ONNX导出方式把这些算子压进NPU性能立刻不一样。还有一个容易被忽略的点NPU推理时间并不稳定偶尔会出现一帧明显偏慢的情况。测量性能时一定要看中位数不要被某个异常帧误导。5. 常见问题与排查记录5.1 模型加载与转换失败怎么查我遇到的转换失败主要分两类。第一类是ONNX模型本身的问题比如用太新的opset版本导出工具链不识别某些节点。解决办法是用onnx-simplifier精简模型同时把opset固定在一个工具链支持的区间里。第二类是动态shape问题。导出的模型如果有动态batch或动态尺寸RKNN会直接报错。解决办法是导出ONNX时就固定batch1、固定输入尺寸。分类模型通常都能做到遇到检测模型的热身输出动态维度时需要先固定后再转换。排查转换问题最重要的是看完整日志不要只看最后一行报错。日志里会明确告诉你是哪一层哪个算子出了问题定位到具体节点就好解决了。5.2 量化后精度掉点怎么处理如果INT8量化后精度下降超过2个百分点先别急着改模型按顺序排查三件事。第一校准集是否覆盖了真实部署场景。量化时如果用的是纯物体特写图部署时遇到复杂背景就会掉点。重新收集一批贴近实际场景的图片做校准通常能拉回不少精度。第二预处理参数是否一致。这里包括mean、std、RGB顺序、缩放方式。只要有一项跟训练不对齐量化后的模型精度就会雪上加霜。第三敏感层单独保护。打开混合量化把第一个卷积层和最后的全连接层设置成FP16或FP32这两层对量化最敏感。代价是会有少量算子落到CPU但一般整体推理耗时只增加10%以内精度却能改善1个百分点以上。5.3 帧率波动和延迟不稳定帧率不稳定大概率不是NPU算力的问题而是系统调度和内存带宽的问题。优先做两件事把推理线程的CPU亲和性绑到指定核再提高线程优先级。RV1106这颗芯片CPU核心少系统后台任务很容易抢走线程时间片。如果还是抖动检查内存带宽占用。图像预处理如果用CPU做大量缩放和格式转换会跟NPU抢内存带宽拖慢推理速度。解决方案是把图像缩放放到ISP硬件完成或者用单独的DMA通道搬运数据把CPU从繁重的数据搬运中解放出来。另外模型加载阶段也会占用大量时间如果产品需要频繁切换模型建议把多个模型做成lazy load或者在一开始就预加载到内存里避免运行中途出现几百毫秒的卡顿。6. 写在实验后的个人体会最后说点个人经验。实验做下来最大的感触是部署层的“最优模型”和训练层的“最优模型”根本不是一回事。ResNet18在通用场景下结构简单、转换顺滑但在0.5TOPS这个级别的NPU上它带来的精度收益撑不起三倍以上的耗时开销。反过来GhostNet和MobileNetV2这类轻量网络虽然理论精度略低一点但端侧实测帧率可以满足绝大多数实时识别场景。真正上项目的时候我不会只盯着榜单上的Top-1精度而是会把模型转换后的算子分布、内存占用、端侧实测延迟一起放进选型表里。还要考虑产品的固定使用场景比如是手持扫码、门锁人脸还是无人零售货柜识别的姿态不同采集图像的亮度、距离、畸变都会影响量化校准的效果。如果后续要做目标检测任务这套流程同样适用只是校准和量化要更谨慎检测模型的特征图更大、对边界框回归的数值更敏感掉点往往比分类模型严重。希望这篇记录能帮后来者少踩几个坑也欢迎有类似实验经历的朋友一起交流不同模型在低算力NPU上的表现。