1. 为什么要在Hi3516CV610上折腾YOLOv8

第一次拿到Hi3516CV610这块板子的时候,我其实没打算在上面跑YOLOv8。这颗芯片定位是智能视觉SoC,主打低功耗IPC场景,内置NPU算力大概在1TOPS级别(不同配置略有差异),按常规思路跑个轻量分类网络或者人脸检测就够了。但项目需求摆在那里——要在边缘端做实时目标检测,并且把视频流通过RTSP推出去给后端平台消费,预算又卡得死,Hi3516CV610几乎是唯一选择。

于是就有了这个从模型转换到RTSP推流的完整链路。整条链路走下来,涉及的核心环节包括:YOLOv8模型训练与导出、ONNX中间格式转换、芯片厂商工具链量化编译、板端推理程序集成、视频编码与RTSP服务搭建。每一步都有坑,而且坑和坑之间是串联的——前面一步没处理好,后面直接跑不起来。

这篇文章适合谁看?如果你手里正好有Hi3516CV610开发板,或者在做类似边缘AI视觉项目,需要把YOLO系列模型部署到国产SoC上并输出标准视频流,那这篇内容基本可以当操作手册用。如果你只是想了解边缘端模型部署的整体流程,也可以把它当作一个完整的案例来参考。我会把每一步的意图、参数选择理由、踩过的坑都写清楚,尽量让你少走弯路。

需要提前说明的是,Hi3516CV610的NPU工具链和通用GPU部署路线完全不同。你不能指望拿个ONNX丢进去就能跑,中间必须经过厂商提供的模型转换工具做量化、图优化、算子映射。这也是整个流程里最耗时、最容易出问题的环节。

2. 整体方案设计与技术选型思路

2.1 为什么选YOLOv8而不是YOLOv5或YOLOv7

YOLOv8相比前代最大的变化是anchor-free检测头和解耦头设计,在同等参数量下精度更高,而且Ultralytics的工程化做得非常好,训练、验证、导出全流程一条命令搞定。对于边缘部署来说,YOLOv8n(nano版本)的参数量约3.2M,输入640x640时计算量约8.7GFLOPs,经过INT8量化后模型体积可以压到3MB左右,Hi3516CV610的NPU完全吃得下。

另一个考虑是社区生态。YOLOv8的导出格式支持ONNX、TensorRT、OpenVINO等,虽然Hi3516CV610不直接支持这些,但ONNX作为中间格式是厂商工具链的标配输入。YOLOv5虽然也支持ONNX导出,但它的anchor-based检测头在量化时对anchor尺寸敏感,INT8量化后精度掉点比v8明显。实测下来,同样的数据集,YOLOv8n量化后mAP只掉1-2个点,YOLOv5n能掉3-5个点。

2.2 模型转换链路的整体设计

整个转换链路是这样的:PyTorch权重 → ONNX → 厂商工具链中间格式 → 板端可执行模型。听起来简单,但每一步都有细节。

PyTorch到ONNX这一步,核心是确定输入输出节点名称和动态轴设置。Hi3516CV610的工具链对动态shape支持有限,所以导出时要把batch固定为1,输入尺寸固定为模型实际推理尺寸。输出节点要明确指定,因为YOLOv8的检测头输出是三个不同尺度的特征图,工具链需要知道哪些节点是最终输出。

ONNX到厂商中间格式这一步,用的是芯片配套的模型转换工具(通常叫NNIE或类似名称的编译器)。这个工具会做算子融合、权重量化、内存分配优化。量化方式一般选INT8对称量化,需要提供校准数据集。校准集的选择很关键——不能随便拿几张图糊弄,要从训练集里均匀采样,覆盖各种场景。

2.3 RTSP推流方案的选择

板端推理完成后,视频流怎么出去?最直接的方式是用RTSP。Hi3516CV610的SDK自带视频编码单元(VPU),支持H.264/H.265硬件编码。推理结果(检测框)需要叠加到视频帧上,然后送进编码器,最后通过RTSP服务推流。

RTSP服务端有两种做法:一种是用SDK自带的RTSP服务模块,另一种是自己移植live555或者用轻量级RTSP服务器。SDK自带的方案集成度最高,但灵活性差,比如你想同时推多路流或者做鉴权就比较麻烦。自己移植live555工作量大,但可控性强。我最终选了SDK自带方案,因为项目只需要单路推流,没必要折腾。

推流地址格式一般是 rtsp://板子IP:554/stream ,后端用VLC或者ffmpeg拉流验证。这里有个细节:RTSP默认走UDP传输,但在网络不稳定的环境下容易丢包花屏,建议在拉流端强制TCP模式。

3. 环境搭建与模型训练导出实操

3.1 Ubuntu20.04下的YOLOv8环境配置

