本节摘要:优化器决定模型怎么更新参数。本节讲 SGD、Adam 等优化器,以及学习率预热、余弦退火等策略——训练检测器的"方向盘"。
阅读完本节,你应当能够:
优化器根据损失梯度更新参数:\theta_{t+1} = \theta_t - \eta \nabla L。学习率 \eta 太大震荡,太小收敛慢。
优化器的本质是回答"往哪个方向走、走多大步"。梯度告诉方向,学习率和动量决定步长。检测模型参数量从几百万到上亿,优化策略直接影响能否收敛到好的局部最优,以及收敛速度。
| 优化器 | 特点 | 适合 |
|---|---|---|
| SGD | 简单稳定,泛化好 | 检测常用(YOLO/Faster R-CNN) |
| SGD+Momentum | 加动量加速 | 检测默认 |
| Adam | 自适应学习率 | 快速实验 |
| AdamW | Adam+权重衰减 | Transformer 类 |
# SGD + Momentum optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.937, weight_decay=5e-4)
SGD 虽然简单,但泛化性好,是检测训练主流(YOLOv5、Faster R-CNN 都用)。动量项记录历史梯度方向,避免在损失面狭窄处来回震荡。momentum=0.9 是常见默认,YOLOv5 用了 0.937。
Adam 自适应调整每个参数学习率,收敛快,但泛化有时不如 SGD。AdamW 加权重衰减,Transformer 类检测器常用。
为什么检测默认用 SGD 而不用 Adam?实验观察:Adam 收敛快但最终精度往往略低于调好的 SGD+Momentum,且对权重衰减的处理不当会导致过拟合。不过近年 DETR 等 Transformer 检测器普遍用 AdamW,说明优化器选择要跟着架构走。
学习率对训练影响极大,常用策略:
训练初期用小学习率,逐步升到初始学习率,避免初期不稳定:
# YOLOv5 预热前 3 个 epoch lr_lambda = lambda epoch: min(1.0, (epoch+1)/3) if epoch < 3 else 1.0
为什么预热?训练开始时权重是随机或预训练的,梯度方向剧烈变化,大学习率容易把参数推离好区域。预热让模型先"稳下来",再用正常学习率加速。
学习率按余弦曲线从初始值降到很小,平滑收敛:
YOLOv4/v5 用余弦退火,后期小学习率精调。相比阶梯衰减,余弦退火全程平滑下降,后期不用手动设衰减节点。
每若干 epoch 学习率乘以衰减因子(如 0.1):
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
Faster R-CNN 经典用阶梯衰减(60/120 epoch 各降 10 倍)。阶梯衰减好理解、好调,但需要在训练前定好衰减时机。
余弦退火 + 周期性重启,跳出局部最优。重启时学习率回到高位,把模型从当前局部最优"弹"出去探索新区域,适合训练时间充裕的情况。
权重衰减(L2 正则)防止过拟合:
SGD 用 weight_decay 参数,AdamW 用解耦权重衰减。权重衰减让大权重受罚,模型倾向于用更小的参数拟合,泛化更好。注意:Adam 的实现里 weight_decay 作用方式与 SGD 不同,AdamW 把它与梯度更新解耦,训练更稳定。
# YOLOv5 优化器配置 optimizer = optim.SGD(params, lr=0.01, momentum=0.937, weight_decay=5e-4, nesterov=True) # 学习率:3 epoch 预热 + 余弦退火 lf = lambda x: ((1 + math.cos(x * math.pi / epochs)) / 2) * (1 - lrf) + lrf # lrf=0.01 scheduler = optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lf)
这套组合是 YOLOv5 的默认:SGD + Nesterov 动量 + 权重衰减 + 预热 + 余弦退火。它经过大量实验验证,直接搬用到自定义数据集通常表现不错。
EMA 的做法:每个 step 用 w_{ema} = \alpha w_{ema} + (1-\alpha) w 更新影子权重,推理用 EMA 权重。它等价于对多次快照做平均,抑制权重震荡,常能白捡 0.5~1 个点 mAP。多尺度训练让模型见过各种分辨率,部署时对输入尺寸不敏感。混合精度把计算降到 FP16,显存减半、速度翻倍,配合梯度缩放避免精度损失。
问:学习率怎么定? 先用大学习率(0.01 或 0.001)快速试验几轮看损失是否下降,再用预热 + 余弦退火从初始学习率平滑调度。YOLOv5 默认 lr=0.01,Faster R-CNN 微调常用 0.001~0.005。
问:batch 小怎么办? 减小 batch 会让 BN 统计噪声变大,可改用 GroupNorm,或保留大 batch 用梯度累积模拟。
问:换优化器后精度掉了? 优化器与学习率、权重衰减强耦合。从 SGD 换 Adam 后,学习率要降一个数量级,权重衰减可能也要重新调。
⚠️ 常见坑:直接用 Adam 训检测——Adam 泛化可能不如 SGD+Momentum。检测默认 SGD+Momentum,Adam 用于快速实验。
💡 关键直觉:优化器是训练方向盘。检测常用 SGD+Momentum(泛化好)。学习率:预热(稳起步)+余弦退火(平滑收敛)。加 EMA、多尺度训练、混合精度提升效果。
下一节讲数据增强。