优化器与训练技巧(Adam / SGD / LR Schedule / Warmup)
先把结论放前面
优化器的选择和学习率调度是训练深度网络最关键的两个工程决策:
- SGD + Momentum:泛化能力更强,调参直觉清晰,但收敛慢、需要仔细调学习率
- Adam / AdamW:收敛快,对学习率不那么敏感,但泛化能力有时不如 SGD
- 实际建议:Transformer 类模型用 AdamW(Adam 的权重衰减修正),CNN / 传统深度学习用 SGD+Momentum,大模型用 AdamW
学习率调度比学习率本身更重要:Warmup + Cosine Annealing 是当前最标准的配置。
SGD with Momentum
标准 SGD
θ ← θ - α · ∇L(θ)
问题是梯度方向震荡,收敛慢。
Momentum(动量)
v_t = β · v_{t-1} + ∇L(θ) # 动量累积
θ ← θ - α · v_t # 沿动量方向更新
Momentum 让更新方向保持惯性,减少震荡,加速收敛。β = 0.9 是标准值。
物理类比:一个小球在损失曲面上滚动,Momentum 让它有惯性。
Nesterov Momentum
标准 Momentum 先累积历史梯度再更新,Nesterov 先"前瞻"一步再修正:
v_t = β · v_{t-1} + ∇L(θ - α · β · v_{t-1}) # 先走一步
θ ← θ - α · v_t
Nesterov 通常比标准 Momentum 更快收敛,尤其在曲面弯曲处。
Adam(Adaptive Moment Estimation)
Adam 的更新规则
Adam 维护两个指数移动平均:
- 动量(m_t):梯度的一阶矩估计(类似 Momentum)
- 自适应学习率(v_t):梯度平方的指数移动平均(自动调节每个参数的学习率)
m_t = β₁ · m_{t-1} + (1-β₁) · g_t # 动量
v_t = β₂ · v_{t-1} + (1-β₂) · g_t² # 自适应学习率(二阶矩)
m̂_t = m_t / (1 - β₁^t) # 偏差修正
v̂_t = v_t / (1 - β₂^t) # 偏差修正
θ ← θ - α · m̂_t / (√v̂_t + ε)
Adam 的自适应学习率
- 梯度大的参数 → v_t 大 → 学习率自动减小
- 梯度小的参数 → v_t 小 → 学习率自动增大
结果是每个参数有独立的学习率,自动适应梯度的稀疏性。
AdamW(带权重衰减的 Adam)
标准 Adam 的 L2 正则化和权重衰减不是一回事——Adam 的自适应学习率让 L2 正则效果不稳定。
AdamW 修正了这个问题,直接在梯度上施加权重衰减:
θ ← θ - α · (m̂_t / √v̂_t + λ · θ)
Adam vs SGD+Momentum
| 维度 | SGD + Momentum | Adam / AdamW |
|---|---|---|
| 泛化能力 | 更强 | 有时更差 |
| 收敛速度 | 慢 | 快 |
| 学习率敏感性 | 高(需要精细调度) | 低(自适应) |
| 超参数调参 | 难 | 相对容易 |
| 理论支持 | 强 | 弱(收敛不稳定) |
| 大数据训练 | 优(泛化好) | 差(有时泛化差) |
Transformer 训练为什么用 AdamW:因为 Transformer 的优化曲面(loss landscape)用 SGD 不容易找到好的泛化点,AdamW 在收敛速度和泛化之间找到了更好的平衡。
学习率调度(Learning Rate Schedule)
为什么需要学习率调度
固定学习率的两个问题:
- 学习率太大 → 震荡不收敛
- 学习率太小 → 收敛太慢
Warmup(学习率预热)
Transformer 训练初期(尤其是大模型)需要 Warmup:
t < T_warmup: lr = t / T_warmup × lr_max
t ≥ T_warmup: lr = lr_max
为什么需要 Warmup:训练初期参数随机,梯度方向不可靠。如果一开始学习率太大,会把网络"踢"到一个不好的区域,后续很难恢复。Warmup 让参数在早期稳定后再大学习。
Warmup 的另一个解释:分布式训练时,各 Worker 的梯度在早期差异大,Warmup 让网络慢慢稳定。
Cosine Annealing(余弦退火)
lr(t) = lr_min + (lr_max - lr_min) × (1 + cos(π · t / T)) / 2
从 lr_max 缓慢退火到 lr_min,曲线是余弦形状。配合 Warmup 是 Transformer 训练的标准配置:
Warmup (线性) → Cosine Annealing (余弦)
Step Decay(阶梯衰减)
每 N 个 epoch 把学习率乘以 γ(γ = 0.1):
lr_new = lr_old × 0.1 (每 30 epochs)
简单有效,是 CNN 训练的传统方法。但需要手工选择衰减时机,不如 Cosine Annealing 平滑。
实际训练配置参考
Transformer(大模型,推荐)
optimizer = AdamW(model.parameters(), lr=3e-4, weight_decay=0.01)
scheduler = CosineAnnealingWarmupLR(
optimizer,
warmup_steps=2000,
max_steps=num_training_steps,
min_lr=3e-5
)
CNN(图像,推荐)
optimizer = SGD(model.parameters(), lr=0.1, momentum=0.9, weight_decay=5e-4)
scheduler = MultiStepLR(optimizer, milestones=[30, 60, 90], gamma=0.1)
如果放到面试里怎么讲
"Adam 为什么有时泛化不如 SGD?"
Adam 的自适应学习率对每个参数自动调节,但这个自适应本身是"短期"的——只看过去几个 step 的梯度平方均值。这会导致它对某些方向的"惩罚"过大,让网络找到的解泛化不如 SGD。Momentum 的 SGD 因为有更"长期"的累积方向,梯度曲面更平滑,泛化能力通常更好。这在大规模训练(如 GPT/BERT)里有大量实验验证。
"Warmup 为什么对 Transformer 重要?"
Transformer 的参数是随机初始化的,早期梯度方向噪声很大。如果一开始学习率太大,会把参数"踢"到一个损失曲面的不稳定区域,难以恢复。另外大模型分布式训练时,早期各 Worker 梯度差异很大,Warmup 让参数在早期稳定下来再大学习,保证各 Worker 同步稳定。
最后记几个点
- SGD+Momentum 泛化能力强但收敛慢;Adam 收敛快但泛化有时更差
- AdamW = Adam + 正确的权重衰减,是 Transformer 训练的推荐优化器
- 学习率调度比学习率本身更重要,固定学习率几乎训不好大模型
- Warmup 解决训练初期梯度方向不稳定的问题,是 Transformer 的必备配置
- Cosine Annealing + Warmup 是当前最标准的训练配置
- 分布式训练(多 GPU)时,梯度同步通信成本高,正确的学习率调度更关键
跨库关联
- LLM 训练流程总览 — 大模型训练中的优化器配置
- Transformer 详解 — Transformer 为什么用 AdamW