4. YOLOv8模型训练
好,咱们进入第四章。这一章是实战的硬核部分——把YOLOv8跑起来,并且跑出好效果。
说实话,很多同学在训练阶段容易翻车。要么是参数没调对,模型训飞了;要么是数据不够,过拟合严重。我刚开始做工业质检项目时也踩过不少坑,今天把这些经验都摊开来讲。
4.1 配置文件解析——别小看这个YAML
YOLOv8的训练配置都写在YAML文件里。很多人直接复制粘贴,改个路径就开训。嗯,这样容易出问题。
我们来看一个典型的配置文件结构:
# ultralytics/cfg/models/v8/yolov8n.yaml
# 模型骨架部分
backbone:
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 3, C2f, [128, True]]
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 6, C2f, [256, True]]
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 6, C2f, [512, True]]
- [-1, 1, Conv, [768, 3, 2]] # 7-P5/32
- [-1, 3, C2f, [768, True]]
- [-1, 1, SPPF, [768, 5]] # 9
# 颈部(Neck)部分
head:
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 3, C2f, [512]] # 12
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
- [-1, 3, C2f, [256]] # 15 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 12], 1, Concat, [1]] # cat head P4
- [-1, 3, C2f, [512]] # 18 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]]
- [[-1, 9], 1, Concat, [1]] # cat head P5
- [-1, 3, C2f, [768]] # 21 (P5/32-large)
- [[15, 18, 21], 1, Detect, [nc]] # Detect(P3, P4, P5)
这里每个数字代表什么?我解释一下:
- 第一个数字:输入来源。-1表示上一层,正数表示第几层
- 第二个数字:重复次数。比如C2f模块重复3次
- 第三个参数:模块类型。Conv、C2f、SPPF这些
- 第四个参数:模块参数。比如[64, 3, 2]表示输出通道64、卷积核3、步长2
我的习惯: 工业场景下,我一般不改backbone结构,只调head部分的检测头数量。比如检测小目标时,我会在head里加一个P2层(160x160的特征图),专门抓小缺陷。
4.2 训练参数调优——别让模型训飞了
训练参数这块,我见过最离谱的是有人把学习率设成0.1,loss直接炸到NaN。咱们一步步来。
核心参数就这几个:
| 参数名 | 默认值 | 工业场景建议 | 说明 |
|---|---|---|---|
| lr0 | 0.01 | 0.001 ~ 0.005 | 初始学习率。数据量小就调低 |
| lrf | 0.01 | 0.01 ~ 0.1 | 最终学习率 = lr0 * lrf |
| momentum | 0.937 | 0.9 ~ 0.95 | SGD动量,一般不动 |
| weight_decay | 0.0005 | 0.0001 ~ 0.0005 | 权重衰减,防过拟合 |
| batch | 16 | 看显存,越大越好 | batch size,影响BN层效果 |
| epochs | 100 | 200 ~ 500 | 工业场景数据少,多训几轮 |
| patience | 50 | 30 ~ 50 | 早停轮数,loss不降就停 |
实际训练命令长这样:
yolo train \
model=yolov8n.pt \
data=custom_dataset.yaml \
epochs=300 \
batch=32 \
lr0=0.002 \
lrf=0.05 \
weight_decay=0.0003 \
patience=40 \
imgsz=640 \
device=0,1,2,3 \
workers=8 \
project=industrial_qc \
name=defect_detection_v1
我曾经踩过的坑: 有一次我把batch设成64,但显存只有8G,结果训练到一半OOM了。后来我学乖了——先用batch=8试跑一个epoch,看显存占用,再逐步往上加。另外,workers数别超过CPU核心数,否则数据加载会成为瓶颈。
4.3 迁移学习技巧——站在巨人肩膀上
迁移学习是工业质检的救命稻草。你想想看,工厂里能收集到的缺陷样本可能就几百张,从头训练一个YOLOv8?不现实。
我的做法是这样的:
- 选对预训练权重:YOLOv8官方提供了COCO预训练权重。但如果你做的是特定工业场景,比如PCB缺陷检测,我建议先用类似场景的公开数据集做一次预训练
- 冻结backbone:前50个epoch冻结backbone,只训练head。这样模型不会忘记通用的特征提取能力
- 解冻微调:50个epoch后解冻全部层,用更小的学习率(lr0=0.0001)微调
- 数据增强策略:工业场景下,mosaic和mixup很有用。但注意——如果你的缺陷样本很少,mosaic可能会把缺陷切碎,反而不好
冻结训练的代码实现:
from ultralytics import YOLO
# 加载预训练模型
model = YOLO('yolov8n.pt')
# 冻结backbone
for name, param in model.model.named_parameters():
if 'backbone' in name:
param.requires_grad = False
# 第一阶段:只训练head
model.train(
data='custom_dataset.yaml',
epochs=50,
lr0=0.001,
freeze=10 # 冻结前10层
)
# 第二阶段:解冻全部,小学习率微调
for param in model.model.parameters():
param.requires_grad = True
model.train(
data='custom_dataset.yaml',
epochs=100,
lr0=0.0001,
resume=True
)
关键经验: 工业场景下,我建议用yolov8m或yolov8l作为基础模型。虽然nano版本快,但小缺陷的召回率不够。我做过对比——在同一个PCB缺陷数据集上,yolov8n的mAP@0.5是0.82,yolov8m能到0.91。推理速度慢了30%,但精度提升明显。
4.4 训练过程监控——别等训完才发现翻车
训练跑起来之后,你不能撒手不管。我习惯用TensorBoard实时监控,YOLOv8原生支持。
启动监控:
# 训练时自动生成日志
yolo train ... project=my_project name=exp1
# 另开终端,启动TensorBoard
tensorboard --logdir my_project/exp1
监控哪些指标?我列个清单:
- train/loss:训练loss。正常应该稳步下降,如果震荡剧烈,说明学习率太高
- val/loss:验证loss。如果验证loss先降后升,那就是过拟合了,赶紧加正则化或早停
- metrics/mAP50:这个最重要。工业场景下,mAP50达到0.9以上才算合格
- learning_rate:看看学习率变化曲线,确认是不是按余弦退火在衰减
- 混淆矩阵:每个epoch结束后看一下,哪个类别容易漏检
下面这张图是我在实际项目中总结的训练监控流程:
实际训练时,我还会关注一个容易被忽略的指标——类别分布。工业场景下,正负样本往往极度不平衡。比如一个产品上99.9%的区域都是OK的,只有0.1%是缺陷。这时候看mAP会骗人——模型可能学成了「全部判OK」。
我的做法: 每10个epoch手动跑一次验证集,打印出每个类别的precision和recall。如果某个缺陷类别的recall低于0.5,我就回去检查标注质量,或者给这个类别加权重。YOLOv8支持在数据集的YAML里设置cls_pw参数,给不同类别不同的loss权重。
嗯,训练监控这块就说这么多。记住一句话:不要等训练结束才看结果。中间发现问题,及时止损,重新调参,比跑完一轮再回头省时间得多。