3. 模型训练与导出:从标注到TensorRT的完整链路
这一章,我们正式进入YOLO部署的核心环节——模型训练与导出。说白了,就是把你手里的原始图片,变成能在嵌入式设备上跑起来的推理引擎。我做了这么多年嵌入式AI,见过太多人在这一步翻车:训练时精度很高,一导出就崩;或者导出的模型在PC上跑得好好的,上板就报错。嗯,这里面的坑,我一个个给你拆开讲。
3.1 自定义数据集标注——别在第一步偷懒
数据集的质量,直接决定模型的天花板。我刚开始做项目时,总觉得标注差不多就行,结果模型训练出来,检测框总是歪歪扭扭。后来花了三倍时间重新标注,才把精度拉回来。所以,标注这件事,值得你认真对待。
3.1.1 标注工具选择
我个人习惯用LabelImg,开源、轻量、支持YOLO格式直接导出。当然,LabelStudio、CVAT这些也都不错。选哪个不重要,关键是格式要对。
| 工具 | 输出格式 | 适用场景 |
|---|---|---|
| LabelImg | YOLO .txt / Pascal VOC .xml | 小团队、快速标注 |
| LabelStudio | JSON / COCO / YOLO | 多人协作、复杂标注 |
| CVAT | 多种格式 | 大规模标注、自动标注辅助 |
3.1.2 YOLO标注格式详解
YOLO的标注格式很简单:每张图片对应一个同名的.txt文件,每行代表一个目标。格式是:
<class_id> <x_center> <y_center> <width> <height>
注意,这里的坐标都是归一化的,范围0~1。x_center和y_center是目标框中心点相对于图片宽高的比例,width和height是框的宽高相对于图片宽高的比例。
3.1.3 数据集划分
标注完成后,把数据集分成三份:训练集、验证集、测试集。我一般按8:1:1的比例划分。注意,测试集要完全独立,不能参与任何训练决策。
# 简单的划分脚本
import os, random, shutil
images = os.listdir('images/')
random.shuffle(images)
train = images[:int(0.8*len(images))]
val = images[int(0.8*len(images)):int(0.9*len(images))]
test = images[int(0.9*len(images)):]
3.2 YOLOv8训练流程——从配置文件到模型权重
YOLOv8的训练流程,比之前的版本简化了不少。你只需要准备好数据集和配置文件,一行命令就能跑起来。但简化不等于无脑,里面的参数调优还是很有讲究的。
3.2.1 准备数据集配置文件
创建一个data.yaml文件,告诉YOLOv8你的数据在哪:
train: /path/to/train/images
val: /path/to/val/images
test: /path/to/test/images
nc: 3 # 类别数量
names: ['person', 'car', 'bicycle'] # 类别名称
3.2.2 选择预训练模型
YOLOv8提供了多种规模的预训练模型:nano、small、medium、large、xlarge。对于嵌入式部署,我建议从nano或small开始。nano模型参数量最小,适合资源受限的设备;small模型在精度和速度之间取得了不错的平衡。
| 模型 | 参数量 | mAP50-95 | 推理速度(FP16) |
|---|---|---|---|
| YOLOv8n | 3.2M | 37.3% | ~1.5ms |
| YOLOv8s | 11.2M | 44.9% | ~2.5ms |
| YOLOv8m | 25.9M | 50.2% | ~4.5ms |
3.2.3 开始训练
一行命令启动训练:
yolo train model=yolov8n.pt data=data.yaml epochs=100 imgsz=640 batch=16
这里有几个关键参数:
- epochs:训练轮数。我一般设100~300轮,看验证集loss不再下降就停。
- imgsz:输入图片尺寸。嵌入式设备建议用640或320,太大影响速度。
- batch:批次大小。根据显存调整,能大尽量大。
3.3 模型量化——FP16和INT8
模型量化,说白了就是把模型参数的精度降低,换来更小的体积和更快的推理速度。嵌入式设备上,这一步几乎是必须的。
3.3.1 FP16量化
FP16量化是最简单的,几乎无损。把模型权重从FP32转成FP16,体积减半,速度提升明显。YOLOv8训练完成后,可以直接导出FP16模型:
yolo export model=best.pt format=onnx half=True
我在Jetson Nano上测试过,FP16比FP32快了将近一倍,精度只掉了不到0.5%。
3.3.2 INT8量化
INT8量化更激进,精度损失也更大。它需要校准数据集来统计激活值的分布。YOLOv8的INT8量化流程:
yolo export model=best.pt format=onnx int8=True data=data.yaml
注意,INT8量化需要你提供校准数据,一般从训练集里取几百张就够了。
3.4 导出为ONNX/TensorRT格式
训练好的模型,最终要导出成部署格式。ONNX是中间格式,TensorRT是NVIDIA平台上的优化引擎。
3.4.1 导出ONNX
ONNX是跨平台的模型交换格式。YOLOv8导出ONNX很简单:
yolo export model=best.pt format=onnx
导出的ONNX模型可以用Netron可视化查看结构。我建议你养成这个习惯,检查一下输入输出节点是否正确。
3.4.2 导出TensorRT
TensorRT是NVIDIA的推理优化引擎,能在Jetson系列设备上发挥极致性能。导出TensorRT引擎有两种方式:
- 直接导出:YOLOv8支持直接导出TensorRT:
yolo export model=best.pt format=engine - 通过ONNX转:先用ONNX导出,再用trtexec工具转换:
trtexec --onnx=best.onnx --saveEngine=best.engine --fp16
我个人更推荐第二种方式,可控性更强,可以指定动态batch、精度模式等参数。
3.5 本章知识体系
下面这张图,把整个流程串起来了:
3.6 常见问题与避坑指南
最后,分享几个我实际项目中遇到的坑,希望能帮你少走弯路:
- 标注格式错误:标注文件里的坐标必须是归一化的,而且类别ID要从0开始。我曾经用1开始,结果模型把背景当成了第0类,检测结果全乱套。
- 训练时显存溢出:减小batch size或图片尺寸。如果还不行,试试梯度累积。
- 量化后精度骤降:检查校准数据集是否具有代表性。另外,INT8量化对某些层特别敏感,可以尝试逐层量化或混合精度量化。
- TensorRT导出失败:确保ONNX模型结构正确,有些算子TensorRT不支持,需要手动替换。