0. 优化器到底在做什么?#
神经网络训练的目标是最小化损失函数:
ωminL(ω)其中:
- ω:模型参数,可以是一个参数向量,也可以代表神经网络中的全部权重矩阵;
- L(ω):当前参数下的损失函数;
- 优化器的任务:不断更新 ω,让 L(ω) 变小。
最基础的更新公式是:
ωt+1=ωt−ηgt其中:
gt=∇ωL(ωt)含义是:
第 t 次迭代时,在当前参数 ωt 处,计算 loss 对参数 ω 的梯度。
符号说明:
| 符号 | 含义 |
|---|
| ωt | 第 t 步的全部参数 |
| gt | 第 t 步的梯度 |
| η | 学习率 |
| −gt | loss 下降最快的方向 |
| ωt+1 | 更新后的参数 |
需要特别注意:
ωt表示第 t 步时的参数整体,不表示第 t 个参数。
如果模型有 n 个参数:
ωt=[ωt,1,ωt,2,⋯,ωt,n]那么梯度也是一个向量:
gt=[gt,1,gt,2,⋯,gt,n]其中:
gt,i=∂ωt,i∂L
1. 普通梯度下降:只看当前梯度#
普通梯度下降公式:
ωt+1=ωt−ηgt它的逻辑是:
- 当前参数是 ωt;
- 计算当前梯度 gt;
- 梯度方向是 loss 上升最快方向;
- 沿着负梯度方向更新;
- 更新步长由学习率 η 控制。
1.1 单参数情况#
如果只有一个参数 ω:
ωt+1=ωt−η∂ωt∂L如果:
∂ωt∂L>0说明增大 ω 会让 loss 增大,所以应该减小 ω。
如果:
∂ωt∂L<0说明增大 ω 会让 loss 减小,所以应该增大 ω。
1.2 多参数情况#
如果参数为:
ω=[ω1,ω2]则梯度为:
gt=[∂ωt,1∂L,∂ωt,2∂L]对应更新为:
ωt+1,1=ωt,1−η∂ωt,1∂Lωt+1,2=ωt,2−η∂ωt,2∂L也就是每个参数都沿着自己的负梯度方向走一步。
2. 普通梯度下降的问题#
2.1 所有参数共用同一个学习率#
普通梯度下降中:
ωt+1,i=ωt,i−ηgt,i所有参数都使用同一个学习率 η。
但真实训练中,不同参数的梯度尺度可能差别很大:
- 有些参数梯度很大,需要小步更新;
- 有些参数梯度很小,需要保留较大更新;
- 一个统一学习率很难同时适配所有参数。
2.2 只看当前梯度,容易震荡#
如果 loss 曲面像狭长山谷,梯度可能表现为:
普通梯度下降每次只看当前梯度,会导致参数路径在山谷两侧来回摆动,收敛速度变慢。
2.3 学习率很难调#
学习率过大:
学习率过小:
后续优化算法基本都围绕这些问题改进:
1. 方向如何更稳定?
2. 每个参数的步长如何自适应?
3. 历史梯度如何影响当前更新?
4. 训练初期和后期如何更稳定?
text
3. Momentum:利用历史方向减少震荡、加速稳定方向#
Momentum 的核心思想是:
当前梯度可能抖动,但历史梯度方向可以提供更稳定的运动趋势。
普通梯度下降:
ωt+1=ωt−ηgtMomentum 引入速度变量 vt:
vt=βvt−1+gt然后更新参数:
ωt+1=ωt−ηvt其中:
| 符号 | 含义 |
|---|
| vt | 动量 / 历史梯度方向累计 |
| β | 动量系数,常用 0.9 |
| gt | 当前梯度 |
| η | 学习率 |
有些资料会写成:
vt=βvt−1+(1−β)gt这是指数滑动平均写法。两种写法思想一致,区别在于是否把 (1−β) 放进动量定义里。
3.1 Momentum 的展开形式#
从:
vt=βvt−1+gt不断展开:
vt=gt+βgt−1+β2gt−2+β3gt−3+⋯说明 vt 是历史梯度的加权和。越新的梯度权重大,越旧的梯度权重小。
3.2 为什么稳定方向会加速?#
假设某个方向的梯度长期一致:
gt=a那么:
vt=a+βa+β2a+⋯当 t 足够大时:
vt≈1−βa如果:
β=0.9则:
1−0.91=10这说明长期一致的方向会被放大,大约加速到 10 倍。
3.3 为什么震荡方向会被削弱?#
如果某个方向的梯度反复变化:
g1=b,g2=−b,g3=b,g4=−b则动量累积中会出现:
b−βb+β2b−β3b+⋯正负方向会互相抵消。
所以 Momentum 的效果是:
4. AdaGrad:让每个参数拥有自己的学习率#
AdaGrad 解决的问题是:
不同参数的梯度尺度不同,因此不同参数应该拥有不同的有效学习率。
AdaGrad 维护历史梯度平方和:
Gt=Gt−1+gt⊙gt然后更新:
ωt+1=ωt−Gt+ϵη⊙gt其中:
| 符号 | 含义 |
|---|
| Gt | 历史梯度平方累计 |
| ⊙ | 逐元素乘法 |
| ϵ | 防止除零的小常数 |
4.1 单个参数形式#
对第 i 个参数:
Gt,i=Gt−1,i+gt,i2ωt+1,i=ωt,i−Gt,i+ϵηgt,i定义有效学习率:
ηt,i=Gt,i+ϵη于是:
ωt+1,i=ωt,i−ηt,igt,i所以 AdaGrad 本质上是在给每个参数分配自己的动态学习率。
4.2 AdaGrad 的直觉#
如果某个参数历史梯度很大:
Gt,i 大则:
ηt,i 小这个参数后续更新会变谨慎。
如果某个参数历史梯度很小:
Gt,i 小则:
ηt,i 相对较大这个参数仍然可以继续学习。
4.3 AdaGrad 为什么使用平方梯度?#
梯度有正有负。如果直接累加:
g1+g2+⋯可能正负抵消。例如:
10+(−10)=0这并不说明该方向不重要,只说明梯度方向发生过变化。
使用平方:
gt2可以记录梯度大小,不受正负号影响。
4.4 AdaGrad 的缺点#
AdaGrad 的累计项:
Gt=Gt−1+gt2只会越来越大。因此有效学习率:
Gt+ϵη会越来越小。
训练后期可能出现:
有效学习率过小
参数几乎不再更新
模型还未充分收敛,训练已经走不动
text
这就是 RMSProp 要解决的问题。
5. RMSProp:只记近期梯度平方,避免 AdaGrad 后期步长过小#
RMSProp 可以看作 AdaGrad 的改进。
AdaGrad 使用完整历史累计:
Gt=Gt−1+gt2RMSProp 改成指数滑动平均:
st=ρst−1+(1−ρ)gt⊙gt然后更新:
ωt+1=ωt−st+ϵη⊙gt其中:
| 符号 | 含义 |
|---|
| st | 梯度平方的指数滑动平均 |
| ρ | 衰减系数,常用 0.9 或 0.99 |
| gt2 | 当前梯度平方 |
5.1 RMSProp 的展开形式#
从:
st=ρst−1+(1−ρ)gt2展开得到:
st=(1−ρ)gt2+ρ(1−ρ)gt−12+ρ2(1−ρ)gt−22+⋯所以 RMSProp 更重视近期梯度平方,久远梯度的影响会指数衰减。
5.2 RMSProp 与 AdaGrad 的核心区别#
AdaGrad:
Gt=g12+g22+⋯+gt2RMSProp:
st=(1−ρ)τ=1∑tρt−τgτ2区别可以概括为:
AdaGrad:所有历史梯度平方都记住
RMSProp:近期梯度平方更重要,久远历史逐渐遗忘
text
5.3 RMSProp 的优点#
RMSProp 避免了 AdaGrad 分母无限增长的问题。如果最近梯度变小,st 也会下降,有效学习率有机会恢复。因此 RMSProp 更适合非平稳的深度学习训练过程。
5.4 RMSProp 的问题#
RMSProp 的有效学习率是:
ηt=st+ϵη如果 st 下降,分母变小,有效学习率会上升。这在一些情况下是合理的,但也可能造成训练不稳定。
6. Adam:Momentum + RMSProp + 偏差修正#
Adam 全称为:
Adaptive Moment Estimation它结合了两个核心思想:
Momentum:用历史梯度平均稳定方向
RMSProp:用历史梯度平方平均调整步长
text
Adam 维护两个变量。
一阶动量:
mt=β1mt−1+(1−β1)gt二阶动量:
vt=β2vt−1+(1−β2)gt⊙gt偏差修正:
m^t=1−β1tmtv^t=1−β2tvt参数更新:
ωt+1=ωt−ηv^t+ϵm^t
7. Adam 每一项的含义#
7.1 当前梯度 gt#
gt=∇ωL(ωt)表示当前 batch 下 loss 对参数的瞬时梯度。
7.2 一阶动量 mt#
mt=β1mt−1+(1−β1)gt它是梯度的指数滑动平均。作用是平滑当前梯度、减少方向抖动、让长期一致的方向更稳定。
如果:
β1=0.9则:
mt=0.9mt−1+0.1gt7.3 二阶动量 vt#
vt=β2vt−1+(1−β2)gt2它是梯度平方的指数滑动平均。作用是估计每个参数最近的梯度尺度,梯度大的方向缩小步长,梯度小的方向保留更新。
如果:
β2=0.999则:
vt=0.999vt−1+0.001gt27.4 偏差修正 m^t、v^t#
Adam 初始化时通常令:
m0=0,v0=0这会导致训练初期 mt 和 vt 被 0 明显拉低。
所以需要偏差修正:
m^t=1−β1tmtv^t=1−β2tvt偏差修正的本质:
指数滑动平均从 0 开始,训练初期会被 0 拉低。
理论上第 t 步会少乘一个 1 - β^t。
所以除以 1 - β^t,可以把估计值放大回合理尺度。
text
8. Adam 偏差修正的数学推导#
以一阶动量为例:
mt=β1mt−1+(1−β1)gt并且:
m0=0递推展开:
mt=(1−β1)τ=1∑tβ1t−τgτ假设每一步梯度的期望恒定为:
E[gτ]=μ两边取期望:
E[mt]=E[(1−β1)τ=1∑tβ1t−τgτ]利用期望的线性性质:
E[mt]=(1−β1)τ=1∑tβ1t−τE[gτ]代入:
E[gτ]=μ得到:
E[mt]=(1−β1)τ=1∑tβ1t−τμ把 μ 提出来:
E[mt]=(1−β1)μτ=1∑tβ1t−τ观察求和项:
τ=1∑tβ1t−τ=1+β1+β12+⋯+β1t−1这是等比数列:
1+β1+β12+⋯+β1t−1=1−β11−β1t代回:
E[mt]=(1−β1)μ1−β11−β1t约掉 (1−β1):
E[mt]=(1−β1t)μ这说明 mt 的期望比真实均值 μ 少了一个系数:
1−β1t所以修正为:
m^t=1−β1tmt于是:
E[m^t]=μ二阶动量同理:
vt=β2vt−1+(1−β2)gt2所以:
v^t=1−β2tvt
9. 用数字理解偏差修正#
设:
β1=0.9且每一步梯度都等于:
gt=10真实平均梯度为:
μ=10第 1 步:
m1=0.1×10=1明显比 10 小。
偏差修正:
m^1=1−0.91m1=0.11=10第 2 步:
m2=0.9×1+0.1×10=1.9偏差修正:
m^2=1−0.921.9=0.191.9=10这说明偏差修正能够把前期被 0 压小的估计恢复到合理尺度。
10. 为什么 vt 的偏差更严重?#
Adam 常用:
β2=0.999第 1 步:
1−β21=0.001说明未修正的 v1 只有真实二阶矩的千分之一。
第 100 步:
1−0.999100≈0.095也只有真实二阶矩的约 9.5%。
因此二阶动量如果不做修正,训练初期会严重偏小。
Adam 同时修正 mt 和 vt,是为了让前期的方向估计和尺度估计都更加合理。
11. Adam 的直觉总结#
Adam 更新公式:
ωt+1=ωt−ηv^t+ϵm^t可以理解为:
分子 \hat{m}_t:
告诉模型应该往哪个方向走。
分母 \sqrt{\hat{v}_t}:
告诉模型这个方向最近波动大不大,步子应该多大。
偏差修正:
解决训练初期 m_t 和 v_t 从 0 开始导致估计偏小的问题。
text
一句话概括:
Adam 用一阶动量稳定方向,用二阶动量自适应步长,用偏差修正解决冷启动偏差。
text
12. AdamW:现代深度学习更常用的 Adam 变体#
Adam 的原始 weight decay 与自适应学习率耦合在一起,可能影响泛化。
AdamW 的核心改进是:
把 weight decay 从 Adam 的自适应梯度更新中解耦出来。
AdamW 可以简化理解为:
ωt+1=ωt−ηv^t+ϵm^t−ηλωt其中:
- λ:weight decay 系数;
- 前一项:Adam 的自适应梯度更新;
- 后一项:独立的权重衰减。
12.1 AdamW 的优势#
AdamW 在现代深度学习中非常常用,尤其适合:
Transformer
ViT
CLIP
多模态模型
扩散模型
AIGC 检测模型
预训练模型微调
text
实践中常用组合:
AdamW + warmup + cosine decay
text
13. AMSGrad:防止 Adam 有效学习率突然变大#
Adam 和 RMSProp 都有一个潜在问题:
vt是指数滑动平均,可能变小。
如果 vt 变小,那么:
vt变小,于是有效学习率:
vt+ϵη会变大。
AMSGrad 的解决方法是维护历史最大二阶动量:
v~t=max(v~t−1,vt)其中 max 是逐元素最大。
然后更新:
ωt+1=ωt−ηv~t+ϵm^t这样 v~t 不会下降,分母不会突然变小,有效学习率不会突然变大。
14. 各优化器之间的主线关系#
SGD
│
├── Momentum
│ └── 解决梯度方向震荡问题
│
├── AdaGrad
│ └── 解决每个参数学习率相同的问题
│
├── RMSProp
│ └── 解决 AdaGrad 历史累计过大、后期学习率过小的问题
│
├── Adam
│ └── Momentum + RMSProp + 偏差修正
│
├── AdamW
│ └── Adam + 解耦 weight decay
│
└── AMSGrad
└── Adam + 防止二阶动量下降导致有效学习率突然增大
text
15. 公式总表#
| 优化器 | 核心变量 | 关键公式 | 核心思想 |
|---|
| SGD | 无 | ωt+1=ωt−ηgt | 沿当前负梯度更新 |
| Momentum | vt | vt=βvt−1+gt | 累积历史方向,减少震荡 |
| AdaGrad | Gt | Gt=Gt−1+gt2 | 历史梯度越大,后续学习率越小 |
| RMSProp | st | st=ρst−1+(1−ρ)gt2 | 用近期梯度平方调节学习率 |
| Adam | mt,vt | 一阶动量 + 二阶动量 + 偏差修正 | 稳定方向 + 自适应步长 |
| AdamW | mt,vt | Adam + 解耦权重衰减 | 更适合现代深度学习 |
| AMSGrad | v~t | v~t=max(v~t−1,vt) | 防止有效学习率突然变大 |
16. 从几何角度理解优化器#
所有优化器都可以抽象为:
ωt+1=ωt−ηPtgt其中 Pt 可以理解为“梯度预处理器”。
不同优化器的本质区别就在于如何构造 Pt。
16.1 SGD#
Pt=I直接使用当前梯度。
16.2 Momentum#
Momentum 用历史梯度方向共同决定当前更新方向,主要改变方向稳定性。
16.3 AdaGrad / RMSProp / Adam#
它们使用类似:
Pt=历史梯度平方+ϵ1的形式,主要改变每个参数的有效学习率。
16.4 AdamW#
AdamW 在 Adam 的基础上额外加入解耦权重衰减,使正则化更加清晰。
17. 优化器选择建议#
17.1 通用深度学习任务#
优先使用:
optimizer = torch.optim.AdamW(
model.parameters(),
lr=1e-4,
weight_decay=0.01
)
python
适合:
Transformer
ViT
CLIP
多模态模型
AIGC 检测
扩散模型
预训练模型微调
text
17.2 CNN 图像分类任务#
可以比较:
optimizer = torch.optim.SGD(
model.parameters(),
lr=0.01,
momentum=0.9,
weight_decay=5e-4,
nesterov=True
)
python
SGD + Momentum 有时泛化更好,但学习率和训练轮数更难调。
17.3 微调预训练 backbone#
推荐使用分组学习率:
optimizer = torch.optim.AdamW([
{"params": backbone.parameters(), "lr": 1e-5},
{"params": classifier.parameters(), "lr": 1e-4},
], weight_decay=0.01)
python
原因:
backbone 已有预训练知识,学习率小一点;
classifier 是新加的分类头,学习率大一点。
text
17.4 优化器要和 scheduler 一起看#
常见现代组合:
AdamW + warmup + cosine decay
text
含义:
warmup:
训练初期学习率从小逐渐升高,防止一开始更新过猛。
cosine decay:
训练中后期学习率逐渐下降,让模型稳定收敛。
text
18. PyTorch 代码对应#
18.1 SGD#
optimizer = torch.optim.SGD(
model.parameters(),
lr=0.01
)
python
18.2 SGD + Momentum#
optimizer = torch.optim.SGD(
model.parameters(),
lr=0.01,
momentum=0.9
)
python
18.3 AdaGrad#
optimizer = torch.optim.Adagrad(
model.parameters(),
lr=0.01
)
python
18.4 RMSProp#
optimizer = torch.optim.RMSprop(
model.parameters(),
lr=0.001,
alpha=0.99,
eps=1e-8
)
python
其中 alpha 对应公式中的 ρ。
18.5 Adam#
optimizer = torch.optim.Adam(
model.parameters(),
lr=0.001,
betas=(0.9, 0.999),
eps=1e-8
)
python
18.6 AdamW#
optimizer = torch.optim.AdamW(
model.parameters(),
lr=1e-4,
betas=(0.9, 0.999),
weight_decay=0.01
)
python
18.7 AdamW + AMSGrad#
optimizer = torch.optim.AdamW(
model.parameters(),
lr=1e-4,
amsgrad=True
)
python
19. 一句话总结每个优化器#
SGD#
Momentum#
把历史梯度方向累积成动量,稳定方向加速,震荡方向抵消。
text
AdaGrad#
每个参数根据历史梯度平方调整学习率,历史梯度越大,后续学习率越小。
text
RMSProp#
用近期梯度平方的滑动平均调整学习率,避免 AdaGrad 后期学习率过小。
text
Adam#
用 Momentum 管方向,用 RMSProp 管步长,再用偏差修正解决训练初期估计偏小。
text
AdamW#
在 Adam 基础上解耦 weight decay,是现代深度学习最常用的默认优化器之一。
text
AMSGrad#
限制二阶动量不下降,防止 Adam 的有效学习率突然增大。
text
20. 最终主线记忆#
优化器的发展可以记成一句话:
SGD 只看当前梯度;
Momentum 加入历史方向;
AdaGrad 给每个参数自适应学习率;
RMSProp 让 AdaGrad 忘掉太久远的历史;
Adam 把 Momentum 和 RMSProp 结合;
AdamW 让 weight decay 更合理;
AMSGrad 让 Adam 的有效学习率更稳定。
text
最重要的理解是:
优化器不是魔法,它本质上在决定四件事:
1. 往哪个方向走;
2. 每个方向走多大;
3. 历史梯度如何影响现在;
4. 如何避免训练初期和后期的不稳定。
text
实际深度学习中,最稳妥的默认组合是:
AdamW + warmup + cosine decay
text
经典 CNN 分类任务中,SGD + Momentum 仍然值得作为强基线。
严谨实验不应该只比较优化器名字,还应该同时比较:
学习率
weight decay
scheduler
batch size
训练轮数
数据增强
冻结策略
分组学习率
text