4. 优化器选择:SGD、Adam、AdamW、LAMB 对比归纳总结
空间模型训练里,优化器选不对,调参全白费。这话不夸张。
我刚开始接触大模型训练那会儿,觉得 Adam 是万能的,什么任务都往上套。后来遇到一个 100B 参数的多模态模型,训练到一半 loss 开始震荡,梯度直接炸了…… 嗯,从那以后我才认真去撸每个优化器的底层逻辑。
这一节我们就把四个最常用的优化器——SGD(带动量)、Adam、AdamW、LAMB——掰开揉碎讲清楚。你会明白它们各自擅长什么,又该在什么场景下用。
4.1 先捋一捋核心区别
说白了,优化器干两件事:用梯度更新参数,同时控制更新的大小和方向。不同优化器的区别就在于“怎么算动量”、“怎么调学习率”、“怎么处理权重衰减”。
| 优化器 | 动量机制 | 学习率自适应 | 权重衰减 | 典型适用场景 |
|---|---|---|---|---|
| SGD + Momentum | 一阶指数滑动 | 无 | 独立于梯度 | 小 batch、CV 微调、需要精细控制 |
| Adam | 一阶 + 二阶矩估计 | 逐参数 | 耦合衰减(早期版本) | NLP、推荐系统、多任务学习 |
| AdamW | 一阶 + 二阶矩估计 | 逐参数 | 解耦衰减 | Transformer 系列、大规模预训练 |
| LAMB | 一阶 + 二阶矩估计 | 逐层 + 归一化 | 解耦衰减 | 超大 batch (≥16K)、分布式训练 |
你看,Adam 和 AdamW 只有一列之差——“权重衰减”的策略。但这个差异在空间模型里特别要命。
4.2 为什么 AdamW 比 Adam 更适合 Transformers
我个人习惯在一开始就直接用 AdamW。为什么?
原始的 Adam 把权重衰减和梯度更新混在一起算:
θ = θ - lr * (m / (sqrt(v) + ε) + λ * θ)
看到那个 λ * θ 了吗?它被包在自适应学习率的分母外面。这样一来权重大小会反向影响正则强度,说白了就是“强的项被惩罚更多,弱的项反而罚得少”。对于 Attention 层里参数分布极不均衡的空间模型,这种耦合衰减常常导致 loss 降不下去。
# PyTorch 中的正确写法
# AdamW 直接支持 decoupled weight decay
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-4, weight_decay=0.01)
# 用 Adam 模拟 AdamW?千万别这么干
# optimizer = torch.optim.Adam(model.parameters(), lr=1e-4, weight_decay=0.01)
PyTorch 从 1.7 以后 torch.optim.AdamW 就是官方实现了,放心用。
4.3 LAMB 专为大 batch 而生
当你用 AdamW 把 batch size 推到 4096 以上时,你会发现 loss 开始不稳定,甚至直接发散。这时候就该 LAMB 上场了。
LAMB 的核心思想是逐层做“学习率归一化”——每层的参数更新量 ||Δθ|| 和该层参数范数 ||θ|| 的比值被限制在一个合理的范围。这样一来,哪怕 batch size 大到 64K,更新步长也不会飘。
实战经验: 我去年调一个 7B 参数的视觉-语言联合训练任务,单机 8 卡,每张卡 batch=16,总 batch=128,用 AdamW 跑了 100K step 一切正常。后来上到 64 卡分布式训练,总 batch=4096,AdamW 训了 500 step 就 loss 爆炸。换成 LAMB(lr=4e-3, weight_decay=0.01)后稳如老狗,收敛更快。
LAMB 的典型配置长这样:
# DeepSpeed 或 Hugging Face Trainer 中启用 LAMB
# 需要安装 deepspeed
--deepspeed ds_config.json
# ds_config.json 中配置
{
"optimizer": {
"type": "LAMB",
"params": {
"lr": 0.004,
"betas": [0.9, 0.999],
"eps": 1e-8,
"weight_decay": 0.01
}
}
}
4.4 什么时候该用 SGD?
你可能会问:都 2025 年了,还有人用 SGD?
有的。而且是在某些场景下它反而是最优解。
- 小样本微调: 当数据量小于 1K 时,自适应优化器的二阶矩估计方差会非常大,SGD + Momentum 反而更鲁棒。
- GAN 训练: 生成器和判别器的博弈需要精确控制更新量,自适应学习率有时候会破坏 Nash 均衡。
- 3D 重建 / NeRF: 这类任务的 loss landscape 相对平滑,SGD 的收敛稳定性更好。
CosineAnnealingLR(T_max=epochs),初始学习率 0.1 或 0.01,动量 0.9。
4.5 四个优化器的决策流程(一张图说清楚)
下面这张流程图可以帮你快速做选择。我自己平时写训练脚本前都会对着它走一遍:
4.6 参数初始化技巧(来自踩坑)
选好优化器只是第一步,参数怎么设更关键。我列几个我自己的经验值:
| 参数 | SGD+Momentum | Adam | AdamW | LAMB |
|---|---|---|---|---|
| 初始学习率 | 0.01 ~ 0.1 | 1e-4 ~ 1e-3 | 1e-4 ~ 1e-3 | 1e-3 ~ 4e-3 |
| β₁ | 动量=0.9 | 0.9 | 0.9 | 0.9 |
| β₂ | — | 0.999 | 0.999 | 0.999 |
| ε | — | 1e-8 | 1e-8 | 1e-8 |
| 权重衰减 | 0.0001 ~ 0.001 | 不建议用 | 0.01 ~ 0.1 | 0.01 ~ 0.1 |
| 梯度裁剪 | 可选 1.0 | 推荐 1.0 | 推荐 1.0 | 推荐 1.0 |
一句话总结我的选择习惯:
- 单卡、常规模型 → AdamW(省心,好调)
- 多卡、大 batch (≥4K) → LAMB(必须用,否则容易崩)
- 小数据、GAN、NeRF → SGD+Momentum(手动控制感更强)
- 遗留项目或纯 NLP 小模型 → Adam(兼容旧代码)
4.7 一个常见的“自适应 vs 非自适应”误区
很多人觉得自适应学习率优化器一定比 SGD 好。其实不然。我遇到过好几次这样的情况:AdamW 训到后期学习率降到 1e-6 以下,参数几乎不动了;而 SGD 因为学习率是手动调度(比如 T_max=100 的余弦退火),反而能跳出来继续降到更低 loss。
为什么会这样?因为自适应优化器把历史梯度信息累积在了二阶矩里,当梯度过小时,sqrt(v) 也会很小,导致有效学习率突然变大,震荡。而 SGD 没有这个“回光返照”,很老实。
所以——做 ablation study 或者比赛提点的时候,不妨试试 SGD + 余弦退火,有时候会有惊喜。