优化器详解:从SGD到Adam的原理与参数调优

选择合适的优化器以及理解其背后的参数,往往决定了模型是能够快速收敛到最佳状态,还是在训练过程中产生“梯度爆炸”甚至完全无法收敛。本文将通俗地解释这些概念,并深入剖析 PyTorch 中常用优化器的关键参数。

1. 通俗理解:蒙眼下山

想象你被蒙住双眼,放置在一座高山上。你的目标是下到山谷的最低点——在深度学习中,这代表着让模型的损失函数 (Loss) 最小化。

优化器,就是你的下山策略



graph TD
    Start("山顶 (高 Loss)") --> Strategy{选择优化器}
    Strategy -- "SGD" --> Path1("固定步长,稳步试探")
    Strategy -- "Adam" --> Path2("自适应速度,智能调整")
    Path1 --> Goal("山谷 (低 Loss)")
    Path2 --> Goal

🚶 基础选手:SGD (随机梯度下降)

策略:用脚探一下当前的地面,感觉哪个方向是向下的,就往那个方向迈出固定的一步。

特点

  • 老实:它完全依赖当前的梯度方向。你设定多大的步长(学习率),它就走多远。
  • 稳健但缓慢:如果步长太小,下山速度极慢;如果步长太大,可能会在山谷震荡甚至跑偏。
  • 优势:在计算机视觉(CV)任务中(如 ResNet 训练),SGD 往往能找到更平坦、泛化能力更强的极小值点。

🏎️ 进阶选手:Adam (自适应矩估计)

策略:它不仅看当前的坡度,还"记得"之前的速度(动量),并且会根据地形的复杂程度自动调整步子大小。

  • 平坦路段:自动加速。
  • 陡峭悬崖:自动减速,防止冲过头。

特点

  • 智能:结合了动量(Momentum)和自适应学习率(RMSprop 的思想)。
  • 快速:收敛速度通常远快于 SGD。
  • 劣势:对“初始推力”(学习率)非常敏感,且在某些 CV 任务上,最终的泛化性能可能不如精心调教的 SGD。

2. 深入剖析:关键参数与含义

在 PyTorch 中,我们通常通过 torch.optim 来调用这些优化器。理解每个参数的物理含义,是避免“炼丹”失败的关键。

SGD 的关键参数

1
optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9, weight_decay=1e-4)
  1. lr (Learning Rate, 学习率)
    • 含义:下山的“步长”。
    • 通俗解释:决定了你每一次更新参数时变化有多大。
    • 典型值0.1, 0.01。SGD 需要较大的 lr 才能推动模型前进。
  2. momentum (动量)
    • 含义:模拟物理中的“惯性”。
    • 通俗解释:如果之前一直是下坡,那么这次不仅要看当前的坡度,还要加上之前的速度冲下去。这有助于冲过局部的平坦区域(鞍点)或小坑。
    • 典型值0.9。这意味着当前的更新方向有 90% 来自之前的积累,10% 来自当前的梯度。
  3. weight_decay (权重衰减)
    • 含义:L2 正则化。
    • 通俗解释:一种“惩罚机制”。为了防止模型为了拟合数据而变得过于复杂(参数值过大),我们在损失函数里加了一项惩罚。它就像给模型加了“刹车”,防止过拟合。
    • 典型值1e-4 (0.0001) 或 5e-4

Adam 的关键参数

1
optimizer = torch.optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999), eps=1e-8)
  1. lr (Learning Rate)
    • 注意:Adam 的学习率通常比 SGD 小得多。
    • 典型值0.001 (1e-3) 或 3e-4。这是因为 Adam 内部会自动根据梯度的一阶矩和二阶矩放大更新幅度。
  2. betas (Beta1, Beta2)
    • 含义:控制两个“记忆”的衰减率。
    • beta1 (默认 0.9):对应 一阶矩估计(即动量 Momentum)。控制“惯性”保持多久。
    • beta2 (默认 0.999):对应 二阶矩估计(即梯度的平方)。用来衡量“路况”的平稳程度,从而实现自适应步长。
    • 调参建议:通常保持默认即可。
  3. eps (Epsilon)
    • 含义:数值稳定性项。
    • 作用:防止分母为零。在计算自适应步长时,分母是梯度的平方根,加一个极小数 eps 避免除零错误。

