尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

RK3588 NPU部署YOLOv8:ONNX转RKNN与板端推理实战

RK3588 NPU部署YOLOv8:ONNX转RKNN与板端推理实战 1. 为什么选择RK3588加YOLOv8这套组合RK3588这颗芯片在边缘计算圈子里火起来核心原因就一个它把NPU算力做到了6TOPS同时价格压到了很多开发者能接受的范围。我最早接触RK3588是做视觉检测项目当时对比过几套方案Jetson系列性能确实强但成本高树莓派加神经计算棒又太折腾RK3588算是找到了一个平衡点。它的NPU采用三核架构每个核心2TOPS支持INT8和INT16量化推理这对YOLOv8这种计算密集型的检测模型来说非常关键。YOLOv8作为Ultralytics推出的目标检测框架相比前代在精度和速度上都有明显提升。它的网络结构做了不少优化C2f模块替换了原来的C3模块梯度分流更充分检测头也改成了解耦头设计。这些改进让YOLOv8在同等参数量下能拿到更好的mAP但代价是模型结构更复杂直接部署到NPU上需要经过一番转换和适配。整套流程走下来核心链路是这样的在PC端用PyTorch训练YOLOv8模型导出为ONNX格式作为中间表示然后通过RKNN-Toolkit2把ONNX转成RK3588 NPU能执行的RKNN模型最后在板端用RKNN Runtime加载推理。每一步都有坑ONNX导出时的算子兼容性、量化时的精度损失、板端推理时的内存对齐任何一个环节出问题都会导致最终跑不起来。这篇文章适合谁看如果你手上有RK3588开发板想跑YOLOv8做目标检测但卡在模型转换或者板端部署环节那这篇内容能帮你省掉大量试错时间。如果你还没入手板子只是想了解整个流程长什么样也可以先看看心里有个底。我下面会按照实际操作的顺序把每个环节的关键点、参数选择依据、常见报错和解决方法都讲清楚。2. 训练环境搭建与YOLOv8模型训练要点2.1 PC端训练环境配置训练环境这块我建议直接用Ubuntu 20.04或22.04Windows下虽然也能跑但后面ONNX导出和RKNN转换容易出玄学问题。显卡方面GTX 1660 Ti 6G显存起步跑YOLOv8n或YOLOv8s没问题如果要训YOLOv8m或更大模型建议8G显存以上。我实测过用1660 Ti训YOLOv8sbatch size设16输入640x640显存占用大概5.2G刚好够用。Python环境用conda建一个独立环境避免和系统包冲突conda create -n yolov8 python3.10 conda activate yolov8 pip install ultralytics pip install onnx onnxsim onnxruntimePyTorch版本要和CUDA匹配我一般用CUDA 11.8配PyTorch 2.1.0这个组合比较稳。装完之后跑一下yolov8 checks确认环境没问题。2.2 数据集准备与标注规范YOLOv8支持的数据集格式是YOLO格式每张图对应一个txt标注文件每行格式是class_id x_center y_center width height坐标都要归一化到0到1之间。标注工具我用LabelImg或者RoboflowLabelImg本地跑方便Roboflow在线协作更顺手。数据集目录结构要组织成这样dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamldata.yaml里写清楚路径和类别path: /home/user/dataset train: images/train val: images/val nc: 3 names: [person, car, dog]这里有个容易踩的坑标注时如果图片有旋转或者EXIF方向信息读进来之后坐标会对不上。我建议标注前先用脚本把所有图片的EXIF方向信息统一处理掉避免训练时框位置偏移。2.3 训练参数选择与调优经验YOLOv8的训练命令很简洁yolo detect train datadata.yaml modelyolov8s.pt epochs200 imgsz640 batch16 patience50但参数怎么选有讲究。imgsz要和部署时的输入尺寸一致RK3588 NPU对640x640支持最好如果改成其他尺寸后面转换时可能要额外处理。batch根据显存来显存不够就降batch或者用梯度累积。patience设50表示50轮没提升就早停避免过拟合。学习率方面YOLOv8默认用余弦退火初始lr0设0.01最终lrf设0.01。如果数据集比较小建议把lr0降到0.001否则容易震荡。我训过一个只有800张图的数据集用默认学习率loss直接飞了降到0.001之后才稳定下来。数据增强默认开了mosaic和mixupmosaic对小目标检测提升明显但如果你的数据集里目标都很大mosaic可能会把目标切得太碎这时候可以调低mosaic的概率。训练过程中用TensorBoard看loss曲线如果box_loss和cls_loss都下降但mAP不涨大概率是过拟合了需要加数据或者加正则。2.4 模型导出ONNX的关键细节训练完之后导出ONNXyolo export modelbest.pt formatonnx opset12 simplifyTrueopset版本选12这是RKNN-Toolkit2支持比较好的版本。simplifyTrue会调用onnxsim做图优化把一些冗余算子合并掉对后面转换有好处。导出之后用Netron打开看一下网络结构确认输入输出节点名字。YOLOv8的ONNX输出一般是output0shape是[1, 84, 8400]84是4个坐标加80个类别8400是候选框数量。如果你训的类别数不是80这个维度会变比如3类就是[1, 7, 8400]。注意导出ONNX时不要加dynamicTrueRK3588 NPU不支持动态shape必须固定输入尺寸。3. ONNX转RKNN模型全流程拆解3.1 RKNN-Toolkit2环境搭建RKNN-Toolkit2是瑞芯微官方提供的模型转换工具只能在x86 Linux上跑Windows和Mac都不行。我一般用Ubuntu 22.04的Docker环境省得污染主机。pip install rknn-toolkit2 -i https://mirrors.aliyun.com/pypi/simple/装完之后python -c from rknn.api import RKNN验证一下。如果报错说找不到librknnrt.so需要把runtime库路径加到LD_LIBRARY_PATH里。3.2 量化策略选择INT8还是INT16RK3588 NPU支持INT8和INT16两种量化精度。INT8速度快算力利用率高但精度损失相对大INT16精度好但速度会慢一些而且不是所有算子都支持INT16。我的经验是如果模型本身参数量大、冗余度高INT8量化后精度掉点通常在1%以内可以直接用。如果模型很小或者对精度要求极高先用INT16跑一版对比如果INT16和FP16精度差不多再试INT8。量化需要校准数据集就是从训练集里抽一批图一般200到500张就够了。校准集要覆盖各种场景否则量化参数会偏。我试过只用白天图片做校准结果夜间图片检测精度掉得厉害后来把夜间图片也加进去才正常。3.3 RKNN转换脚本编写与参数解析转换脚本核心就几步加载ONNX、配置量化参数、构建RKNN、导出模型。from rknn.api import RKNN rknn RKNN(verboseTrue) # 配置 rknn.config( mean_values[[0, 0, 0]], std_values[[255, 255, 255]], target_platformrk3588, quantized_dtypeasymmetric_quantized-8, optimization_level3 ) # 加载ONNX ret rknn.load_onnx(modelbest.onnx) assert ret 0, load_onnx failed # 构建 ret rknn.build(do_quantizationTrue, datasetcalib.txt) assert ret 0, build failed # 导出 ret rknn.export_rknn(best.rknn) assert ret 0, export failed rknn.release()mean_values和std_values要和训练时的预处理一致。YOLOv8训练时输入是0到1归一化的所以mean设0std设255。如果这里搞错了推理结果会完全不对。optimization_level设3会做更多图优化但有时候会引入精度问题如果发现转换后精度异常可以降到2试试。3.4 转换常见报错与解决思路报错最多的是算子不支持。RKNN-Toolkit2对ONNX算子的支持是有限的YOLOv8里有些算子比如SiLU激活函数早期版本不支持需要替换成ReLU或者Hardswish。不过新版本已经支持SiLU了建议用最新版工具。另一个常见问题是shape不匹配。ONNX里如果有动态维度转换时会报错。解决方法是在导出ONNX时就把shape固定死或者用rknn.config里的dynamic_input指定。还有量化校准失败的情况通常是校准集图片格式不对或者路径写错了。校准集txt文件里每行是一张图的路径路径要写绝对路径相对路径容易找不到。4. 板端部署与推理性能调优4.1 RK3588开发板环境准备板子到手先烧系统官方推荐用Ubuntu 22.04或者Debian 11。烧录用RKDevToolUSB线连板子的OTG口按住Recovery键上电进入烧录模式。系统起来之后把RKNN Runtime库拷到板子上scp librknnrt.so root192.168.1.100:/usr/lib/然后装Python的rknn-toolkit-lite2pip install rknn-toolkit-lite2如果要用C推理需要交叉编译或者直接在板子上编译链接librknnrt.so。4.2 Python推理脚本编写板端Python推理脚本比PC端简单因为不需要转换直接加载rknn模型就行from rknnlite.api import RKNNLite import cv2 import numpy as np rknn RKNNLite() rknn.load_rknn(best.rknn) rknn.init_runtime(core_maskRKNNLite.NPU_CORE_0_1_2) img cv2.imread(test.jpg) img cv2.resize(img, (640, 640)) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) outputs rknn.inference(inputs[img])core_mask设NPU_CORE_0_1_2表示三个NPU核心都用上推理速度最快。如果只用一个核心速度大概慢三倍。后处理部分要把输出解码成框YOLOv8的输出是[1, 84, 8400]需要做转置、sigmoid、NMS。这部分代码比较长建议直接参考官方示例改。4.3 性能实测与瓶颈分析我实测YOLOv8s在RK3588上INT8量化640x640输入单帧推理时间大概25到30毫秒也就是30到40 FPS。这个速度做实时检测够用了。如果换成YOLOv8n能跑到50 FPS以上。瓶颈主要在NPU和CPU之间的数据搬运。如果后处理用CPU做会占不少时间。优化方法一是把后处理也放到NPU上但RKNN对后处理算子支持有限二是用多线程一个线程推理一个线程后处理流水线起来能提升吞吐。内存方面RKNN模型加载后大概占几十MB加上输入输出buffer整体内存占用可控。但如果同时跑多个模型要注意NPU核心分配别都挤在一个核心上。4.4 多核NPU调度策略RK3588的三个NPU核心可以独立调度也可以协同工作。core_mask参数控制用哪些核心NPU_CORE_0只用核心0NPU_CORE_0_1核心0和1NPU_CORE_0_1_2三个核心都用如果跑单个模型用三个核心能最大化利用算力。但如果要同时跑多个模型比如一个检测一个分类可以分配不同核心避免互相抢资源。我试过同时跑YOLOv8检测和PP-OCR文字识别检测用核心0和1OCR用核心2两个模型互不干扰整体帧率比串行跑高不少。5. 实操中踩过的坑与排查技巧5.1 模型转换阶段的典型问题问题一ONNX导出后推理结果和PyTorch不一致。这个通常是预处理没对齐。PyTorch推理时输入是RGB、0到1归一化ONNX导出后如果预处理没跟上结果就会偏。解决方法是在导出ONNX时把预处理也打包进去或者确保推理时预处理和训练时完全一致。问题二RKNN转换后精度掉太多。先检查量化校准集是否覆盖足够场景再检查mean_values和std_values是否设对。如果还不行试试关掉量化用FP16跑一版对比一下是量化问题还是转换问题。问题三板端加载RKNN模型报错。最常见的是RKNN Runtime版本和转换工具版本不匹配。转换用的RKNN-Toolkit2版本要和板端librknnrt.so版本对应版本差太多会加载失败。5.2 板端推理常见异常处理异常一推理结果全是乱码或者置信度极低。检查输入图片的通道顺序RKNN默认输入是NHWC如果传进去的是NCHW就会出错。另外检查归一化参数mean和std要和转换时一致。异常二推理速度远低于预期。先确认core_mask是否设了三个核心再检查是否开了debug模式。debug模式会打印大量日志严重拖慢速度。另外检查CPU频率是否被限制cpufreq-info看一下如果是powersave模式调到performance。异常三内存泄漏。反复推理后内存持续增长通常是输出buffer没释放。RKNN的inference接口每次返回新的numpy数组如果一直持有引用不释放内存就会涨。解决方法是用完就del或者复用buffer。5.3 精度与速度的平衡取舍实际项目中精度和速度往往要折中。我的做法是先定速度底线比如要求30 FPS然后在这个约束下选精度最高的模型和量化策略。如果INT8掉点太多就换INT16或者用更大的模型但降分辨率。另一个技巧是混合量化对精度敏感的层用INT16其他层用INT8。RKNN-Toolkit2支持通过配置文件指定某些层不量化但操作比较繁琐需要逐层分析。5.4 常见问题速查表问题现象可能原因排查方法解决方案ONNX导出失败opset版本不兼容检查opset版本改用opset 12RKNN转换报算子不支持算子不在支持列表查看工具日志替换算子或升级工具版本板端加载模型失败Runtime版本不匹配对比版本号统一转换和运行环境版本推理结果异常预处理不一致对比PC和板端预处理对齐mean/std和通道顺序推理速度慢核心未全开或debug模式检查core_mask和日志级别设三核并关闭debug内存持续增长输出buffer未释放监控内存变化及时释放或复用buffer6. 从训练到部署的完整链路复盘整套流程走下来最耗时间的其实不是训练而是模型转换和板端调试。训练有Ultralytics封装好的接口基本开箱即用但转换和部署涉及的工具链比较碎版本兼容性、算子支持、参数对齐每个环节都可能卡住。我的建议是先把链路跑通再优化。用一个预训练的YOLOv8n模型走一遍ONNX导出、RKNN转换、板端推理的完整流程确认环境没问题之后再换自己的数据集和模型。这样出问题的时候容易定位是环境问题还是模型问题。另外RKNN-Toolkit2的模拟器功能很实用可以在PC上模拟板端推理不用每次都烧到板子上。模拟器跑通了再上板能省不少时间。但模拟器和真实NPU还是有差异最终验证必须在板子上做。最后分享一个小技巧转换RKNN时把verbose打开日志里会打印每一层的量化信息如果发现某层量化误差特别大可以针对性地调整。这个日志很多人忽略但排查精度问题时非常有用。
返回列表