2. YOLOv8模型训练与权重获取:用Ultralytics官方库训出自定义数据集
好,模型选型搞定了,接下来就是真刀真枪地训练。这一章我会带你走一遍完整的流程:从准备自定义数据集、跑训练命令,到拿到那个关键的 best.pt 文件。顺便,我也会拆开模型配置文件给你看看里面到底写了啥。
我个人习惯把训练前的准备工作叫做“三件套”:数据、配置、代码。这三样齐了,训练就是一键的事。
best.pt 权重文件 + 对模型配置文件的清晰理解。
2.1 自定义数据集准备:别让数据拖后腿
我在项目里见过太多人,模型结构选得挺好,训练参数调了半天,最后发现是数据集格式不对——白忙活。YOLOv8 用的是标准的 COCO 格式,但做了简化。你需要准备成这样:
dataset/
├── images/
│ ├── train/ # 训练图片
│ └── val/ # 验证图片
├── labels/
│ ├── train/ # 训练标签(.txt文件)
│ └── val/ # 验证标签
└── data.yaml # 数据集配置文件
每个 .txt 标签文件的格式是:
<class_id> <x_center> <y_center> <width> <height>
注意,坐标都是归一化到 [0, 1] 的。我刚开始做标注时,有次忘了归一化,模型直接训飞了——损失降不下去,检测框全跑出画面。嗯,这个坑我替你们踩过了。
data.yaml 长这样:
train: ./images/train
val: ./images/val
nc: 3
names: ['person', 'car', 'bicycle']
| 字段 | 说明 | 常见错误 |
|---|---|---|
train |
训练图片路径 | 用了路径,换机器就炸 |
val |
验证图片路径 | 路径写错导致验证集为空 |
nc |
类别数量 | 跟标签文件里的 class_id 对不上 |
names |
类别名称列表 | 顺序必须跟 class_id 一致 |
2.2 训练命令:一行代码搞定
Ultralytics 官方库把训练封装得极其简单。你只需要一行命令:
yolo train model=yolov8n.pt data=coco128.yaml epochs=100 imgsz=640
参数说明:
- model:预训练权重路径。用
yolov8n.pt表示从 Nano 版本开始微调。 - data:你的
data.yaml路径。 - epochs:训练轮数。我一般先跑 50 轮看看损失曲线,再决定要不要加。
- imgsz:输入图片尺寸。640 是默认值,显存够的话可以试试 1280。
训练过程中,你会看到终端里实时打印损失值和 mAP。我个人习惯盯着 box_loss 和 cls_loss 看——如果这两个值在最后 10 轮还在明显下降,说明还没收敛,可以加轮数。
device=0 指定 GPU,用 workers=8 加速数据加载。我遇到过 workers 设太大导致内存爆掉的情况,建议根据你的 CPU 核心数来设,一般 4 或 8 就够。
2.3 导出最佳权重:best.pt 在哪?
训练结束后,Ultralytics 会自动在 runs/detect/train/weights/ 目录下生成两个文件:
- best.pt:验证集上 mAP 最高的权重。这是我们部署时用的。
- last.pt:最后一轮的权重。如果训练中途断了,可以用它恢复。
为什么用 best.pt 而不是 last.pt?你想想看,模型可能在中间某个 epoch 就达到了最佳性能,继续训练反而可能过拟合。我有个项目就是用了 last.pt,结果部署后检测精度比预期低了 3 个点——换成 best.pt 立马好了。
拿到 best.pt 后,你可以快速验证一下:
yolo predict model=best.pt source=test.jpg
看到检测框正常,就可以放心进入下一阶段了。
2.4 模型配置文件结构:拆开看看里面
YOLOv8 的模型结构定义在 ultralytics/cfg/models/v8/ 目录下。拿 yolov8n.yaml 举例:
# Ultralytics YOLOv8n
nc: 80
scales:
n: [0.33, 0.25, 1024] # depth, width, max_channels
backbone:
- [-1, 1, Conv, [64, 3, 2]]
- [-1, 1, Conv, [128, 3, 2]]
- [-1, 3, C2f, [128, True]]
- [-1, 1, Conv, [256, 3, 2]]
- [-1, 6, C2f, [256, True]]
- [-1, 1, Conv, [512, 3, 2]]
- [-1, 6, C2f, [512, True]]
- [-1, 1, Conv, [768, 3, 2]]
- [-1, 3, C2f, [768, True]]
- [-1, 1, SPPF, [768, 5]]
head:
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 6], 1, Concat, [1]]
- [-1, 3, C2f, [512]]
...
关键点解读:
- scales:控制模型深度和宽度。n/s/m/l/x 版本就是靠这个缩放的。
- backbone:特征提取网络。每一行是一个模块,格式是
[输入层, 重复次数, 模块类型, 参数]。 - head:检测头。负责把特征图转换成最终的检测结果。
举个例子,[-1, 3, C2f, [128, True]] 的意思是:从上一层取输入,重复 3 次 C2f 模块,输出通道 128,使用 shortcut 连接。
2.5 本章知识结构图
下面这张图把整个流程串起来了,你可以对照着看:
2.6 避坑总结
最后,我把训练过程中容易踩的坑列一下,都是我用真金白银换来的经验:
| 问题 | 现象 | 解决方案 |
|---|---|---|
| 标签 class_id 越界 | 训练报错或 loss 为 NaN | 检查标签文件,确保 class_id < nc |
| 图片路径错误 | 训练时提示找不到图片 | 用相对路径,或检查 data.yaml 路径 |
| 显存不足 | 训练中断,报 CUDA OOM | 减小 batch size 或 imgsz |
| 过拟合 | 训练损失低,验证损失高 | 增加数据增强或早停 |
| 用了 last.pt 部署 | 精度比预期低 | 换成 best.pt 重新验证 |
嗯,这一章的内容就到这。拿到 best.pt 之后,你就可以准备进入下一阶段——模型导出了。到时候我会教你如何把这个 PyTorch 权重转成 OpenCV 能直接用的格式。