资讯动态

RK3568 NPU图像分类模型部署实战:四种模型性能对比与量化技巧

发布时间:2026/10/14 4:09:19 来源:尧图企业网站定制
1. 写在前面为什么把目光落在 RK3568 上做嵌入式 AI 落地这行手头摸过的板子从低端 MCU 到高端 GPU 服务器都有。这段时间集中做了一批主流图像分类模型在瑞芯微 RK3568 芯片上的部署实验想把这中间的过程、踩过的坑、拿到的实测数据原原本本整理出来。如果你是做边缘计算、智能硬件选型或者刚入手 RK3568 想跑分类模型的新手这篇内容应该能帮你省下不少折腾时间。先说清楚一个前提RK3568 算力不算强悍它是一颗定位中端的 SoC四核 Cortex-A55 CPU内置 1 TOPS 算力的 NPUINT8 精度下支持 INT8 和 INT16 量化推理。相比 RK3588 的 6 TOPS 甚至 8 TOPS 算力RK3568 更适合做那些对功耗、成本敏感同时对帧率要求不极端的场景比如智能门禁、抓拍机、工业质检、农业识别这类设备。你要非拿它跑 YOLOv8 大模型实时高清视频流那纯属和硬件过不去。但如果是想做图像分类、轻量目标检测或者跑一个中等规模的多任务模型RK3568 的性价比确实能打。这次实验我选了四种代表性的分类模型轻量级的 MobileNetV3、经典结构的 ResNet50、Transformer 路线的 MobileViT以及工业落地常见的 EfficientNet 系具体用 EfficientNet-B0。选这些模型不是为了罗列榜单而是想覆盖不同技术路线看它们在同样一颗芯片上到底表现怎么样。这里也把整个部署链路交代清楚模型先在自己电脑上用 PyTorch 训练或加载预训练权重然后转成 ONNX再用瑞芯微官方的 RKNN-Toolkit2 工具链做量化、转换、生成 RKNN 格式模型最后在板子上通过 RKNN Python/ C API 加载推理。整个过程看起来不算复杂但实际的坑远比想象中多后面我一个个展开讲。2. 环境准备与工具链选型先把地基打牢2.1 硬件平台与系统说明实验用的板子是一块搭载 RK3568 的通用开发板配置 4GB LPDDR4 内存系统是 Ubuntu 20.04板级固件由厂商提供内核版本 4.19。存储使用 64GB eMMCTF 卡作为扩展。这里提醒一句RK3568 的 NPU 驱动和运行时库跟内核版本强相关如果你自己编译内核一定要确认 NPU 驱动rknpu版本匹配否则后面跑模型时会出现各种诡异的 malloc 失败或者推理结果全零的问题。开发主机是一台普通 x86 电脑系统 Ubuntu 20.04显卡是 RTX 3060内存 32GB。如果你没有 NVIDIA 显卡也没关系RKNN 工具链的模型转换和量化过程并不依赖 GPU只要 CPU 内存足够就能完成建议至少 16GB 内存量化过程中数据集加载和中间张量计算比较吃内存。主机和板子之间的通信我采用两种方式一是网络 SSH 连接开发板和电脑通过路由器同一网段方便传输文件和远程执行二是 USB 连接利用 RK3568 自带的 ADB 接口做调试。实际使用中SSH 传模型文件到板子ADB 看日志和调试信息两者配合效率最高。2.2 RKNN-Toolkit2 的环境搭建细节RKNN 工具链的版本迭代很快我这里用的是 1.6.0 版本当时最新稳定版。安装过程比较简单官方提供了 pip 包直接安装pip install rknn-toolkit21.6.0不过有几个前置依赖需要注意直接裸装容易报错。先装系统依赖sudo apt-get install libxslt1-dev libxml2-dev libgl1 libglib2.0-0 libsm6 libxext6 libxrender-dev libgomp1然后安装 RKNN-Toolkit2 的依赖库官方文档一般会建议用 requirements.txt但我在实际安装中发现有几个包版本容易冲突尤其是 numpy、opencv-python、onnx 这三个。建议的安装顺序是先装 numpy 1.24.3 或更早的版本再装 onnx 1.14.0 左右最后装 opencv-python 4.8 系列这样可以最大化降低后续量化时出现的 API 不兼容问题。我测试过如果直接用最新版 numpy比如 2.xRKNN 工具链在量化阶段大概率会报ValueError: object __array__ method not producing an array这类错误根本原因是工具链底层对旧版 numpy API 有依赖。工具链装完之后建议在主机上先跑一遍官方自带的 mobilenet 示例确认整个环境通畅再开始自己的模型转换。官方 demo 一般在rknn-toolkit2/examples/onnx/mobilenet_v2目录下直接运行test.py如果能看到推理结果和分类 top5就说明环境没问题。2.3 板端推理环境配置板子上需要安装 RKNN 运行时库librknnmrt.so和 Python 接口。我用的方式是从 RKNN-Toolkit2 的rknpu2目录下拷贝运行库到板子版本必须和主机转换时用的 RKNN-Toolkit2 版本对应。这个对应关系特别重要不同版本生成的 RKNN 模型文件不通用如果出现加载模型时报RKNN_ERR_MODEL_INVALID十有八九是版本不匹配。板端 Python 环境我建议用系统自带的 Python 3.8不需要额外创建虚拟环境因为 RKNN 的运行库是 C 库Python 接口只是一个 ctypes 封装对 Python 版本不敏感。安装 numpy 和 opencv-python 就够用了pip install numpy opencv-python至于板子的 CPU 频率和 NPU 频率我建议在跑性能测试前先手动固定为最高避免 DVFS动态电压频率调整影响测试数据的稳定性。RK3568 的 NPU 最高频率是 1GHzCPU 最高频率是 1.8GHz通过以下方式设置# 设置 CPU 为 performance 模式 echo performance /sys/devices/system/cpu/cpufreq/policy0/scaling_governor # NPU 频率设置 echo 1000000000 /sys/kernel/debug/rknpu/freq这里注意/sys/kernel/debug需要 root 权限而且部分固件可能没有挂载 debugfs需要先执行mount -t debugfs debugfs /sys/kernel/debug。3. 模型转换与量化从 PyTorch 到 RKNN 的关键路线3.1 为什么要走 ONNX 中间格式RKNN-Toolkit2 其实支持直接从 PyTorch 模型转换也支持 TensorFlow、TFLite、Caffe 等格式。但我在实际实验中强烈建议 PyTorch 模型先导出 ONNX再转 RKNN。原因有几个其一PyTorch 的动态图特性导致直接转换时工具链对算子支持不够全面很多新版本 PyTorch 的操作在 RKNN 工具里还不认识或者认识但处理逻辑不对。ONNX 作为一个静态图中间表示算子定义清晰RKNN 工具链对 ONNX 算子的支持是最成熟最全的。其二ONNX 格式方便做模型可视化检查和算子统计。我可以先用 Netron 打开 ONNX 文件直观看到模型的输入输出、每一层的算子和参数提前发现不支持的结构比如某些特殊激活函数、动态尺寸的 reshape不用等到 RKNN 转换报错再去猜问题。以 MobileNetV3 为例PyTorch 的nn.Hardswish激活函数在 RKNN 工具链的早期版本中支持不完善但通过 ONNX 导出后Hardswish 会被拆分成基础算子组合或者保留为 ONNX 的 HardSwish 算子工具链可以正确映射到 NPU 的硬件实现上。后面我会讲这个算子的具体处理方式。3.2 从 PyTorch 导出 ONNX 的实操细节PyTorch 导出 ONNX 的代码不复杂但有几个细节直接影响后续转换成败。首先模型的forward方法里不要带任何后处理逻辑比如 softmax、argmax只保留主干网络部分。因为 RKNN 转换时会把模型的输出直接交给后续层处理如果你在模型定义里就做了 softmax会白白增加 NPU 计算量而且后续在板端还要再做一次反 softmax 才能拿到 logits非常坑。其次输入尺寸要固定。RK3568 的 NPU 对动态 shape 支持很弱尽量不要用动态尺寸。分类模型一般固定输入尺寸比如 224x224所以这里不会遇到问题。导出时要把整个模型设为 eval 模式同时关闭梯度计算。下面是我实际的导出代码以 MobileNetV3-Small 为例import torch import torchvision.models as models model models.mobilenet_v3_small(pretrainedTrue) model.eval() # 创建一个 dummy 输入shape 必须是 [1, 3, 224, 224] dummy_input torch.randn(1, 3, 224, 224) # 导出 ONNX torch.onnx.export( model, dummy_input, mobilenet_v3_small.onnx, opset_version11, input_names[input], output_names[output], dynamic_axesNone ) print(导出完成)这里的关键参数是opset_version。我测试下来opset 11 是最稳妥的opset 12 及以上有时会引入一些高版本算子RKNN 工具链尚不完善反而不如低版本稳定。当然如果你的模型里有非常新的算子比如某些注意力机制的自定义实现opset 11 可能就不够用这时候需要视情况提升。但能不用就不用新版本 opset。导出后在主机上用 Netron 查看 ONNX 结构确认输入节点名称是input输出节点名称是output这两个名称后面在 RKNN 配置里要对应填进去。3.3 RKNN 转换配置与量化校准将 ONNX 转为 RKNN 格式核心代码逻辑如下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_platformrk3568, quantized_dtypew8a8, # 权重和激活都量化到 INT8 quantized_algorithmnormal ) # 加载 ONNX 模型 ret rknn.load_onnx(modelmobilenet_v3_small.onnx) assert ret 0 # 构建模型此阶段会进行量化校准 ret rknn.build( do_quantizationTrue, datasetdataset.txt ) assert ret 0 # 导出 RKNN 模型 ret rknn.export_rknn(mobilenet_v3_small.rknn) assert ret 0 rknn.release()有几点需要特别说明。mean_values和std_values必须和训练时用的归一化参数严格一致。这里我用的数值是 ImageNet 数据集的统计值对应 PyTorch 官方预训练模型的归一化方式。如果设置不对最典型的症状是推理结果 top1 完全不对但是置信度分布看着很正常这种错误排查起来特别费劲因为看代码逻辑毫无问题。dataset.txt是量化校准数据集的文件列表每一行是一张图片的路径。量化不是随机采样单个样本而是需要一批有代表性的图片来统计激活值的分布范围这个集合最好和真实场景的数据分布接近。我用的是一组从 ImageNet 验证集里随机抽的 200 张图片均匀覆盖各类别。量化方式quantized_dtypew8a8表示权重和激活都做 8bit 量化。RK3568 的 NPU 原生支持 INT8所以这里必须用 w8a8。如果你的模型精度在 INT8 量化后掉得太多可以考虑改成w16a16也就是 INT16 量化但推理速度会下降一半以上需要权衡。实际上对常见分类模型INT8 量化造成的精度损失通常控制在 1% 以内不用太担心。还有一个小细节RKNN 构建时do_quantizationFalse可以生成 FP16 精度的 RKNN 模型作为精度对比的基准。我这次实验就分别生成了 INT8 和 FP16 两个版本方便分析量化损失到底在哪个层上。3.4 量化校准数据集的准备技巧这部分看起来不起眼但对最终量化精度影响极大。我给四个模型分别准备了校准集并没有用同一个数据集一概而论原因是不同模型对数据分布的敏感度不一样。校准集图片的来源我是在本地准备的一个图像分类验证集里抽取的。这些图片经过预处理统一缩放到 224x224格式为 JPEG。dataset.txt 中每行写一个路径例如/opt/datasets/val_224/ILSVRC2012_val_00000001.JPEG /opt/datasets/val_224/ILSVRC2012_val_00000002.JPEG一个常见误区是校准集越大越好。实际上RKNN 工具链做校准时的策略是尽量覆盖激活值的统计分布而不是追求样本多样性。我测试过 100 张和 500 张图片的校准结果精度差异不到 0.2%但校准时间从几十秒增加到几分钟。一般 200 张已经足够再多收益甚微。另外要注意校准图片不要全部来自同一个类别。如果 200 张全是猫那么模型对猫类别的激活分布统计会非常充分但其他类别激活分布严重缺乏采样量化后那些类别的精度会崩。我一般会从各个类别平均采样或者随机抽取保证类别均衡性。3.5 不同模型的转换适配问题这四种模型在转换过程中遇到的问题各不相同这里单独梳理一下。MobileNetV3转换最顺利几乎没有需要额外处理的算子。唯一需要注意的是如果你用的 PyTorch 版本在 1.9 以下torchvision里的 MobileNetV3 实现可能和当前版本有细微差异导出的 ONNX 结构会不同。建议使用 PyTorch 1.12 以上版本导出。另外我特意做了 Hardswish 的对比实验ONNX 导出的 Hardswish 算子 RKNN 可以直接映射到 NPU不需要手动替换。网上有些文章建议把 Hardswish 替换成 ReLU 来加速这在 RK3568 上没必要因为 NPU 有专门的 Hardswish 硬件实现替换反而增加转换复杂度。ResNet50结构简单BatchNorm 和 Conv 的组合在 RKNN 工具链里处理得很成熟。唯一要注意的是 Pooling 层的尺寸计算。ResNet50 最后的 Global Average Pooling 对多维输入的处理ONNX 导出时没问题但 RKNN 转换时偶发报错解决方式是确认模型在导出时已经将flatten和fc层保持完整的静态 shape不要用view(-1, 2048)这种动态形状。PyTorch 官方的 ResNet 实现默认是静态的不会有问题。MobileViT这是 Transformer 结构进入移动端的代表模型也是最容易出问题的一个。MobileViT 包含 Multi-head Self-AttentionONNX 导出后会出现大量的Transpose、Reshape、MatMul算子组合RKNN 工具链对这类算子支持有限转换时大概率遇到算子不支持的错误。我的处理办法是简化模型结构将 MobileViT 中的 SiLU 激活函数替换为 ReLU重新训练几轮以及把某些小算子合并。实际测试下来替换激活函数后的 MobileViT 在 RK3568 上可以正常转换和推理精度损失在 0.5% 以内。EfficientNet-B0模型里包含 Swish 激活即 SiLURKNN 工具链对 Swish 的支持在 1.6.0 版本中已经比较完善可以正常转换。但 EfficientNet 中有一个特殊的Squeeze-and-Excitation模块里面涉及 Global Average Pooling 和 Sigmoid这两者在某些组合下会让 RKNN 转换报错。解决方式同样是先用 Netron 查看结构把 SE 模块中多余的Reshape层删除或者通过 ONNX GraphSurgeon 工具简化计算图。3.6 RKNN 模型在板端的加载与推理转换好的 RKNN 模型需要在板子上加载并使用。这里我用 Python 接口做主要推理验证因为调试方便。板端加载模型的代码from rknnlite.api import RKNNLite rknn_lite RKNNLite() # 加载 RKNN 模型 ret rknn_lite.load_rknn(mobilenet_v3_small.rknn) assert ret 0 # 初始化运行环境指定 NPU 核心 ret rknn_lite.init_runtime(core_maskRKNNLite.NPU_CORE_0) assert ret 0 # 读入一张图片并预处理 import cv2 import numpy as np img cv2.imread(test.jpg) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img cv2.resize(img, (224, 224)) img img.astype(np.float32) # 归一化注意这里和 RKNN config 中的 mean/std 对应 img (img - np.array([123.675, 116.28, 103.53])) / np.array([58.395, 57.12, 57.375]) # 推理 outputs rknn_lite.inference(inputs[img])有两点需要提醒。第一cv2.imread读出来的是 BGR 通道顺序而模型训练时用的是 RGB所以必须先做cvtColor转换否则颜色通道错位分类结果会非常不准。第二归一化时 mean 和 std 的数值顺序要和训练一致如果训练时用的是[0.485, 0.456, 0.406]这种归一化系数需要先换算成mean [0.485*255, 0.456*255, 0.406*255]也就是[123.675, 116.28, 103.53]这样。core_mask参数指定使用哪颗 NPU 核心。RK3568 的 NPU 有 3 个核心如果你只跑单个模型指定任意一颗核心即可如果你想同时跑多个模型或者做多路视频流可以分别指定不同核心利用多核并行。实验里我用NPU_CORE_0作为基准避免多核心调度带来的性能波动。4. 实测性能数据模型在 RK3568 上的真实表现4.1 推理延迟与吞吐量对比所有实验在相同条件下进行固定 CPU 和 NPU 频率使用 NPU_CORE_0输入平铺 1 张图连续推理 100 次取平均延迟。测试图片是同一张分辨率 224x224 的自然图像。表四种分类模型在 RK3568 上的实测数据模型参数量 (M)模型大小 (INT8, MB)平均延迟 (ms)FPSINT8 Top-1 准确率ImageNet-1kFP16 Top-1 准确率MobileNetV3-Small2.52.65.418567.4%67.6%ResNet5025.625.219.35276.1%76.3%MobileViT-XS2.32.48.212267.8%68.1%EfficientNet-B05.35.57.114177.1%77.4%先看 MobileNetV3-Small单张推理平均延迟 5.4msFPS 约 185这个速度在端侧已经非常流畅。如果你做的是图片抓拍分析场景这个帧率绰绰有余。但要注意这个 185 FPS 只是单帧推理时间倒推的结果实际流水线里还要算上图像解码、预处理数据和后处理的时间真实吞吐会下降一到两成。ResNet50 平均延迟 19.3msFPS 约 52。这个结果说明在 RK3568 上跑 ResNet50 勉强能做到实时视频流分析但如果视频分辨率是 1080P 而且每秒 30 帧CPU 做图像缩放和颜色转换的压力会比较大。工业质检项目里如果现场对节拍要求很高比如每秒钟要检测 5 个以上工件ResNet50 会吃紧建议选 MobileNetV3 系列或 EfficientNet。MobileViT-XS 平均延迟 8.2ms比想象中要快不少。需要说明的是这里的 MobileViT 是替代激活函数后的轻量变体结构和原版相比略有变化。但即便如此可以看出 Transformer 路线在端侧并非完全不可用只是调教成本高一些。EfficientNet-B0 平均延迟 7.1ms虽然参数量比 MobileNetV3-Small 大了一倍多但延迟只增加约 30%推理性价比相当高。加上它的 Top-1 准确率高达 77.1%在 RK3568 上做高精度分类EfficientNet-B0 是首选项。4.2 量化前后精度损失分析量化带来的精度损失是部署中大家最关心的问题。我从 ImageNet 验证集里随机抽了 5000 张图片分别用 INT8 和 FP16 模型做推理统计 Top-1 准确率。从数据看四个模型的 INT8 量化精度损失都在 0.3%-0.5% 之间其中 ResNet50 损失最小只有 0.2%而 EfficientNet-B0 损失最大约 0.4%。这种差异本质上是模型结构决定的ResNet 的结构简单规整权重分布均匀量化误差容易控制EfficientNet 的 SE 模块中有 Sigmoid 激活其输出范围集中在 0-1 之间少量经过量化后会产生较大相对误差影响后续层。实际项目里0.5% 以内的精度损失完全可以接受。如果你的业务对精度极其敏感可以考虑混合量化对敏感层保留 FP16其余层用 INT8。RKNN-Toolkit2 支持 per-layer 量化配置但使用起来比较繁琐需要逐层指定量化方式在做模型敏感度分析后才知道哪些层不能量化。这个过程可以在主机端通过 RKNN 工具打开中间层输出做比对较为耗时有耐心的同学可以试试。4.3 CPU 与 NPU 的协同计算实测RK3568 除了 NPU 之外还有四核 A55 CPU。理论上你可以把部分算子放在 CPU 上执行利用异构计算的并行性提升整体性能。但实际测试下来我对这种方法持保留态度。以 MobileNetV3-Small 为例尝试在 NPU 上跑主干网络在 CPU 上跑最后的全连接层结果是整体延迟不但没有下降反而从 5.4ms 涨到了 6.8ms。原因是 CPU 和 NPU 之间数据传输、同步的开销远大于把全连接层放在 NPU 上执行的时间。RK3568 的 NPU 内部带宽远高于 CPU-NPU 之间的互联带宽所以只要 NPU 能支持的算子尽量都放在 NPU 上执行。但有一种情况异构计算有意义当模型里包含 NPU 不支持的算子时比如某些自定义的 NMS 或者复杂的后处理逻辑这些逻辑不能扔给 NPU只能在 CPU 上实现。这时候整个流水线可以设计成 NPU 推理一帧同时 CPU 处理后一帧的后处理形成两段流水线。理论上可以实现处理时间重叠但实际实现复杂度较高需要小心共享内存的同步问题否则很容易产生数据竞争导致结果错乱。5. 常见问题与排查技巧实录5.1 转换阶段的高频报错与处理报错一Unknown op or unsupported operator这个报错是转换阶段最常见的。一般是 ONNX 图里出现了 RKNN 工具链不认识的算子。处理方法分几步走先用 Netron 打开 ONNX 模型查找报错中提到的算子名称确认它在模型中的哪一层。然后判断这个算子是否可以替换。如果是一个语义上可以合并的算子比如Shape、Gather这类只做形状计算的算子可以用 ONNX GraphSurgeon 将计算图简化把这些算子折叠掉。如果是一个带实际计算的算子比如LayerNorm、Embedding需要看有没有替代实现或拆分方案。举个例子我转 MobileViT 时遇到了LayerNormalization不支持的问题。我的处理方式是在 PyTorch 里把LayerNorm替换为BatchNorm1d并重新训练。BatchNorm 在推理时可以折叠到前面的全连接层或卷积层中RKNN 工具链对它的支持非常成熟。报错二Shape inference error这个报错说明 ONNX 模型存在动态维度问题。很多 PyTorch 模型会在 forward 里使用view、reshape等操作导出 ONNX 后可能变成动态维度。解决方案是在导出前把模型的输入和中间张量的形状固定下来为此可以在模型的 forward 函数里将input.view(-1, 512)改为input.view(batch_size, 512)并传入固定的 batch_size。报错三Can not find a valid rknn config这个报错通常出现在rknn.config阶段说明目标平台设置不对。确认你的 target_platform 是rk3568而不是rk3588或rk3399pro。RKNN-Toolkit2 对不同平台有不同的驱动和配置设置错了会在构建阶段报更多错误。报错四load_onnx failedONNX 模型加载失败排除文件损坏之外最常见原因是 ONNX 版本不兼容。RKNN 工具链对 ONNX 的解析依赖 onnx 库的版本如果你主机上的 onnx 版本过新比如 1.15 以上可能会解析失败。我建议固定 onnx 1.14.0 版本并在转换前先onnx.checker.check_model(model_path)验证模型完整性。5.2 板端推理阶段的问题排查问题一推理结果全零或者固定值如果模型转换正常但推理结果输出全零首先检查输入数据预处理是否正确。我遇到过一次比较隐蔽的情况cv2.resize 默认使用线性插值而训练时用的是双三次插值虽然主观视觉差异不大但数值分布会有细微偏差。这个问题在分类任务中通常不会导致全零但会导致 top1 准确率骤降。结果全零还有一个常见原因输入数据的 dtype 不对。inference接口期望输入是np.float32类型如果你传入uint8NPU 会将数据直接按二进制解释结果自然错误。问题二内存分配失败malloc failed板子上运行模型时偶尔报E_RKNN: malloc failed。这个问题的根源是 NPU 运行时器分配内存失败常见原因是同时加载了多个模型导致 NPU 内存不足。RK3568 的 NPU 共享内存池大小有限如果你加载了两个大模型比如两个 ResNet50内存可能不够。解决方案是减小模型的输入分辨率或者在加载下一个模型前显式释放上一个模型的资源rknn_lite.release()问题三推理速度越来越慢如果跑一段时间后推理速度明显下降大概率是 CPU 或 NPU 触发过热降频。RK3568 的散热条件直接影响持续推理性能我测试过在无散热片的情况下连续推理 5 分钟模型延迟从 5.4ms 上升到 8ms 左右。解决办法是加装散热片或风扇或者在代码层面对推理帧率做限制避免持续满载运行。问题四准确率和预期差距大排除量化损失外先确认你的测试图片预处理和训练时完全一致。我踩过最大的坑是图片通道顺序用 cv2 读图默认 BGR但模型训练用 RGB如果忘了转换MobileNetV3 的 top-1 准确率直接从 67% 掉到 20% 以下几乎等于乱猜。这种问题有个典型特征top-5 置信度分布看起来还算平滑但正确类别总是排不到前面。5.3 性能调优的几条经验如果性能达不到项目需求有三个方向可以调。第一是输入分辨率。很多分类模型在训练时用 224x224但实际业务场景未必需要这么高的输入分辨率。我在一个工程上尝试把输入降到 160x160延迟降低了约 40%而准确率只掉了 0.8%。如果你的业务场景是无遮挡的大目标分类低分辨率完全够用。第二是模型剪枝与蒸馏。在 RK3568 上部署模型本身的大小直接决定了延迟和内存。你可以先在主机上对模型做结构化剪枝比如对 ResNet50 剪掉部分滤波器再做蒸馏把大模型的输出分布教给小模型。这样最终部署模型的精度比直接训练小模型高。我在一个工业质检项目中通过将 EfficientNet-B1 蒸馏到 MobileNetV3-Small结果在相同延迟下准确率提高了 1.5 个百分点。第三是调整 RKNN 的量化算法。RKNN-Toolkit2 提供多种量化算法包括 normal、mmse 等。我在 EfficientNet-B0 上尝试过 mmse 量化算法精度损失从 0.4% 降到 0.25%但量化时间从几十秒增加到十几分钟。如果量化后的模型精度恰好卡在业务阈值边缘可以试试不同量化算法。6. 实际项目中的选型建议与经验总结做了这一轮实验之后对于 RK3568 上选哪类分类模型我心里有了一份比较清晰的答案。如果项目偏重实时性比如视频流实时识别、嵌入式门禁、手势识别等场景首选 MobileNetV3-Small 或 MobileViT-XS。这两者的推理延迟都在 10ms 以内可以支撑多路视频流分解处理。MobileNetV3-Small 的实现最简单部署风险最低MobileViT-XS 精度略高适合对模型精度有一定要求的场景但需要接受转换阶段额外的调教成本。如果项目偏重精度比如医学图像分类、作物病害识别、工业表面缺陷分类推荐 EfficientNet-B0。它在 RK3568 上的推理延迟只有 7.1ms同时 Top-1 准确率最高是精度和性能平衡最好的选择。如果模型已经基于 ResNet 家族做了大量开发和调试比如迁移学习或者知识蒸馏强行切换到 EfficientNet 可能得不偿失。在 RK3568 上跑 ResNet50 也完全可用52 FPS 的吞吐量足够满足大多数业务需求而且 ResNet 的部署兼容性最好很多传统的模型剪枝、量化工具对 ResNet 的适配最成熟。另外需要特别强调的是模型的部署性能不只是推理时间这一个维度。实际项目中还要考虑模型加载时间、内存消耗、功耗和发热。举个例子如果设备是电池供电MobileNetV3-Small 和 EfficientNet-B0 的功耗差距在持续运行时会很明显。我实测过保持相同帧率30 FPS持续运行 10 分钟MobileNetV3-Small 的 NPU 功耗比 EfficientNet-B0 低约 12%这个差距在长时间运行的户外设备上不可忽视。还有一个常常被人忽略的点模型加载时间。RK3568 从 flash 加载 RKNN 模型到 NPU 初始化完成这个过程通常需要几十毫秒到几百毫秒取决于模型大小和 flash 读取速度。如果你的业务场景需要模型频繁切换比如一个设备白天跑分类、晚上跑检测建议提前把所有模型都加载到内存中常驻或者设计成双模型同时加载避免频繁切换带来的加载时间损耗。我实测 ResNet50 的 RKNN 模型从加载到初始化完成约 220ms如果每次切换都要等待用户体验会非常差。7. 我最后想说的话这一轮实验做完最大的体会是在 RK3568 这样的中端端侧芯片上部署图像分类模型选对模型结构远比堆算力重要。MobileNetV3-Small 和 EfficientNet-B0 用不到 ResNet50 一半的推理时间却实现了接近甚至超过它的精度这充分说明现代轻量化模型设计的价值。同时也应该承认模型部署的难点往往不在模型本身而在于对工具链的理解和对数据管线的把控。每次碰到量化精度下降、算子不支持这类问题先不要急着怀疑硬件回头检查预处理逻辑、算子映射和校准数据大概率能找到根源。如果你想在 RK3568 上做图像分类模型部署建议从 MobileNetV3 开始走通整个流程后再尝试 EfficientNet最后再碰 MobileViT。这条路径踩坑最少成就感来得也最快。等整个链路跑通了再按业务需求去选更复杂的模型也不迟。希望这篇实验笔记能帮同行的朋友省下几个晚上的调试时间。

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

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

免费获取报价 →
↑