4、优化器选择(上):SGD与Momentum的原理与适用场景、Adam与AdamW的对比
说到优化器,很多同学上来就无脑用Adam。我刚开始做模型调优时也这样,觉得Adam省心、收敛快。但后来踩了不少坑才发现——选不对优化器,模型精度可能直接掉几个点。今天咱们就把SGD、Momentum、Adam和AdamW这几个主流优化器掰开揉碎讲清楚。
4.1 SGD:最朴素的梯度下降
SGD(随机梯度下降)是所有优化器的老祖宗。它的思想很简单:沿着梯度反方向走一步。
公式长这样:
θ = θ - η * ∇θ J(θ)
其中η是学习率,∇θ J(θ)是损失函数对参数的梯度。
听起来很合理对吧?但实际用起来问题不少。我印象最深的一次,训练一个图像分类模型,SGD跑了200个epoch还没收敛。为什么?因为SGD在峡谷地形里会来回震荡——梯度指向最优解的方向分量小,垂直方向的分量大,参数就在山谷两边来回跳,就是下不去。
SGD的核心特点:
- 每次更新只依赖当前batch的梯度,随机性强
- 容易跳出局部极小点(因为噪声大)
- 但收敛慢,尤其在病态曲面上
- 对学习率非常敏感
我的经验:SGD适合数据量极大、需要精细调优的场景。比如在CV领域做迁移学习,用SGD微调往往比Adam效果好。但前提是你得把学习率、动量、权重衰减这些超参数调好。
4.2 Momentum:给梯度加上惯性
为了解决SGD震荡的问题,Momentum(动量)引入了速度累积的概念。说白了就是:如果梯度方向一直朝一个方向走,那就加速;如果方向来回变,那就减速。
公式:
v = γ * v + η * ∇θ J(θ)
θ = θ - v
γ是动量系数,通常取0.9。v是累积的速度。
你可以想象一个小球从山坡上滚下来——它不会因为遇到一个小坑就停下来,而是靠着惯性冲过去。这就是Momentum的精髓。
我曾经在训练一个NLP模型时,用SGD死活不收敛,换成Momentum后,50个epoch就达到了SGD 200个epoch的效果。差别就这么大。
注意:动量不是越大越好。γ=0.99时,模型可能冲过头,在最优解附近震荡。我一般从0.9开始调,效果不好再试0.95或0.99。
4.3 Adam:自适应学习率的集大成者
Adam结合了Momentum和RMSProp的思想——既考虑梯度的一阶矩(动量),又考虑二阶矩(自适应学习率)。
它的核心公式:
m = β1 * m + (1-β1) * g # 一阶矩估计
v = β2 * v + (1-β2) * g² # 二阶矩估计
m_hat = m / (1 - β1^t) # 偏差修正
v_hat = v / (1 - β2^t)
θ = θ - η * m_hat / (√v_hat + ε)
Adam为什么受欢迎?因为它对超参数不敏感。默认的β1=0.9、β2=0.999、ε=1e-8,在很多任务上都能直接跑出不错的结果。
但Adam有个问题——泛化能力不如SGD。我在做图像分类比赛时发现,Adam在训练集上loss降得很快,但验证集精度就是上不去。换成SGD+Momentum后,验证集精度反而高了1-2个点。
为什么会这样?学术界有几种解释:
- Adam的自适应学习率导致权重更新过于激进,容易陷入尖锐的局部极小点
- SGD的随机性更强,能找到更平坦的最优解,泛化更好
- Adam对权重衰减的处理方式有问题(这点下面细说)
4.4 AdamW:修复Adam的权重衰减问题
AdamW是Adam的改进版,主要改了权重衰减(Weight Decay)的实现方式。
在Adam中,权重衰减是这么做的:
# Adam的权重衰减(错误方式)
g = ∇θ J(θ) + λ * θ # 把权重衰减加到梯度里
m = β1 * m + (1-β1) * g
v = β2 * v + (1-β2) * g²
θ = θ - η * m_hat / (√v_hat + ε)
而AdamW把权重衰减从梯度计算中分离出来:
# AdamW的权重衰减(正确方式)
g = ∇θ J(θ) # 先算原始梯度
m = β1 * m + (1-β1) * g
v = β2 * v + (1-β2) * g²
θ = θ - η * (m_hat / (√v_hat + ε) + λ * θ) # 权重衰减单独加
区别在哪?Adam把权重衰减和梯度混在一起,导致自适应学习率对权重衰减也做了缩放——这其实是不对的。AdamW把两者分开,让权重衰减不受学习率自适应的影响。
我在实际项目中发现,AdamW在大规模预训练模型上效果明显优于Adam。比如训练BERT、GPT这类模型,用AdamW几乎成了标配。
4.5 四者对比一览
| 优化器 | 核心思想 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| SGD | 纯梯度下降 | 数据量大、需要精细调优 | 泛化好、理论成熟 | 收敛慢、对学习率敏感 |
| Momentum | 梯度累积+惯性 | 有震荡的优化问题 | 加速收敛、抑制震荡 | 可能冲过头 |
| Adam | 动量+自适应学习率 | 快速原型、NLP任务 | 收敛快、超参数鲁棒 | 泛化差、权重衰减有bug |
| AdamW | Adam+正确权重衰减 | 大规模预训练、CV | 泛化好、权重衰减有效 | 计算量略大 |
4.6 我的选择建议
说了这么多,到底该用哪个?我个人的经验是:
- 快速验证想法:用Adam,默认参数就行
- 做CV比赛或产品:用SGD+Momentum,花时间调学习率和动量
- 训练大模型(BERT/GPT等):用AdamW,权重衰减设0.01
- 迁移学习微调:SGD+Momentum往往比Adam好
避坑指南:我曾经在一个推荐系统项目里,用Adam训了3天,线上A/B测试效果还不如老模型。换成SGD+Momentum后,AUC提升了0.8%。后来分析发现,Adam把模型推到了一个尖锐的极小点,泛化能力差。所以——别迷信Adam,该用SGD时别犹豫。
4.7 知识体系图
下面这张图帮你理清四个优化器的关系:
嗯,优化器选择这块,说白了就是在收敛速度和泛化能力之间做权衡。Adam快但可能泛化差,SGD慢但泛化好。AdamW算是目前比较好的折中方案。
下一节咱们聊聊学习率调度和权重初始化,这两个跟优化器配合好了,效果能再上一个台阶。