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 一致
我曾经踩过的坑: 标签文件里 class_id 从 0 开始,但 names 列表里我写成了 ['person', 'car'],结果训练时类别索引全乱了。检查数据时一定要跑一遍验证脚本,别偷懒。

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 连接。

为什么理解这个有用? 如果你想修改模型结构——比如加一个检测头、换一种激活函数——就得改这个 yaml 文件。我做过一个项目,需要检测极小目标,就是在 backbone 里多加了一层下采样,然后调整 head 的输入层索引。

2.5 本章知识结构图

下面这张图把整个流程串起来了,你可以对照着看:

YOLOv8 训练与权重获取流程 1. 数据准备 images + labels + data.yaml 2. 训练配置 model + data + epochs + imgsz 3. 执行训练 yolo train ... 训练过程:损失下降 + mAP 上升 监控 box_loss / cls_loss / mAP50 4. 权重输出 best.pt(最佳) / last.pt(最后) 5. 快速验证 yolo predict model=best.pt source=test.jpg 💡 核心产出:best.pt 权重文件 + 模型配置文件理解 后续导出和部署都基于这个 best.pt

2.6 避坑总结

最后,我把训练过程中容易踩的坑列一下,都是我用真金白银换来的经验:

问题 现象 解决方案
标签 class_id 越界 训练报错或 loss 为 NaN 检查标签文件,确保 class_id < nc
图片路径错误 训练时提示找不到图片 用相对路径,或检查 data.yaml 路径
显存不足 训练中断,报 CUDA OOM 减小 batch size 或 imgsz
过拟合 训练损失低,验证损失高 增加数据增强或早停
用了 last.pt 部署 精度比预期低 换成 best.pt 重新验证

嗯,这一章的内容就到这。拿到 best.pt 之后,你就可以准备进入下一阶段——模型导出了。到时候我会教你如何把这个 PyTorch 权重转成 OpenCV 能直接用的格式。