1-优化算法
1. 优化问题的基本形式
神经网络的训练目标是最小化经验风险:
其中
参数更新的通用形式是对
其中
2. 梯度下降的统一更新框架
所有自适应学习率方法都可以写成如下统一形式:
其中:
是一阶矩估计(first moment),梯度的某种滑动平均,替代原始梯度 是二阶矩估计(second moment),梯度平方的某种滑动平均,用于归一化更新幅度 是防止除零的小常数(通常 ) - 具体算法由
和 的更新方式决定
3. 各优化算法详解
3.1 SGD(随机梯度下降)
基本形式
SGD 使用随机梯度(mini-batch 梯度)代替完整数据集的梯度:
其中
收敛性分析
使用随机梯度而非真实梯度的代价是:
SGD 的收敛速度(在凸函数下)为
为什么 SGD 泛化更好
有研究指出,SGD 的噪声使参数在损失曲面上探索,而非精确收敛到平坦的极小值点。平坦(flat)的极小值点通常泛化能力更强,而 sharp 的极小值点虽然训练 loss 更低,但泛化性能差。SGD 的噪声相当于一种隐式正则化,推动模型趋向平坦区域。
实战经验
SGD 收敛较慢,需要仔细调学习率衰减(learning rate schedule)。典型配置:初始
3.2 Momentum(动量法)
为什么需要动量
在山谷地形中,如果梯度在不同方向上交替变化(如在狭长的峡谷中来回振荡),纯 SGD 的每一步更新都会抵消之前的部分进步,收敛极慢。Momentum 引入”速度”的概念,让更新方向带有历史惯性,从而在正确方向上加速,在振荡方向上抵消。
数学推导
设速度
其中
由于
物理直觉
Momentum 模拟物理中的动量:参数更新类似于一个有质量的物体在损失曲面(重力场)上滚动,惯性使它不会在每个山谷震荡处停下来,而是沿着谷底滑行。
对 SGD 的改进效果
- 加速收敛:相同 epoch 数下,动量 SGD 的 loss 通常低于普通 SGD
- 减少振荡:在峡谷地形中,正交于峡谷方向的梯度被历史速度抵消
- 跳出局部最优:惯性使模型有机会冲出浅的局部最优
实战经验
3.3 Nesterov Momentum
与标准动量的区别
标准 Momentum 在当前位置计算梯度,然后加上历史速度的方向做更新。Nesterov 提前一步”lookahead”:先按历史速度方向探索,再用那个位置的梯度做修正:
区别在于:标准动量的梯度在
为什么 Nesterov 更有效
Nesterov 的梯度包含了对”即将到来的速度”的修正。当参数即将overshoot 时,Nesterov 提前感知到梯度变化(因为已经往那个方向走了一步),并提前施加反向修正。这使得 Nesterov 比标准动量更早地稳定在极小值点附近,收敛更快、更稳定。
收敛速度的理论保证
在强凸函数下,标准 Momentum 的收敛速率是
实战经验
Nesterov 在理论上有优势,但实践中与标准 Momentum 的差异在小批量(small batch)训练中不明显。当 batch size 较大、梯度噪声较小时,Nesterov 的优势才显著。PyTorch 的 SGD(..., nesterov=True) 实现 Nesterov 动量,使用公式:
(具体实现与上述推导等价,但形式略有不同,需注意 PyTorch 文档)
3.4 AdaGrad(Adaptive Gradient)
为什么需要自适应学习率
不同参数在训练中需要的更新幅度差异巨大:Embedding 层的梯度通常较小且稀疏,MLP 的梯度较大且密集。若使用统一学习率,某些参数更新不足(欠拟合),某些参数更新过度(振荡/发散)。
AdaGrad 的核心思想:对频繁更新的参数使用小学习率,对稀疏更新的参数使用大学习率。
数学推导
AdaGrad 对每个参数维护一个累积梯度平方和
其中
解释:若参数在历史上经常收到大的梯度,则
问题:梯度平方的累积导致学习率衰减
AdaGrad 的问题是
实战经验
AdaGrad 在稀疏数据、在线学习场景表现良好。但在深度学习(深层网络、长期训练)中几乎不用,因为训练到后期所有参数的学习率都被压到极低。若必须使用 AdaGrad,建议在深度网络中留有一定余量(不要训练到完全收敛)。
3.5 RMSProp(Root Mean Square Propagation)
解决 AdaGrad 累积问题
RMSProp 引入了指数滑动平均来替代 AdaGrad 的无界累积,从而让二阶矩估计保持”跟踪近期梯度方差”的能力,而不被历史梯度主导:
其中
为什么叫 “Root Mean Square”
归一化因子
与 AdaGrad 的关键区别
AdaGrad 累积所有历史梯度平方(单调递增),而 RMSProp 用 EMA 让旧的梯度平方逐渐衰减。这意味着 RMSProp 可以适应非平稳目标(non-stationary):训练过程中损失曲面的曲率变化时,RMSProp 可以跟踪这种变化,而 AdaGrad 不行。
实战经验
3.6 Adam(Adaptive Moment Estimation)
综合一阶与二阶自适应
Adam 整合了 Momentum 的一阶矩估计和 RMSProp 的二阶矩估计,同时解决两个问题:梯度方向(动量)和梯度量级(自适应学习率)。
数学推导
一阶矩估计(动量):
二阶矩估计(自适应学习率):
偏差修正
由于
因此需要进行偏差修正(bias correction):
当
参数更新:
物理直觉
:梯度的方向(往哪个方向走) :梯度的”能量”(步幅多大) :归一化后的方向向量,模长由 控制,方向由动量决定
Adam 的优点
- 超参数默认效果好:
在大多数任务中不需要调参即可工作 - 适合大规模训练:二阶矩的自适应学习率使训练稳定,大 batch 下收敛快
- 适合稀疏梯度:对稀疏参数(如 Embedding)的学习率自适应调整
实战经验
Adam 的默认配置几乎”开箱即用”,是快速原型实验的首选优化器。但很多实验性研究(Fudan Vision Lab 的研究等)表明,在最终部署模型的训练中,SGD + Momentum 的泛化能力通常更好,尤其在视觉分类任务上。Adam 适合在以下场景使用:(1)需要快速验证想法的初期实验;(2)模型结构复杂、用 SGD 需要仔细调学习率衰减的情形;(3)训练大模型时作为 warmup 阶段。
3.7 AdamW(Adam with Weight Decay)
问题引入:L2 正则化 vs 权重衰减
Adam 原生支持 L2 正则化,方式是在梯度上加上
然后执行标准 Adam 更新。这相当于在损失函数中加入
但 AdamW 论文(Loshchilov & Hutter, 2019)指出:L2 正则化 ≠ 权重衰减。两者在标准 SGD 中等价(因为 SGD 的更新天然带有
AdamW 的修正
AdamW 的权重衰减直接作用于参数:
即在参数更新时直接减去
为什么 AdamW 更有效
设参数
AdamW 与 SGD + L2 的关系
在 SGD 中,权重衰减和 L2 正则化是等价的(因为
实战经验
AdamW 是 Transformer 训练的标准优化器(BERT、GPT、LLaMA 等均使用 AdamW)。权重衰减参数
4. Adam 训练快但泛化未必最好的原因
4.1 理论分析
Adam 的自适应学习率使每个参数在训练初期就获得较大的有效学习率(因为二阶矩估计在初期较小),这导致快速收敛到某个局部最优,但这个最优未必是泛化能力最强的那个(recall:SGD 的噪声帮助跳出 sharp 的局部最优)。
SGD 在训练初期由于动量尚未累积,参数更新相对保守,在损失曲面上探索更长时间,最终可能收敛到更平坦(flat)的区域。
4.2 经验观察
- 在 ImageNet 分类、COCO 目标检测 等视觉任务上,SGD + Momentum 的最终测试准确率通常高于 Adam 1~3%。
- 在 NLP 生成模型、Transformer 上,AdamW 是标准配置,此时泛化差距不明显,可能因为:Transformer 架构本身表达能力足够强,Adam 的自适应学习率足够稳定;或者预训练任务的标签弱(语言建模),不需要 SGD 那种隐式正则化效果。
- 在 小数据集、少样本学习 场景,SGD 的隐式正则化更宝贵,应优先用 SGD。
5. 任务特性与优化器适配
5.1 稀疏梯度 → Adam / AdaGrad
稀疏梯度意味着某些参数(如 Embedding)只在少数样本上更新。Adam 的二阶矩归一化自动对这些稀疏参数保持大学习率,避免更新不足。SGD + Momentum 对稀疏参数的处理不友好——稀疏参数可能因为长时间无梯度而完全”死掉”。
5.2 非平稳目标(Non-stationary Objective)→ RMSProp / Adam
非平稳目标指损失曲面的曲率随训练不断变化(如课程学习、RL 的奖励变化)。AdaGrad 的单调累积无法跟踪这种变化,RMSProp 和 Adam 的 EMA 形式可以动态跟踪,适时调整学习率。
5.3 噪声梯度 → SGD / SGD + Momentum
大 batch 训练时梯度噪声小,用 Adam 可快速收敛;小 batch 时梯度噪声大,SGD + Momentum 的噪声帮助探索,可以得到更好的泛化。实践中,batch size 从 32 降到 8 时,Adam 和 SGD 的性能差距会缩小。
5.4 特定任务的优化器偏好
| 任务 | 推荐优化器 | 理由 |
|---|---|---|
| 视觉分类(ResNet 等) | SGD + Momentum | 泛化更好 |
| 目标检测(检测头) | SGD + Momentum | 检测头训练通常用 SGD |
| Transformer / BERT / GPT | AdamW | 权重衰减、标准配置 |
| RNN / LSTM | RMSProp / Adam | 非平稳梯度,二阶矩自适应 |
| 强化学习(PPO/A3C) | Adam(常用 Adam) | 梯度噪声大但不稳定,Adam 默认配置省心 |
| 少样本学习 | SGD + Momentum | 噪声正则化珍贵 |
| 词嵌入训练 | AdaGrad / Adam | Embedding 稀疏,Adam 自适应学习率 |
6. 工程实践
6.1 优化器选择建议
选择决策流程:
- 快速原型 / 深度实验初期 → 选 Adam / AdamW,默认超参数,通常 5~10 分钟就能看到 loss 下降
- 视觉分类 / 检测 / 分割 → 选 SGD + Momentum,跑完整训练 schedule
- Transformer / 生成模型 → 选 AdamW,
按任务调 - Embedding 相关的任务 → 选 Adam 或 AdaGrad
- 若 Adam 泛化不好 → 切换 SGD + Momentum,配合 learning rate warmup
6.2 超参数设置建议
Adam / AdamW
| 超参数 | 常见取值 | 说明 |
|---|---|---|
| 默认 | ||
| 通常不调 | ||
| 通常不调;对收敛有影响时(如训练极长)可设为 | ||
| 通常不调;若数值不稳定(如混合精度训练)可设为 | ||
| AdamW 专用;若用 L2 正则化则效果弱于 weight decay | ||
| 常用 linear warmup 1000~10000 步 | 防止初始阶段梯度过大,尤其 Transformer | |
| 通常配合 cosine decay 或 constant | Adam 通常不需要 decay;若衰减则用 cosine |
SGD + Momentum
| 超参数 | 常见取值 | 说明 |
|---|---|---|
| 通常比 Adam 大 10~100 倍;需配合 schedule | ||
| momentum | 通常不调 | |
| weight decay | L2 正则化(与 SGD 天然等价) | |
| schedule | step decay(每 30 epoch 乘 0.1)或 cosine | SGD 必须配合衰减,Adam 通常不需要 |
| Nesterov | True / False | 对 sharp 极小值有轻微帮助;通常设为 True |
6.3 常见问题排查
问题 1:Loss 不下降(训练完全停滞)
诊断:学习率过小?梯度消失?
- 检查梯度范数:若各层梯度范数
,很可能是梯度消失。检查激活函数(是否饱和)、初始化(是否 Xavier/He)、归一化层(BatchNorm gamma 是否为 1) - 若梯度正常但 loss 不降:学习率可能太小;尝试 10 倍大学习率
解决方案:
- 学习率过低 → 增大学习率(Adam:
,SGD: ) - 梯度消失 → 检查激活函数和初始化;必要时换 ReLU / He 初始化
- 参数初始化错误 → BatchNorm 的
设为 1, 设为 0
问题 2:Loss 振荡(不收敛但也不停滞)
诊断:学习率过大?Batch size 太小?
- 观察 loss 曲线:若振荡幅度大但趋势向下(缓慢下降),学习率可能略大
- 若振荡剧烈且无下降趋势:学习率过大或梯度爆炸
解决方案:
- 学习率略大 → 降低学习率 2~5 倍
- Batch size 太小 → 若显存允许,增大 batch size(梯度噪声减小)
- 启用梯度裁剪(
clip_grad_norm(1.0)):防止梯度爆炸 - Adam 中若
过小(接近 0.9),二阶矩估计不稳定,改为
问题 3:Loss 发散(变为 NaN / Inf)
诊断:数值爆炸、学习率过大、损失函数数值不稳定
- 梯度爆炸:启用梯度裁剪,
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) - 学习率爆炸:检查学习率是否设置正确(如误将
用于 Adam) - Softmax/BCE 数值不稳定:检查 logits 范围;若过大(>
),对 logits 做裁剪或用框架的安全实现
解决方案:
- 立即降低学习率为原来的 1/10
- 若 loss 已经 NaN,重新初始化,用更低学习率重启
- 混合精度训练(AMP)可以缓解某些数值问题
问题 4:训练后期停滞(Loss 降到平台后不再下降)
诊断:学习率衰减到过小?陷入局部最优?
- 若 loss 曲线在平台期前有明显下降,然后完全水平:学习率衰减到过小,或参数进入 plateau
- 若 loss 在平台前有振荡:可能是 sharp 极小值,学习率在 plateau 后无法推动参数跳出
解决方案:
- 学习率过早衰减 → 重训,使用更长的 warmup 或更慢的衰减(cosine decay)
- 若确实是 plateau:使用 SGD 的噪声特性(切换到 SGD 最后一阶段);或尝试增加随机性(Dropout 增强)
- AdamW 中 weight decay 过大 → 降低
7. 优化器选择速查表
| 场景 | 推荐优化器 | 超参数建议 | 替代方案 |
|---|---|---|---|
| 快速原型 / 深度网络调参 | Adam / AdamW | — | |
| 视觉分类(ResNet, 分类网络) | SGD + Momentum | SGD + Nesterov( | |
| 目标检测(检测头) | SGD + Momentum | 同上 | — |
| Transformer / 大语言模型 | AdamW | — | |
| RNN / LSTM | Adam | RMSProp + Momentum | |
| 词嵌入训练(稀疏) | Adam | AdaGrad(在线学习) | |
| 强化学习(PPO/A3C) | Adam | — | |
| 少样本学习 | SGD + Momentum | — | |
| 大模型预训练(LLM/ViT) | AdamW + 分布式 | — |
8. 常见错误配置案例
案例 1:Adam 学习率过大
错误:直接用
后果:Adam 的自适应学习率已经将有效学习率缩小了数个量级,
正确做法:Adam 常用
案例 2:Adam + L2 正则化(而非 AdamW)
错误:对 Adam 使用 weight_decay 参数,实际上调用的是 L2 正则化(在梯度上加
后果:L2 正则化在 Adam 中被二阶矩归一化后衰减,有效正则化强度远弱于预期,无法达到期望的正则化效果。
正确做法:若使用 Adam 且需要权重衰减,使用 AdamW(torch.optim.AdamW),并设置 weight_decay=0.01。
案例 3:SGD 不使用学习率衰减
错误:使用 SGD + Momentum 但保持学习率恒定。
后果:SGD 的收敛依赖于学习率逐渐减小。恒定大学习率会导致参数在极小值附近持续振荡,无法收敛到稳定点。
正确做法:配合步衰减(每
案例 4:RNN 中误用 SGD
错误:对 LSTM 使用 SGD without momentum。
后果:RNN 的梯度在时间步上传播,噪声大且路径长,SGD 的收敛速度极慢且极易陷入局部最优或梯度消失/爆炸。
正确做法:使用 Adam(
案例 5:Adam 的 设置过小
错误:将
后果:
正确做法:
案例 6:训练 Transformer 时不做学习率 warmup
错误:直接使用
后果:Transformer 的残差连接在训练初期可能导致信号过大(尤其 pre-norm 架构),梯度在第一层可能爆炸或消失。Warmup 让参数在训练初期以小学习率缓慢调整,避免极端梯度。
正确做法:使用 linear warmup(如 1000 步 warmup),然后用 cosine decay 或 constant。