共计 1794 个字符,预计需要花费 5 分钟才能阅读完成。
背景痛点:梯度下降的局限性
传统梯度下降(SGD)在深度学习训练中存在几个典型问题:
- 非凸函数优化困难 :神经网络的损失函数往往是非凸的,SGD 容易陷入局部最优或鞍点
- 学习率敏感 :固定学习率可能导致收敛缓慢(学习率太小)或震荡(学习率太大)
- 稀疏数据表现差 :对于稀疏特征(如 NLP 中的词向量),所有参数使用相同学习率会导致更新不均衡
一个直观的例子是当损失函数存在 ” 峡谷 ” 地形时(一个维度陡峭,另一个维度平缓),SGD 会沿着陡峭方向震荡前进。
优化算法对比
| 算法 | 内存占用 | 收敛速度 | 超参数敏感性 | 适用场景 |
|---|---|---|---|---|
| SGD | 低 | 慢 | 高 | 小批量数据 |
| Momentum | 中等 | 中等 | 中等 | 需要突破局部最优 |
| RMSprop | 中等 | 快 | 低 | 非平稳目标函数 |
| Adam | 高 | 很快 | 很低 | 默认首选 |
Adam 算法原理
Adam 结合了动量(Momentum)和自适应学习率(RMSprop)的思想,核心公式:
- 计算梯度的一阶矩估计(动量项):
$$m_t = \beta_1 m_{t-1} + (1-\beta_1)g_t$$ - 计算梯度的二阶矩估计(自适应项):
$$v_t = \beta_2 v_{t-1} + (1-\beta_2)g_t^2$$ - 偏差修正(初始阶段补偿):
$$\hat{m}_t = \frac{m_t}{1-\beta_1^t}$$
$$\hat{v}_t = \frac{v_t}{1-\beta_2^t}$$ - 参数更新:
$$\theta_t = \theta_{t-1} – \eta \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon}$$
其中 $\beta_1$ 通常取 0.9,$\beta_2$ 取 0.999,$\epsilon$ 为防止除零的小常数(1e-8)。
PyTorch 实现示例
import torch
from torch import nn
from torchvision import datasets, transforms
# 初始化模型和优化器
model = nn.Sequential(nn.Linear(784, 128),
nn.ReLU(),
nn.Linear(128, 10)
)
optimizer = torch.optim.Adam(model.parameters(),
lr=0.001,
betas=(0.9, 0.999), # beta1 和 beta2
eps=1e-8,
weight_decay=0.01, # L2 正则化
amsgrad=False
)
# 梯度裁剪
max_norm = 1.0
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm)
# 学习率预热
warmup_steps = 1000
scheduler = torch.optim.lr_scheduler.LambdaLR(
optimizer,
lr_lambda=lambda step: min(1.0, step / warmup_steps)
)
MNIST 实验对比
使用相同超参数(batch_size=128, lr=0.001)训练 3 层 MLP:
- SGD:loss 下降平稳但缓慢,100 epoch 后 test acc=97.2%
- Momentum:前期收敛快,后期有轻微震荡,test acc=97.8%
- Adam:最快收敛,test acc=98.1%

常见问题解决方案
- 训练后期震荡 :
- 动态调整 beta1(如从 0.9 线性衰减到 0.8)
-
增加 epsilon 值(如从 1e- 8 调整到 1e-6)
-
显存溢出 :
-
使用梯度累积:每 N 个 batch 更新一次参数
loss.backward() if (i+1) % 4 == 0: # 每 4 个 batch 更新 optimizer.step() optimizer.zero_grad() -
过拟合 :
- 早停机制:验证集 loss 连续 3 次不下降时停止
- 模型检查点:保存验证集表现最好的模型
延伸思考
- Adam 是否适合所有任务?在强化学习等非平稳问题中,有研究指出 SGD 可能更稳定
- Transformer 训练为何常用 AdamW?因为传统的 weight decay 在 Adam 中实现不准确,AdamW 将其解耦
总结建议
对于大多数深度学习任务,Adam 是很好的默认选择。但在以下情况建议考虑其他方法:
- 需要极致的模型精度时(如竞赛):尝试 SGD+Momentum
- 训练资源非常有限时:使用 RMSprop
- 处理特殊架构(如 GAN):可能需要混合不同优化器
调参时可以先用 Adam 快速验证模型可行性,再根据需求切换到更精细的优化策略。
正文完