训练环境我用的是Ubuntu20.04 + Python3.8 + PyTorch1.13 + CUDA11.7。显卡是GTX1660Ti,6GB显存,跑YOLOv8n训练绰绰有余。如果你没有独立显卡,CPU版本也能跑通流程,只是训练速度慢很多,建议至少用Google Colab或者云GPU。

安装步骤不复杂,但有几个坑要注意。首先是PyTorch版本和CUDA版本的匹配,装错了后面训练会报各种奇怪的错误。其次是Ultralytics包的版本,不同版本导出的ONNX结构可能有差异,建议锁定一个稳定版本,比如8.0.x系列。

conda create -n yolov8 python=3.8
conda activate yolov8
pip install torch==1.13.1+cu117 torchvision==0.14.1+cu117 --extra-index-url https://download.pytorch.org/whl/cu117
pip install ultralytics==8.0.145
pip install onnx==1.14.0 onnxruntime==1.15.1

安装完成后用 yolo checks 命令验证环境,确认CUDA可用、版本匹配。

3.2 数据集准备与标注要点

数据集格式用YOLO标准的txt标注,每行格式是 class_id x_center y_center width height ,坐标都是归一化到0-1的值。标注工具推荐Labelme或者LabelImg,Labelme更适合做分割任务,纯检测用LabelImg就够了。

标注的时候有几个经验:第一,边界框不要贴得太紧,留1-2个像素的余量,因为量化后模型对边界敏感;第二,小目标要特别注意,如果目标在图像中占比小于1%,量化后很容易漏检,建议在训练时开启mosaic增强;第三,负样本(没有目标的背景图)要占一定比例,大概10%-20%,可以减少误检。

数据集目录结构按Ultralytics的要求组织:

dataset/
  images/
    train/
    val/
  labels/
    train/
    val/
  data.yaml

data.yaml里配置好路径、类别数和类别名称。

3.3 YOLOv8n训练与调参心得

训练命令很简单:

yolo detect train data=dataset/data.yaml model=yolov8n.pt epochs=200 imgsz=640 batch=16

但参数怎么调有讲究。epochs不是越多越好,YOLOv8自带早停机制,patience默认50,如果50轮验证集指标没提升就自动停。batch size根据显存来,6GB显存跑640尺寸batch=16刚好。学习率用默认的0.01配合余弦退火就行,不用瞎调。

训练过程中要盯着几个指标:box_loss和cls_loss是否稳定下降,mAP50和mAP50-95是否持续上升。如果loss震荡厉害,可能是学习率太大或者batch size太小。如果mAP卡住不涨,检查数据集标注质量,或者试试加数据增强。

训练完成后,最优权重保存在 runs/detect/train/weights/best.pt 。先用 yolo detect val 验证一下精度,确认没问题再导出。

3.4 导出ONNX的关键参数设置

导出ONNX这一步直接决定后面能不能转换成功。命令如下:

yolo export model=best.pt format=onnx imgsz=640 opset=11 simplify=True

opset选11,不要选太新的版本,厂商工具链对高版本opset支持不好。simplify=True会调用onnx-simplifier做图优化,去掉冗余算子。导出后可以用Netron打开看看结构,确认输入是 images ,输出是三个检测头。

有个细节:YOLOv8默认导出会带后处理(NMS),但厂商工具链通常不支持NMS算子,所以要在导出时去掉后处理,只保留原始检测头输出。具体做法是修改Ultralytics的导出代码,或者在导出后手动裁剪ONNX图。我选择的是后者,用onnx工具把后处理节点删掉,只保留到三个输出头。

4. 模型转换与板端部署核心环节

4.1 厂商工具链的安装与配置

Hi3516CV610的模型转换工具通常随SDK一起提供,安装过程比较繁琐,需要在Linux环境下配置一堆依赖。安装完成后,核心工具是一个命令行程序,输入ONNX,输出板端可加载的模型文件。

配置文件中需要指定几个关键参数:输入尺寸、量化方式、校准数据集路径、输出节点名称。输入尺寸要和ONNX一致,量化方式选INT8,校准数据集准备100-200张图就够了,从训练集里随机采样。

4.2 INT8量化校准的实操细节

量化校准是整个转换过程中最影响精度的环节。校准的原理是用一批真实数据跑一遍浮点模型,统计每层激活值的分布,然后确定量化缩放因子。校准集选得不好,量化后精度直接崩。

我的做法是从训练集里按类别均匀采样,每个类别至少20张,总共200张左右。采样时要注意覆盖不同光照、不同角度、不同尺度的目标。如果某个类别样本特别少,可以适当过采样。

校准过程中工具会输出每层的量化误差,重点关注误差大的层。如果某些层误差超过阈值,可以尝试把这些层设为浮点计算(混合量化),牺牲一点速度换精度。

4.3 板端推理程序的集成