3. 实战避坑:为什么会“梯度爆炸”?

在实际开发中,一个最常见的错误就是将 SGD 的经验直接套用到 Adam 上

典型事故现场

假设你习惯了训练 ResNet,配置了 lr=0.1。然后你想尝试一下 Transformer,于是把优化器改成了 Adam,但忘记了修改学习率



graph TD
    Config["配置: Adam 优化器"] --> Input["输入: SGD 级别的学习率 (0.1)"]
    Input -- "对于 Adam 来说" --> Mechanism["Adam 内部的自适应放大机制"]
    Mechanism --> Result["实际更新步长过大 (相当于 SGD 的 100 倍)"]
    Result --> Boom["参数变为 NaN / Infinity"]
    Boom --> Loss["Loss 震荡或不收敛"]

原因分析: Adam 自带“助推器”(自适应调整)。对于 Adam 来说,0.001 已经是很快的速度了。如果你给它 0.1 的初始推力,相当于给一辆法拉利加了火箭燃料,瞬间就会因为步长过大冲出赛道,导致参数变成 NaN (Not a Number) 或无穷大。

修正方案: 一旦切换到 Adam,务必将学习率降低 1-2 个数量级(从 0.1 降到 0.001)。


4. 选型指南:我该用哪个?

没有绝对的“最好”,只有“最适合”。

✅ 选择 SGD 的场景

  • 任务:计算机视觉标准任务(图像分类、物体检测、分割)。
  • 代表模型:ResNet, VGG, YOLO。
  • 理由:虽然收敛慢,需要配合学习率衰减策略(Learning Rate Scheduler),但往往能收敛到更优的解,测试集准确率更高。
  • 推荐配置SGD(lr=0.1, momentum=0.9, weight_decay=5e-4)

✅ 选择 Adam 的场景

  • 任务:自然语言处理(NLP)、强化学习、生成对抗网络(GAN)、或快速原型开发。
  • 代表模型:Transformer, BERT, GPT, ViT。
  • 理由:收敛速度极快,对超参数(Hyper-parameters)不那么敏感,开箱即用。
  • 推荐配置Adam(lr=1e-3)AdamW(lr=3e-4)

💡 小贴士:AdamW 是什么?

你可能会在现在的代码中经常看到 AdamW。它是 Adam 的修正版。简单来说,Adam 在处理 weight_decay(权重衰减)时存在一个理论上的 Bug,AdamW 修复了这个问题,使得它在训练 Transformer 等大模型时效果更好、更稳定。


总结

  • SGD 像手动挡赛车,上限高,但需要精细的油门控制(调参)。
  • Adam 像自动挡跑车,起步快,省心,但在某些赛道上可能不如手动挡精准。
  • 切记:换车(优化器)的时候,千万别忘了换挡(调整学习率)!

5. 拓展:其他常见优化器一览

除了 SGD 和 Adam,深度学习工具箱中还有许多其他优化器。了解它们有助于在特定场景下做出更合适的选择。

📊 RMSprop (Root Mean Square Propagation)

诞生背景:为了解决 AdaGrad 学习率过早衰减的问题。

核心思想:使用梯度的移动平均平方(而非累积平方)来调整学习率,这样可以让学习率在训练后期仍然保持活力。

下山比喻:就像一个经验丰富的登山者,会根据最近一段路的情况(而不是整段路程)来判断下一步的步长。

1
optimizer = torch.optim.RMSprop(model.parameters(), lr=0.01, alpha=0.99)

关键参数: * lr:学习率,典型值 0.01 * alpha:平滑常数,控制历史梯度的衰减速度,默认 0.99

适用场景:RNN(循环神经网络)训练,是 Adam 出现之前的主流选择。


📈 AdaGrad (Adaptive Gradient)

