1. 为什么需要续训YOLOv8模型
训练深度学习模型是个漫长的过程,尤其是像YOLOv8这样的目标检测模型。我遇到过太多次训练到一半突然中断的情况——可能是服务器掉电、GPU内存不足,或者是训练程序意外崩溃。每次看到训练到一半的模型被迫终止,都让人特别抓狂。
更糟的是,有些数据集需要训练很长时间才能收敛。比如我去年处理的一个工业缺陷检测项目,完整训练需要300个epoch,每次训练都要3天时间。如果因为意外中断就得从头开始训练,不仅浪费时间,还可能错过重要的项目节点。
续训功能就是为解决这个问题而生的。它能让我们从上次中断的地方继续训练,而不是从头开始。但很多人不知道的是,简单的续训操作背后藏着不少坑。比如续训后学习率调度器状态不对、优化器动量参数重置、早停机制误判等问题,都可能导致续训后的模型性能不如连续训练的效果。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 准备工作:理解YOLOv8的检查点机制
2.1 检查点文件都保存了什么
YOLOv8在训练过程中会自动保存检查点文件,通常存放在runs/detect/train/weights目录下。这些.pt文件不只是保存了模型权重,还包含了训练状态的全套信息:
- 模型参数(当然是主要的)
- 优化器状态(包括动量缓存等)
- 当前epoch数
- 最佳评估指标值
- 学习率调度器状态
- 早停计数器状态
理解这点很重要,因为完整的续训需要恢复所有这些状态,而不仅仅是加载模型权重。我曾经犯过只恢复模型权重的错误,结果续训后模型性能大幅下降。
2.2 检查点的保存频率
默认情况下,YOLOv8会:
- 每个epoch保存一次last.pt(最后一个检查点)
- 当验证指标提升时保存best.pt(最佳模型)
- 可以通过save_period参数控制中间检查点的保存频率
建议在开始长时间训练前,先确认你的保存设置。我有次设置了很大的save_period,结果在训练中断时发现最近的检查点已经是20个epoch前的了,不得不浪费很多计算资源。
3. 基础续训方法:使用resume参数
3.1 最简单的续训方式
最直接的续训方法就是设置resume=True参数:
python复制from ultralytics import YOLO
model = YOLO('runs/detect/train/weights/last.pt')
results = model.train(resume=True)
这个方法会自动:
- 从last.pt加载模型权重
- 恢复优化器和学习率调度器状态
- 从上次的epoch继续计数
但要注意,这种方法会沿用原来的epoch总数。比如你原本设置训练100个epoch,已经训练了60个,那么续训后会继续训练剩余的40个epoch。
3.2 调整总epoch数
如果想在续训时增加总训练轮次,需要修改两处:
python复制model = YOLO('runs/detect/train/weights/last.pt')
results = model.train(resume=True, epochs=150) # 假设想训练到150个epoch
但这里有个坑:仅仅这样设置可能不够,因为YOLOv8内部会从检查点读取已完成的epoch数。更可靠的做法是直接修改检查点文件中的epoch计数(后面会详细介绍)。
4. 高级续训技巧:手动修改检查点
4.1 直接修改训练脚本
有时候基础方法不够用,特别是当你想:
- 跳过一些已经训练过的epoch
- 调整学习率调度
- 修改早停参数
这时可以手动修改YOLOv8的源代码(记得备份原文件!):
- 找到ultralytics/engine/trainer.py文件
- 修改check_resume方法:
python复制def check_resume(self):
# 原代码:resume = self.args.resume
resume = 'runs/detect/train/weights/last.pt' # 硬编码检查点路径
return resume
- 修改resume_training方法:
python复制def resume_training(self, ckpt):
ckpt = torch.load('runs/detect/train/weights/last.pt') # 手动加载检查点
start_epoch = 100 # 假设要从第100个epoch开始
# ...其余代码保持不变
4.2 调整早停机制
YOLOv8默认使用早停机制(patience),如果验证指标长时间不提升就会提前终止训练。续训时可能需要调整这个参数:
python复制# 在ultralytics/engine/trainer.py中找到_setup_train方法
self.stopper, self.stop = EarlyStopping(patience=300), False # 增大patience值
我有次续训后模型很快停止,就是因为没注意到早停计数器是从检查点恢复的,patience值已经所剩无几。
5. 验证续训效果
5.1 监控训练曲线
续训后要特别注意观察训练曲线是否连贯:
- 损失函数应该平稳过渡,没有突然跳跃
- 学习率曲线应该连续
- 验证指标变化趋势应该与中断前一致
如果发现异常,比如损失突然上升,可能是状态恢复不正确。这时最好回退到上一个检查点重新续训。
5.2 对比完整训练
为了确保续训没有影响模型性能,可以:
- 保留一份完整训练的模型
- 用相同数据训练两份模型:一份连续训练,一份中间中断后续训
- 比较最终模型在测试集上的表现
在我的测试中,正确配置的续训模型性能差异通常在1%以内。如果差距过大,说明续训过程可能有问题。
6. 常见问题与解决方案
6.1 续训后损失异常
可能原因:
- 优化器状态没有正确恢复
- 学习率调度器重置
- 梯度累积步数不一致
解决方案:
- 检查检查点是否包含优化器状态
- 确保resume=True参数正确传递
- 监控前几个batch的损失变化
6.2 epoch计数错误
有时续训后epoch计数不从正确位置开始。可以:
- 手动修改检查点中的epoch值
- 或者在train()方法中强制设置start_epoch参数
python复制# 修改ultralytics/engine/trainer.py
start_epoch = 100 # 明确指定起始epoch
6.3 内存不足问题
续训时如果修改了batch size可能导致OOM。建议:
- 使用与之前训练相同的batch size
- 或者在修改batch size后从更早的检查点开始续训
7. 最佳实践建议
根据我多次续训YOLOv8模型的经验,总结出以下建议:
-
定期保存检查点:不要依赖默认的保存频率,对于长时间训练,设置save_period=5或更低。
-
记录训练配置:每次训练都要保存完整的配置参数,包括:
- 初始学习率
- 优化器类型
- 数据增强设置
- Batch size
-
验证续训效果:续训完成后,在验证集上立即测试性能,与中断前的指标对比。
-
代码版本控制:训练脚本和YOLOv8版本的变更可能导致续训失败。我吃过这个亏,现在每次训练都会记录代码库的git commit hash。
-
保留完整日志:训练日志是诊断续训问题的关键。建议保存控制台输出到文件,并记录中断时的具体情况。
