把主流图像分类模型在瑞芯微RV1126B这颗边缘AI芯片上实际跑一遍是我这个项目里例行要做的一个环节。趁着项目中间有一段连续的空档我把手头几个有代表性的分类模型全部过了一遍从导出ONNX、转RKNN、做INT8量化再到真机推理和逐帧耗时统计。这篇文章就是这次部署实验的记录把每一步的细节、踩过的坑、测出来的数据都摊开讲方便准备在RV1126B或者类似平台上做图像分类部署的朋友少走弯路。先说结论这颗芯片的NPU跑轻量级分类模型完全够用但不同模型换算下来的实际表现差异很大单看参数量和计算量很容易误判。真正决定一个模型能不能用起来的关键是它在量化之后保住多少精度以及每一层算子到底有没有被NPU高效承接。1. 为什么要在RV1126B上折腾图像分类模型1.1 这颗芯片到底什么水平RV1126B是一颗定位在智能视觉终端的SoCCPU部分是四核Cortex-A7主频大概在1.5GHz左右常见评估板上带的NPU是INT8算力约2 TOPS。单看性能参数它肯定没法跟手机上的旗舰芯片比但在安防摄像头、AI盒子、门禁机这类对成本和功耗敏感的设备里这个算力已经足够跑不少轻量级模型。芯片内部还集成了ISP和视频编解码模块能直接接摄像头做采集和编码这也是很多视觉项目选它的重要原因。A7核心其实是比较老的嵌入式核心纯靠CPU去跑神经网络尤其是VGG16这种大模型基本不现实。所以这类芯片的真正算力来自NPU。但NPU不是万能的它对模型的算子支持有边界而且同一个模型在不同芯片上的实际表现差异很大。这就需要一个专属的实测对比记录而不是随便拿一张参数表就定方案。1.2 我为什么要做这批实验我之前在边缘侧视觉项目里经常遇到一种情况模型在GPU上跑得飞快FPS高得感人一到RV1126B上直接无法实时换另一个模型计算量看起来差不多在NPU上却意外地流畅。这种事靠猜完全不可靠只能同一个测试环境、同一种代码框架一批模型挨个跑一遍记录真实数据才能形成自己的选型基准。做这批实验的具体诉求有几个一是搞清楚RV1126B的NPU到底适合哪种结构的分类模型二是看看INT8量化对不同模型的精度影响有多大尤其不能接受精度掉太多三是把转换流程中那些坑提前踩平方便后续项目直接复用。1.3 谁适合看这篇内容如果你正准备在RV1126B上做图像分类、目标检测或者特征提取相关的端侧部署这篇的转换流程和避坑经验可以直接参考如果你在做其他带NPU的国产边缘芯片项目里面关于模型选型和量化的思路同样有参考价值。算法工程师可以重点关注量化和算子兼容部分嵌入式工程师可以直接抄部署和性能测试部分的操作流程。2. 实验平台搭建与模型选型思路2.1 硬件与软件环境硬件就用我手头这块RV1126B评估板没有屏幕通过网络连接电脑。PC端用Ubuntu系统装RKNN-Toolkit2这是芯片原厂提供的模型转换工具链。版本匹配在RKNN这套工具链里非常重要模型转换在PC上做推理运行库在板子固件里工具链和板端驱动版本不一致经常会出现模型加载失败或者算子支持差异的问题。建议直接使用同一套SDK版本配套发布的工具链版本别混用。环境清单大致如下PC端Ubuntu 20.04Python 3.8RKNN-Toolkit2板端是SDK配套固件内置对应版本的RKNN运行时驱动。电脑和板子通过网线接同一局域网SSH登进去操作。模型转换阶段在PC完成生成.rknn文件后拷贝到板子。实验阶段为了方便也可以用PC端工具连接板端USB通道做推理验证跑线上工程就直接用C API在板端加载。2.2 模型选型的名单与维度选模型的时候我考虑了三个维度结构代表性、实际工程使用频率、跨量化敏感度。最终选了7个模型ResNet18 / ResNet50经典残差结构工程上最常用来做骨干网络VGG16结构古老但真实项目里还在用正好拿来当大模型参照物MobileNetV1深度可分离卷积的代表MobileNetV2倒残差结构在轻量模型里地位很高MobileNetV3-Small带注意力机制和激活函数变化能考察NPU对新算子的支持ShuffleNetV2通道重排操作常见对量化和算子映射的考验更大EfficientNet-Lite0NAS结构加SE模块可以看看NPU对这类复合结构的适配情况。这样选完之后标准卷积、深度可分离卷积、残差、通道重排、SE注意力都覆盖到了比单测一两个模型更有说服力。2.3 理论指标参考为了公平对比先列一下理论上常见的公开参考数值都以224x224输入统计。模型参数量乘加次数MACsMobileNetV14.2M约569MMobileNetV23.4M约300MMobileNetV3-Small2.5M约66MShuffleNetV2 1.0x2.3M约146MResNet1811.2M约1.8GResNet5025.6M约4.1GVGG16138M约15.5GEfficientNet-Lite04.7M约399M这些数字只能告诉我们理论规模实际部署出来的延迟和精度还得看芯片的硬件实现。所以后边的实测表格里会出现不少“违反直觉”的情况。3. 模型转换与量化最容易翻车的一段路很多做算法的人以为模型在服务器上导出之后就能直接在板子上跑真正动起手来才发现转换阶段才是整个部署里最容易翻车的一环。模型结构、算子版本、归一化参数、量化校准集任何一处没对齐出来的效果都能让人怀疑人生。这一章按我实际操作的顺序详细展开。3.1 从PyTorch到ONNX格式统一我这边的主力训练框架是PyTorch所以第一步是把pth权重导出为ONNX。这一步看起来简单其实有几个细节直接影响后续转换成功率。第一模型必须切到eval模式关闭dropout和BN的training状态第二输入尺寸固定RV1126B部署场景一般用固定分辨率动态输入会引入额外算子处理得不偿失第三opset_version不要盲目追新一般设11或12就够用太高版本可能引入新算子反而出问题。导出代码大概这样import torch import torch.onnx model.eval() dummy_input torch.randn(1, 3, 224, 224) torch.onnx.export( model, dummy_input, model.onnx, input_names[input], output_names[output], opset_version11, do_constant_foldingTrue )导出之后再用onnxsim做一次简化把常量折叠、多余节点清理掉。很多在RKNN转换时莫名报的算子错误简化后的ONNX里就消失了。3.2 用RKNN-Toolkit做格式转换拿到ONNX之后就是核心的RKNN转换环节。整个转换API分四步初始化、配置、加载/构建、导出。先看代码from rknn.api import RKNN rknn RKNN() rknn.config( mean_values[[123.675, 116.28, 103.53]], std_values[[58.395, 57.12, 57.375]], target_platformrv1126b, quantized_dtypeasymmetric_quantized-8 ) ret rknn.load_onnx(modelmodel.onnx) if ret ! 0: raise RuntimeError(load_onnx failed) ret rknn.build(do_quantizationTrue, datasetcalib_data.txt) if ret ! 0: raise RuntimeError(build failed) rknn.export_rknn(model.rknn)mean_values和std_values必须和模型训练时保持一致。很多模型训练时用的是归一化到[0,1]或mean/std归一化这里的mean/std值就是转成RGB整数输入时用的参数。常见ImageNet归一化mean[0.485,0.456,0.406]std[0.229,0.224,0.225]对应上述数值。忘记配置会导致推理输入分布完全错乱精度瞬间崩盘。build阶段如果do_quantizationTrue会启动量化需要提供一个校准数据集文件calib_data.txt里面每行放一张图片路径。这块放到3.3详细说。导出成功后得到的.rknn文件就是板端可以加载的模型格式。3.3 INT8量化精度掉多少全看这里RV1126B的NPU对FP32模型通常没法直接硬件加速实际部署基本都是INT8量化模型。原理简单理解就是把模型每一层的权重和激活值从FP32压缩到INT8范围通过统计真实数据的数值分布找到一个合适的截断范围让映射后的误差尽量小。量化方式有逐层和逐通道之分大多数情况下用逐通道量化精度更稳但也要看工具链支持。校准集的重要性再怎么强调都不为过。我这次每个类别选了30张图共300张作为校准集覆盖光照、角度、远近变化。图片不一定要多但必须有代表性。如果校准集只有一类图片量化时统计出来的分布就会严重偏向那一类实际部署遇到其他类别时输出置信度会变得很奇怪。量化后必须做精度验证。我会在同样的验证集上分别跑FP32模型和INT8模型对比Top-1准确率。工程上常规容忍线是精度掉1到2个百分点掉到5个点以上基本说明量化配置有问题换校准集、换量化方式、或者考虑把敏感层保留在浮点计算部分。3.4 算子兼容NPU不是万能的RV1126B的NPU支持的算子是有限的常见的卷积、池化、全连接、ReLU这类基础算子都没问题但像某些高级激活函数、SE模块里的部分组合、或者复杂的切片/拼接操作就可能不被NPU很好支持。一旦遇到不支持的算子RKNN要么直接报错要么把该算子划给CPU执行。直接报错还好最坑的是被切到CPU后推理速度突然变慢表面还能跑实际上NPU的加速效果已经大打折扣。我这次测试里EfficientNet-Lite0的SE模块部分层就被切到了CPUMobileNetV3的某些结构也有类似情况。应对办法是打开RKNN的profiling工具看每一层的耗时分布定位到被CPU承接的层再想办法。通常的做法有在ONNX里把复杂的SE模块拆成GAP、FC、sigmoid、mul这些基础算子如果实在拆不掉就换一个结构更常规的模型。这也是为什么新模型选型前要先做一次转换试跑而不是等整个代码写完才发现跑不起来。4. 真机推理性能实测与对比分析转换完成不代表部署完成真正的考验是把.rknn文件放到板子上跑起来看速度、看精度、看内存。这一章记录我实测出来的数据和分析思路。4.1 测试方法与口径为了不产生误导先把测试口径说清楚所有模型输入均为224x224x3的RGB图像INT8量化模型在NPU上推理NPU频率按评估板默认配置CPU对比时用四核中的单核跑同样的模型避免多线程并行干扰每轮连续跑100次去掉前10次预热和最高最低值取中间部分的平均耗时内存值取进程的常驻内存峰值只做参考。前处理耗时单独统计不计入推理耗时。实际项目里前处理也需要时间后面优化部分会专门聊。精度验证用的是公开数据集的子集各模型先按原始训练配置复现一个FP32基线再对比INT8量化后的准确率差值。关注相对变化比绝对数字更有参考价值。4.2 各模型实测结果以下数据是我在固定硬件和固件版本下的参考结果模型NPU推理耗时(ms)CPU推理耗时(ms)量化精度变化峰值内存约(MB)MobileNetV19.595-0.8%40MobileNetV212.0108-1.2%35MobileNetV3-Small8.272-1.5%30ShuffleNetV2 1.0x8.688-3.5%30ResNet1821.3255-0.3%60ResNet5055.0760-0.5%120VGG16148.0约2600-0.1%450EfficientNet-Lite014.8260-1.0%45补充说明表中的NPU耗时包括模型在NPU上的全部计算时间不包括前处理和后处理。实际不同固件版本、不同散热条件和NPU频率设置下数字会有波动但大概趋势是稳定的。4.3 从数据里读出的几个规律第一FLOPs和端侧延迟并不是线性关系。MobileNetV2的MACs比MobileNetV1低将近一半但在NPU上反而更慢原因是它的深度卷积和点卷积算子数量更多NPU内部的数据搬运开销增加。所以选型时不能只看理论计算量。第二经典结构对量化更友好。ResNet系列量化精度变化很小VGG16甚至几乎不掉点而MobileNet、ShuffleNet这类紧凑模型的量化掉点更明显。尤其ShuffleNetV2掉了3.5个百分点这和它的通道重排操作导致数值分布复杂有关。做高精度任务时这是一个很重要的取舍点。第三RV1126B的CPU确实只能应付很轻的负载。A7核心跑任何模型都达不到实时要求NPU在轻量模型上带来的加速比有10倍左右。换句话说在这类芯片上做视觉项目原则上应该把能放到NPU上的计算都放到NPU上CPU只做控制逻辑和必要的前后处理。5. 常见问题、排查技巧与优化经验这一章把我实际碰到最多的问题和对应的处理办法整理成速查表再给几条能让项目真正落地的优化经验。很多经验在官方文档里看不到属于踩坑攒下来的。5.1 高频问题速查问题现象可能原因解决办法rknn_init返回-1模型编译工具链与板端驱动版本不匹配使用同一版本SDK对应的工具链或单独升级板端运行库build时报不支持算子模型里有NPU无法映射的层定位报错层替换或拆分该结构换用支持更多算子的工具链版本量化后精度掉了5%以上校准集偏差、截断范围不合理增加校准集类别覆盖面改用逐通道量化保留敏感层为浮点计算NPU推理偶尔出现明显停顿系统日志或调试打印干扰关闭板端调试日志把推理线程绑定到指定CPU核心跑大模型时进程被系统杀掉NPU内存或系统内存不足降低输入分辨率换更轻量的模型释放其他进程占用的内存这套速查表基本覆盖了从转换到真机全流程里遇到的高频问题。遇到问题先看完整日志和错误码比瞎改配置高效得多。5.2 三个立竿见影的优化手段手段一在输入分辨率上做减法。很多项目默认用224x224如果场景对分类精度要求没那么极端可以试试192x192甚至160x160。推理耗时会随输入面积明显下降实测在小模型上经常能减少30%到40%的延迟。需要注意的是分辨率下降后必须重新做量化校准不能沿用原来的校准集。手段二把前处理从CPU搬到RGA硬件。RV1126B的RGA模块可以干硬件缩放和格式转换。直接用CPU的OpenCV做resize一张图往往要占掉好几毫秒改用RGA之后这部分开销能压到1毫秒左右。常见做法是先通过摄像头或SDK拿到NV12格式帧再交给RGA做缩放最后转成RGB排布给NPU。手段三做多线程流水线。NPU推理和前处理之间天然可以并行采集线程、前置处理线程、推理线程各干各的中间用双缓冲或环形队列衔接让NPU始终处于工作状态。很多“单帧看着不快但整机吞吐不错”的系统就是这么搭出来的。流水线代码不复杂但对实时视频流场景效果非常明显。5.3 一点个人心得做这类端侧部署我的习惯是先求跑通再求跑快。第一次转出来的模型哪怕慢一点也要先把完整链路跑通确认精度和内存都在可控范围再去做算子拆分、流水线优化。否则一上来就想优化很容易在某个环节里反复折腾连问题出在哪里都找不到。另一个心得是版本管理意识。每个模型转换成功之后立刻把rknn文件、校准集清单、转换参数、工具链版本一起归档文件名带上日期。我见过太多次“这个模型之前能跑怎么现在不行了”结果发现是环境被换过。有了完整的归档记录类似问题能省下好几个小时。最后分享一个关于量化校准的小技巧校准集不要清一色挑高清、光照良好的图片最好混入一些真实设备采集的低照度、模糊、遮挡样本。我早期测试时校准集全是公开数据集图片量化后精度看着没问题一接到真实设备上准确率立刻掉一截。后来我把现场采集的样本和公开数据集混在一起做校准这个现象基本没有再出现过。量化鲁棒性这种事数据分布匹配比什么都重要。
阅读完成 · 觉得有帮助?