核心思想:为每个参数维护一个累积的梯度平方和,频繁更新的参数会获得更小的学习率,稀疏参数会获得更大的学习率。

下山比喻:如果某个方向你经常走(梯度大),说明这个方向可能已经接近目标了,就放慢脚步;如果某个方向很少走(梯度小),就加快探索。

1
optimizer = torch.optim.Adagrad(model.parameters(), lr=0.01)

特点: * 优点:对稀疏梯度友好,适合处理稀疏数据。 * 缺点:学习率会单调递减,训练后期可能过小导致无法继续学习。

适用场景:自然语言处理中的稀疏特征学习,但现在已较少使用。


🔄 AdaDelta

诞生背景:AdaGrad 的改进版,解决了学习率过早衰减的问题。

核心创新:不需要手动设置学习率!它会根据参数更新的历史信息自动调整。

下山比喻:完全自动驾驶,不仅会根据路况调整速度,还会根据之前走过的路来预测下一步该走多远。

1
optimizer = torch.optim.Adadelta(model.parameters(), rho=0.9)

关键参数: * rho:衰减率,控制历史信息的权重,默认 0.9

特点: * 优点:无需设置学习率,对超参数不敏感。 * 缺点:收敛速度可能较慢,实际使用中不如 Adam 受欢迎。


⚡ AdamW (Adam with Weight Decay Fix)

核心改进:修复了 Adam 在处理权重衰减(Weight Decay)时的理论缺陷。

技术细节:在原始 Adam 中,weight_decay 被错误地应用到了梯度上,而不是直接应用到参数上。AdamW 将权重衰减与梯度更新解耦,使得正则化效果更符合 L2 正则化的原始意图。

下山比喻:Adam 在刹车(权重衰减)时,刹车片和油门混在一起了;AdamW 把刹车系统独立出来,刹车更精准。

1
optimizer = torch.optim.AdamW(model.parameters(), lr=3e-4, weight_decay=0.01)

关键参数: * lr:学习率,典型值 3e-4(比 Adam 稍小) * weight_decay:权重衰减,典型值 0.01(可以比 Adam 中设置得更大)

适用场景: * Transformer 模型:BERT、GPT 等大模型的标准选择 * 计算机视觉:ViT(Vision Transformer)等 * 现代深度学习:几乎成为新项目的默认选择

为什么现在更推荐 AdamW? 1. 理论更严谨:权重衰减的实现方式更符合数学原理 2. 泛化性能更好:在大多数任务上测试集表现更优 3. 超参数更稳定:对 weight_decay 的敏感性更低


🎯 其他新兴优化器

NAdam (Nesterov-accelerated Adam)

结合了 Nesterov 动量和 Adam 的优点,在收敛速度和稳定性之间取得更好的平衡。

RAdam (Rectified Adam)

解决了 Adam 在训练初期可能不稳定的问题,通过动态调整学习率来保证训练的稳定性。

Lookahead

一种元优化器,可以包装在任何优化器(如 Adam、SGD)外面,通过"向前看"的策略来稳定训练过程。


📋 快速对比表

优化器 学习率需求 收敛速度 超参数敏感性 主要应用
SGD 较大 (0.1) CV 任务 (ResNet)
Adam 较小 (0.001) NLP、GAN、快速原型
AdamW 较小 (3e-4) Transformer、现代大模型
RMSprop 中等 (0.01) RNN(历史选择)
AdaGrad 中等 (0.01) 慢(后期) 稀疏数据(较少使用)
AdaDelta 无需设置 理论研究(较少使用)

💡 实用建议

  1. 新手入门:直接使用 AdamW(lr=3e-4),这是 2024 年最稳妥的选择。
  2. CV 任务追求极致:尝试 SGD(lr=0.1, momentum=0.9) 配合学习率调度器。
  3. 大模型训练:优先考虑 AdamW,配合 weight_decay=0.1
  4. 实验阶段:先用 AdamW 快速验证想法,再根据任务特点微调。

记住:没有万能的优化器,只有最适合你任务的优化器。理解原理比盲目选择更重要!