板端推理程序基于SDK提供的sample代码修改。核心流程是:初始化NPU → 加载模型 → 读取视频帧 → 预处理 → 推理 → 后处理 → 绘制检测框 → 送编码器。

预处理包括resize、归一化、颜色空间转换(BGR到RGB)。Hi3516CV610的NPU输入要求是NHWC格式,而ONNX通常是NCHW,这个转换在模型转换时已经处理好了,板端直接送NHWC数据就行。

后处理主要是解析三个检测头的输出,做sigmoid激活、解码边界框、NMS过滤。NMS在CPU上做,虽然慢一点但精度有保障。实测YOLOv8n在Hi3516CV610上单帧推理耗时约30-40ms,加上前后处理总共50ms左右,勉强能跑到15-20FPS。

4.4 RTSP推流的配置与验证

RTSP推流基于SDK的venc和rtsp模块。配置流程是:创建venc通道 → 配置编码参数(H.264、CBR、码率2Mbps、GOP30) → 创建RTSP会话 → 绑定venc通道 → 启动服务。

编码参数里GOP设置很关键,GOP太大导致拉流端首帧等待时间长,GOP太小影响编码效率。30是一个比较平衡的值。码率根据分辨率和帧率来,1080p@25fps用2Mbps基本够用,再低会糊。

推流地址格式是 rtsp://192.168.1.100:554/live/0 ,用VLC拉流验证。如果花屏,检查网络带宽和MTU设置;如果延迟大,检查编码器是否开启了B帧,B帧会增加编码延迟,实时场景建议关掉。

5. 常见问题排查与避坑经验

5.1 模型转换失败的高频原因

转换失败最常见的原因是算子不支持。YOLOv8里有些算子厂商工具链不认,比如SiLU激活函数、某些形式的Resize。解决办法是在导出ONNX前把SiLU换成ReLU,或者用工具链支持的算子替换。

另一个原因是输入输出节点名称不匹配。工具链配置文件里写的节点名必须和ONNX里的完全一致,大小写都不能错。用Netron打开ONNX确认节点名。

5.2 量化后精度掉点严重怎么办

精度掉点超过5个点就要排查了。首先检查校准集是否覆盖了所有场景,其次看量化误差大的层能不能改成混合量化。如果还不行,试试用QAT(量化感知训练)重新训练模型,在训练时模拟量化误差,让模型适应量化。

5.3 板端推理报错与内存问题

板端推理报错最常见的是内存不足。Hi3516CV610的内存有限,模型加载、输入输出buffer、中间层内存都要提前分配好。如果报内存分配失败,检查MMZ(媒体内存区)配置是否够大,必要时调整内存布局。

5.4 RTSP拉流不稳定排查

拉流不稳定表现为花屏、卡顿、断流。先确认网络带宽是否足够,2Mbps的流至少要有4Mbps的稳定带宽。然后检查RTSP传输模式,UDP改TCP。如果还不行,降低码率或者分辨率试试。

问题现象 可能原因 排查方法 解决方案
转换报算子不支持 SiLU/Resize等算子 查看工具链日志 替换算子或混合量化
量化后mAP掉点大 校准集不具代表性 分析每层量化误差 扩充校准集或QAT
板端推理内存不足 MMZ配置过小 查看内存分配日志 调整MMZ大小
RTSP花屏 UDP丢包 改TCP拉流 强制TCP模式
推理帧率低 后处理耗时 分段计时 优化NMS或降分辨率

6. 性能优化与后续扩展方向

6.1 推理速度优化的几个手段

如果帧率不够,可以从几个方向优化。第一,降低输入分辨率,从640降到416,推理耗时能减少40%左右,精度掉2-3个点。第二,把NMS放到NPU上做,但需要工具链支持。第三,多线程流水线,一帧推理的同时另一帧做预处理,重叠耗时。

6.2 多路RTSP推流的扩展

单路推流跑通后,如果要推多路,需要创建多个venc通道和RTSP会话。Hi3516CV610的编码能力有限,1080p最多同时编2-3路,再多就要降分辨率。多路场景下NPU推理也要分时复用,整体帧率会下降。

6.3 模型更新与OTA升级思路

实际部署后模型可能需要更新。最简单的做法是把模型文件放在可写分区,通过RTSP或者HTTP接口上传新模型,重启推理程序加载。复杂一点可以做A/B分区,新模型验证通过后再切换。

我在实际项目里踩的最大的坑是校准集选择。第一次随便拿了50张图做校准,量化后mAP掉了8个点,后来老老实实按类别均匀采样200张,掉点控制在2个点以内。这个环节真的不能偷懒,校准集的质量直接决定量化模型能不能用。另外板端内存配置也要留足余量,我一开始按理论值分配,跑起来就OOM,后来加了20%余量才稳定。

Logo

火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。

更多推荐