三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

019、训练基础概念:Epoch Batch LearningRate Warmup EMA 的直观理解

019、训练基础概念:Epoch Batch LearningRate Warmup EMA 的直观理解

019、训练基础概念:Epoch Batch LearningRate Warmup EMA 的直观理解

上周帮同事调一个YOLOv8的模型,他跑了一百个epoch,loss曲线看着挺漂亮,结果mAP只有0.3。我一看训练日志,learning rate从0.01直接干到0.001,warmup阶段压根没起作用,EMA权重也没保存。这种坑我踩过不止一次,今天把这些基础概念掰开揉碎了讲清楚。

Epoch:不是跑完就完事

Epoch就是整个训练集完整过一遍模型。很多人以为epoch越多越好,这是典型的误区。我见过有人把YOLOv5跑300个epoch,结果最后50个epoch的验证集mAP反而下降了——过拟合了。

实际调试中,我习惯先跑50个epoch看趋势。如果loss还在明显下降,继续加;如果loss震荡或者验证集指标停滞,就该停了。YOLOv8默认300个epoch,但你的数据集如果只有几百张图片,100个epoch可能就足够了。

踩坑记录:有一次我训练一个行人检测模型,前50个epoch mAP从0.1涨到0.35,50到80个epoch涨到0.38,80之后基本不动了。这时候继续跑就是浪费算力。所以别迷信固定epoch数,用early stopping更靠谱。

Batch Size:显存和收敛的博弈

Batch size决定了每次更新参数时看多少张图片。YOLO系列默认batch size是16,但很多人直接照搬,结果显存爆了。

别这样写batch_size=64然后发现OOM,又改成batch_size=2。batch size太小(比如1或2)会导致梯度估计噪声大,训练不稳定。我实测过,YOLOv8在batch size=8和batch size=32之间,收敛速度差了一倍。

经验值:如果你的GPU是8GB显存,YOLOv8s模型用batch size=16比较稳;如果是24GB,可以上batch size=64。但注意,batch size翻倍时,learning rate也要相应调整——一般按比例缩放,比如batch size从16变32,lr从0.01调到0.02。

Learning Rate:最容易被忽视的调参项

Learning rate是训练过程中最重要的超参数,没有之一。YOLO默认的lr=0.01是针对COCO这种大数据集的。你的数据集如果只有几千张,0.01可能太大了。

真实案例:有个项目用YOLOv5训练口罩检测,lr=0.01,loss直接炸到NaN。降到0.001后,训练正常了。后来我习惯先跑几个epoch,观察loss曲线:如果loss震荡剧烈,说明lr太大;如果loss下降缓慢,说明lr太小。

YOLO的lr调度策略是余弦退火(Cosine Annealing),但很多人不知道的是,这个调度器是从warmup结束后才开始生效的。所以warmup阶段的设计直接影响后续训练。

Warmup:给模型一个热身期

Warmup就是在训练初期让learning rate从0或很小的值逐渐增加到目标值。YOLOv8默认warmup_epochs=3,warmup_momentum=0.8。

为什么需要warmup:刚初始化时,模型权重是随机的,梯度方向不稳定。如果直接给大lr,模型会“跑偏”。就像你刚睡醒就让你跑百米冲刺,肯定摔跤。

我踩过最深的坑是:有一次把warmup_epochs设成0,结果前10个epoch的loss曲线像心电图一样上下跳动,后面虽然稳定了,但最终mAP比有warmup的低了5个点。

实用建议:对于小数据集(<1000张),warmup_epochs可以设到5-10;大数据集(>10000张),3个epoch就够了。warmup_momentum从0.8逐渐增加到0.937(YOLO默认值),这个参数影响不大,保持默认就行。

EMA:模型参数的“滑动平均”

EMA(Exponential Moving Average)是YOLO系列的一个隐藏大招。它维护一份模型参数的指数移动平均副本,推理时用这个副本而不是原始模型。

直观理解:原始模型参数像股票价格的实时波动,EMA就像它的移动平均线,更平滑、更稳定。训练过程中,原始模型负责探索,EMA负责记录“共识”。

YOLOv8默认启用EMA,但很多人不知道它怎么工作的。代码里是这样实现的:

# 这里踩过坑:EMA的decay参数默认是0.9999# 意味着当前参数只占0.0001的权重,历史参数占99.99%# 所以EMA更新很慢,但最终效果很稳self.decay=0.9999

别这样写:把EMA的decay设成0.9,这样EMA几乎等于原始模型,失去了平滑效果。也别设成0.99999,更新太慢,训练结束了EMA还没跟上。

实际调试中,我习惯在训练结束后,分别用原始模型和EMA模型做推理对比。通常EMA模型的mAP会高1-2个点,尤其是小目标检测场景。

这些概念如何协同工作

训练一个YOLO模型,流程是这样的:

  1. 初始化模型参数,设置lr=0.01
  2. 前3个epoch(warmup阶段),lr从0线性增加到0.01
  3. 每个epoch遍历所有训练数据,按batch size分组
  4. 每个batch计算loss,反向传播,更新原始模型参数
  5. 同时更新EMA模型参数(原始参数的滑动平均)
  6. 每个epoch结束后,用EMA模型在验证集上评估
  7. 根据余弦退火策略调整lr
  8. 重复直到达到设定的epoch数

关键点:验证集评估一定要用EMA模型,而不是原始模型。YOLOv8的验证脚本默认就是这么做的,但如果你自己写训练脚本,很容易忽略这一点。

个人经验总结

  1. Epoch不是越多越好:用early stopping,当验证集mAP连续10个epoch不提升就停止
  2. Batch size选能承受的最大值:但别超过64,再大收益递减
  3. Learning rate从0.01开始:如果loss震荡,降到0.001;如果收敛慢,升到0.02
  4. Warmup一定要开:至少3个epoch,小数据集可以更多
  5. EMA一定要用:推理时用EMA模型,mAP能提升1-2个点

最后说一句:这些参数不是孤立的。比如你增大batch size,lr也要跟着调;你减少epoch数,warmup也要相应缩短。多跑几次实验,记录下每次的参数和结果,慢慢就能找到感觉。别指望一次调参就完美,训练深度学习模型本身就是个迭代过程。

← 返回列表