资讯动态

从SGD到AdamW:深度学习优化器核心原理与实战避坑指南

发布时间:2026/10/20 3:30:42 来源:尧图企业网站定制
训练深度学习模型这几年我见过太多人把精力都花在网络结构设计上却在优化器选择上特别随便。尤其当你从 SGD 一路试到 Adam、再换成 AdamW会慢慢意识到一件事优化算法不是流水线上一个无关紧要的旋钮它几乎决定了你的模型到底能不能收敛、收敛到什么地方、以及泛化能力是及格还是优秀。这篇文章我想用实际训练中的视角把从 SGD 到 AdamW 这一路上的关键原理、踩坑细节和排查思路讲清楚适合刚接触深度学习、正在被损失曲线折磨的初学者也适合那些已经跑通不少模型、但对优化器内部机制仍然模棱两可的同学。1. 为什么优化算法决定训练成败1.1 优化器不是“调参玩具”很多人第一次接触 PyTorch 或 TensorFlow 时第一行代码大概率是Adam因为教程里默认给的就是这个。但如果你把优化器当成一个不用思考的“黑盒”损失函数不降的时候就会非常被动。实际上优化器的作用远比“把梯度往反方向走一步”更复杂它要解决的是在损失曲面这种高维、非凸、充满鞍点和局部极小值的复杂地形上如何用有限的计算资源找到一个足够好的解。我经常用一个类比来解释这件事梯度下降就像是蒙着眼睛在山谷里下山你能感觉到脚下哪个方向最陡但不知道整个地形长什么样。如果步长太大你可能会直接跨过山谷对面的缓坡甚至跳到悬崖下面如果步长太小你在平缓的鞍点区域可能磨上几千轮都没什么进展。而不同优化器的本质差异就是它们对“步长”和“方向”的估计方式不同。SGD 只看当前梯度方向动量方法会参考历史速度自适应方法则对每个参数维度单独调整步长。从这个角度看优化器选型就不是“哪个好用用哪个”而是根据你项目的任务类型、数据规模、模型结构去选择一个与损失曲面特性匹配的更新规则。理解这一点后面再调试模型时就不会一头雾水。1.2 从损失曲面读懂优化目标模型训练的终极目标并不是让训练损失无限逼近零而是在验证集上表现稳定。这就意味着优化算法不仅要把损失压低还要压低得“恰到好处”。在超高维空间中我们几乎不可能可视化真正的损失曲面但从实验规律中可以总结出一些共性平滑但扁平的极小值区域往往对应更好的泛化性能尖锐的极小值区域很容易过拟合而鞍点附近的梯度很小很多非自适应优化器会在这里停滞不前。这也是为什么 SGD 和 Adam 的表现会出现明显差异。SGD 的更新路径通常更“直”它更容易穿越尖锐峡谷后落在比较平坦的区域而自适应优化器因为每个参数更新幅度被归一化常常能找到更快的下降路径但也可能收敛到泛化稍差的尖锐区域。当然这不是绝对规律只是从大量实验里看到的倾向。理解这个背景再看 AdamW 这类变体就会明白大家为什么那么执着于“恢复 SGD 的泛化优点同时保留自适应优化器的训练效率”。2. SGD最朴素的梯度下降也是最容易踩坑的起点2.1 批量大小与学习率的互相牵制标准 SGD 的更新公式看起来简单θ θ - lr * g这里g是当前批次算出来的梯度。问题在于这个更新同时受学习率和批次大小影响。如果你把批次翻倍梯度的方差通常会变小但梯度本身的量级不会严格减半所以最优学习率可能也要跟着调整。很多同学第一次训练 CNN 时固定用 64 的 batch size把学习率设为 0.01模型还能跑一旦为了加速训练把 batch size 改成 256如果不调学习率训练反而开始震荡甚至发散。我自己的经验是在换 batch size 之后可以先粗略用“线性缩放规则”做参考批次变为原来的 k 倍学习率初始值也可以往 k 倍方向试探但上下浮动一两倍都很正常不能死记公式。更重要的是SGD 对特征缩放特别敏感。如果输入没有做标准化或者网络某一层的参数初始化尺度差异很大不同维度的梯度量级可能差出好几个数量级这时用同一个学习率更新所有参数效果一定很差。所以在用 SGD 之前一定要确认数据归一化和参数初始化策略是稳妥的。不要一上来就怪优化器不收敛很多时候是前面的数据管线已经在拖后腿了。2.2 动量到底解决了什么纯 SGD 在遇到局部震荡时更新方向会被当前批次噪声带着到处乱跑。动量Momentum的引入就像给下山的人加了一个惯性每一步不只是看当前脚下的梯度还要结合之前速度的方向和大小。物理意义很简单它让更新方向在历史信息中平滑化能加速沿一致方向的移动同时抑制方向频繁变化的抖动。具体实现上多数框架中的动量项并不复杂维护一个速度变量v更新时v momentum * v g然后用θ θ - lr * v。动量系数通常取 0.9 或 0.99相当于把过去大约1 / (1 - momentum)步的梯度信息纳入考虑。很多人只把这个参数当固定的“稍微好用一点”的开关但实际调试时它和学习率是协同作用的。动量越大有效学习率也会变大因此如果你把 momentum 从 0.9 改成 0.99学习率可能需要适当调小。我在实际项目中用过一次高动量配置收敛速度确实快但损失曲线在后期出现了低频振荡。后面把动量降到 0.9并同步降低了学习率问题才消失。这说明即使是这么简单的超参数也需要放到整个训练配置里去看而不是孤立地调。3. Adam 为什么流行又为什么需要改3.1 自适应学习率的直觉Adam 的全称是 Adaptive Moment Estimation它把动量思想和自适应学习率结合到了一起。具体来说它既维护了梯度的一阶矩估计也就是类似动量的历史平均梯度也维护了梯度的二阶矩估计也就是历史梯度平方的平均。对于梯度比较大的维度二阶矩会变大更新步长会被压低对于梯度比较小或变化缓慢的维度二阶矩较小更新步长会相对放大。这样做的效果是每个参数维度的更新幅度大致被归一化模型对学习率的敏感度大幅下降。这解释了一个经典现象同样的学习率SGD 可能完全跑飞Adam 却能稳定训练。尤其是在 Transformer、GAN 这类模型上不同层、不同参数的梯度尺度差异非常大手动给每个层配学习率几乎不现实而 Adam 等于内置了这种“按维度缩放”的能力。所以它在 NLP 和生成模型领域几乎是默认选择不是没有道理的。但自适应学习率并不是免费的午餐。它的问题在于二阶矩估计本质上是基于历史梯度平方的调整如果历史梯度过大或过小会导致个别维度的更新步长被过度压缩或放大。尤其是在训练后期梯度变小、噪声占比升高Adam 容易出现“来回震荡但就是压不到更低误差”的状态。实际操作中我见过很多模型的 Adam 训练曲线呈现出“前期飞快、后期原地磨”的形状这和二阶矩长期累积后的尺度失衡有很大关系。3.2 Adam 的偏置校正和实际陷阱很多框架实现 Adam 时都包含偏置校正步骤因为前几步的一阶矩和二阶矩估计都从零开始如果直接用来更新初期步长会明显偏小。偏置校正在训练初期效果尤其明显它把前几步的矩估计放大到无偏状态。实际陷阱主要是两个。第一Adam 对学习率初始值虽然不像 SGD 那么敏感但也不是完全不敏感。我在项目里试过把学习率从默认的 0.001 调到 0.0001很多任务训练损失反而更稳定最终精度也没有明显下降。第二Adam 对权重衰减的处理方式藏了一个隐藏 bug 级别的细节传统实现里权重衰减直接加到梯度上相当于在更新时把 L2 正则项混入了自适应缩放过程。结果会导致权重衰减的效果被削弱尤其是配合大学习率时更明显。这也是 AdamW 出现的最直接动机。使用 Adam 时还有一个小经验如果你看到训练损失前期降得很快但验证指标一直不动先不要急着加大模型容量很可能不是模型不够强而是优化器把当前区域过早“锁死”在一个容易走但不够好的路径上。这时候把学习率调低、或者切换权重衰减策略比改网络结构更有效。3.3 AdamW解耦权重衰减的实用价值AdamW 的核心改动看起来很小把权重衰减从梯度里拿出来单独在参数更新时直接乘一个小于 1 的系数。但正是这么一点改动让权重衰减重新变成“真正的 L2 约束”而不是被自适应学习率扭曲的伪正则。从公式风格看传统 Adam 的权重衰减方式是先算出梯度g 原始梯度 weight_decay * θ再对这个合成梯度做一阶矩、二阶矩的更新和缩放。问题在于梯度里的这一项也会被二阶矩缩放。假设某个参数维度梯度一直很小它的二阶矩会很小更新的缩放因子反而很大最后权重衰减的实际力度会被放大到远超预期。AdamW 直接把权重衰减放在参数更新外层完全绕过自适应缩放这个现象就被解除了。在实践中AdamW 对很多任务都有正向帮助。我在图像分类、文本分类和对比学习模型上都做过对比AdamW 的验证精度普遍不低于同条件下 Adam有些任务还稳定高出一两个点。特别是在需要较长训练轮数的预训练或自监督场景AdamW 的后期稳定性明显更好。很多人一开始不习惯“只改一点点”的优化器变体但正是这种细节修正让 Adam 家族在实践中更可靠。4. 常见问题与排查技巧实录4.1 损失不降先查数据再查优化器训练开始后损失完全不动或者只降一小段就停住是最常见的问题之一。我自己的排查顺序通常是先看输入数据有没有有效信息再看标签有没有错位最后才怀疑优化器。有一次我用一个自建的图像数据做分类模型结构很常规优化器用 Adam学习率也是常见值。但跑了几个 epoch训练损失始终在某个数值附近横盘。排查到最后发现是数据读取时把图像像素值错误地在 [0, 255] 和 [0, 1] 之间来回变换导致有效特征几乎被噪声淹没。把数据归一化修好之后同一个优化器、同一个学习率损失立刻正常下降。如果数据没问题再从优化器角度检查学习率是不是太小权重初始化是不是把输出层推到饱和区梯度是不是有 NaN 或者极大值这些都可以通过打印梯度的统计信息快速定位。不要盲目把损失不降归咎于“优化器不够好”那样很容易越调越偏。4.2 训练震荡学习率预热和调度训练过程中损失上下剧烈跳动常见原因有几个学习率过大、batch size 过小、梯度中有大量异常值、或者是接近收敛时没有降低学习率。对 Transformer 这类模型来说学习率预热几乎是必需品因为前几步的梯度方差特别大直接进入正常学习率容易把早期的参数初始状态彻底搅乱。预热阶段先把学习率从很小线性升到目标值给参数一个相对稳定的起步过程。我常用的策略是先跑一个很小的多次实验观察损失曲线形态。如果前 100 步就开始数值震荡首先把学习率除以 3 再试如果震荡仍然明显就把预热步数从 1% 总步数提到 5% 左右。在这个阶段不要同时改一堆超参数一次只改一个否则你根本没法判断是哪个变动把曲线救回来了。学习率调度也一样等训练进入中段后按步数或按指标衰减比从头到尾固定学习率更符合大多数任务的收敛规律。4.3 收敛但泛化差权重衰减、梯度裁剪和正则训练损失降得不错验证集表现却差这是另一个高频问题。很多人把锅甩给“过拟合”然后疯狂加数据增强。但有时候问题出在优化器细节上比如 Adam 的权重衰减被削弱导致参数范数控制不足或者模型在训练后期还在用很大的学习率把权重推向了尖锐的极小值区域。AdamW 之所以在泛化对比中经常胜出一个重要原因正是恢复了有效的权重衰减机制。在训练后期配合余弦退火这类调度让学习率平滑下降通常能让模型在验证集上的表现再上一层。梯度裁剪则更多用在 RNN、Transformer 或者训练不稳定场景它不直接提升泛化能力但能防止某个异常梯度把已经学好的参数破坏掉间接帮助训练走得更远。我还试过在 AdamW 上把 weight decay 从 0.01 往 0.05 方向调整配合较小的数据增强结果在图像分类任务上的验证精度有一定提升。但这类调整必须跟着验证集来千万不要用训练集表现做判断否则你只是在优化一个过拟合指标。5. 真实项目中的选型建议5.1 图像模型、语言模型与小批量场景的优化器选择矩阵不同任务里优化器选型其实是很有规律的。图像分类、目标检测这类 CNN 任务很多经典研究都倾向用带动量的 SGD搭配合理的初始化、学习率调度和权重衰减泛化效果通常很稳。但如果你训练时间有限或者模型结构比较复杂AdamW 也完全能替代而且调试成本更低。语言模型、Transformer 类结构则更推荐 AdamW原因主要有两个这类模型参数量大不同位置的梯度尺度差异明显自适应学习率能让训练起步更顺同时权重衰减的解耦能有效控制参数范数对长时间预训练尤其友好。我训练中小规模的文本分类模型时默认配置就是 AdamW 0.01 权重衰减几乎不需要额外调优。小批量场景是另一个容易被忽略的坑。batch size 很小的时候每个 batch 的梯度噪声很大Adam 的优势更明显因为它通过二阶矩估算给噪声相对大的维度压低了步长。这时候如果硬要用 SGD通常需要搭配很强的手动调度和更长的训练时间并不划算。反过来如果你能用很大的 batch sizeSGD 配合动量反而可能更稳定。下面是我在实际项目里常用的一张参考表注意它只是一个出发点不是绝对真理场景推荐优化器常用学习率权重衰减备注CNN 图像分类大 batchSGD Momentum0.01 到 0.11e-4 到 5e-4需要较稳的调度CNN 图像分类小 batchAdamW1e-3 到 2e-30.01 到 0.05训练更快调试更省心Transformer 类 NLPAdamW5e-5 到 5e-40.01学习率预热基本必需生成模型 / GANAdamW2e-4 到 1e-30.01梯度裁剪视情况使用大规模预训练AdamW1e-4 到 3e-40.01 到 0.1长轮训练下稳定性优先5.2 参数搜索从粗到细的经验很多初学者一上来就做网格搜索把所有学习率、权重衰减、动量系数都排列组合跑一遍这样既烧时间又难看出规律。我的经验是先固定一个“大概率能跑通的配置”比如模型如果是 Transformer就先用 AdamW学习率 3e-4权重衰减 0.01预热几千步跑一个短的训练过程。确认训练损失能下降之后再开始微调超参数。调参时要有一个清晰的顺序先定性看优化器选型对不对再看学习率数量级然后看权重衰减最后才看调度细节。每次只动一个维度并记录验证集表现而不是只看训练损失。我有一个习惯每次实验都存下完整的超参数和损失曲线截图方便回头判断哪一个改动真正起了作用。有些时候你会发现验证集精度对学习率极其敏感但对权重衰减却不敏感。这并不代表权重衰减没用而是说明当前训练数据和模型容量之间暂时没有过拟合压力。真正有意义的是在模型容量足够大、训练轮数足够的条件下观察这些正则手段的效果。不然你只是在浪费时间调一个根本不会被触发的约束。6. 写在最后的一点个人体会把优化器从 SGD 理解到 AdamW不只是为了记住几个公式更重要的是建立一种直觉模型训练到底在解决什么形状的问题不同的更新规则又分别会走向哪里。我自己的习惯是在新项目里不急着选择最“高级”的优化器而是先用一个可靠的配置把整个数据管线、损失计算和评估流程跑通再回头验证不同优化器的差异。因为很多时候模型不收敛并不是优化器的问题而是数据、初始化、学习率调度共同作用的结果。另外我想分享一个实用小技巧训练时记录每一层梯度的均值和方差用日志或可视化工具展示出来比单纯盯一个全局损失要直观得多。梯度消失、梯度爆炸、某个模块完全没有学习信号这些都能从梯度统计上早期看出来。相比之下盲目换优化器反而容易掩盖真正的问题。深度学习优化算法这个方向还在继续演进但从 SGD 到 AdamW 这条主线已经足够覆盖绝大多数实际项目需求。把这条主线上的原理和坑都吃透以后再看任何新的优化器变体你都不会觉得陌生。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