【yolo】YOLO 训练的两个隐藏坑:类别顺序影响收敛 + cache 文件不刷新
【yolo】YOLO 训练的两个隐藏坑:类别顺序影响收敛 + cache 文件不刷新
作者: code bean
关键词: YOLO, 目标检测, data.yaml, 类别顺序, train.cache, val.cache
在最近的 YOLO 训练实验中,我踩了两个隐藏的坑,影响了训练效果和实验结论:
- 修改类别顺序后,训练收敛速度和最终性能居然有差异
- 修改了类别顺序却发现训练结果完全没变,最后才发现是 cache 文件惹的祸
这篇文章把两个问题梳理总结,希望能帮到同样遇到困惑的朋友。
一、类别顺序真的会影响训练结果吗?
我们知道,在 YOLO 的 data.yaml
中定义了类别顺序,例如:
names:0: baidian1: diaose2: heidian3: zangwu
如果我把顺序改成:
names:0: heidian1: zangwu2: baidian3: diaose
并同步修改所有标签文件中的 class_id
,从理论上讲,训练的目标函数完全等价,最终应该学到同样的模型。
但是实验发现:
- Loss 曲线下降速度不同
- mAP 有明显差异
- 早停触发的时间也变了
原因分析
这其实是 YOLO 网络结构 + 梯度传播的一个自然结果:
- 分类头输出是
[cls_0, cls_1, ..., cls_n]
,类别顺序决定了通道语义 - 改变类别顺序,相当于改变了梯度首先强化的通道
- 早期训练中,BatchNorm 和卷积层的统计量被低 ID 类别优先更新
- 如果类别不平衡或设置了早停,低 ID 类别可能先学会,高 ID 类别还没充分学习就被早停
换句话说:
YOLO 确实可能“先学会 ID 小的类别”,导致收敛路径发生变化,从而影响最终结果。
建议做法
-
固定随机数种子:保证可复现性
yolo detect train data=data.yaml seed=42
-
多次训练取平均:减少偶然因素影响
-
延长训练轮数或禁用早停:让所有类别都有充分学习机会
-
类别不平衡时使用 class weights,保证梯度信号均衡
二、修改了标注文件训练结果没变?注意 cache 文件!
有几次把类别顺序后回复后,惊讶地发现:训练结果几乎完全一致,甚至 loss 曲线几乎一模一样。刚刚还发现改了顺序有用,这次怎么没有用了???
后来才发现是 YOLO 的缓存机制 导致的。
YOLO 的 cache 文件是什么
-
train.cache
和val.cache
是 YOLO 自动生成的缓存文件 -
存放在数据集路径下,保存了:
- 图片路径、尺寸
- 标签信息(class_id + bbox)
- 图片哈希值
- 损坏图片标记
-
作用是加快训练启动速度、自动跳过坏图
为什么会踩坑
YOLO 判断缓存是否失效主要依赖图片哈希和标签文件时间戳。
如果我只是改了 data.yaml
的 names
顺序,没有动标签文件的时间戳,YOLO 就会认为缓存依然有效,继续使用旧的标签数据。
结果就是:
- YOLO 根本没有重新读取标签文件
- 我修改的类别顺序没有生效
- 训练结果完全没有变化
解决方法
手动删除 train.cache
和 val.cache
,重新训练即可:
# Windows
del train.cache
del val.cache
或者保留默认参数 cache=True
,让 YOLO 重新生成缓存文件。
不要用 cache=False
,那会禁用缓存,每次训练都要重新扫描,降低启动速度。
三、最佳实践
-
修改数据集后(改图片、标签、类别顺序),第一步:手动删除
train.cache
和val.cache
-
科学对比实验时,务必:
- 固定随机种子
- 清理 cache
- 记录多次训练结果取平均
-
观察收敛行为,建议绘制每个类别的 mAP 曲线,直观看不同类别的学习速度
结论
- 类别顺序会影响 YOLO 的收敛路径,特别是数据不平衡时,可能让低 ID 类别先被学会,从而改变最终性能。
- 如果修改了类别顺序但训练结果没变,首先检查
train.cache
和val.cache
是否被重建,否则 YOLO 可能仍然使用旧的标签数据,导致实验无效。
✅ 通过这次实验,我不仅理解了类别顺序对训练的潜在影响,也学会了在修改数据集后要注意 cache 文件。以后做实验会更谨慎,保证结果真正反映我修改的内容。