深度学习优化器全解析:从SGD到AdamW的选型调参避坑指南

发布时间:2026/9/30 8:44:34
深度学习优化器全解析:从SGD到AdamW的选型调参避坑指南 去年夏天我在调一个图像分类模型时遇到一件很诡异的事loss卡在1.2附近怎么都不肯往下走。我先后排查了数据增强、BatchNorm、网络结构最后把Adam的learning rate从默认的1e-3降到3e-4loss才继续下降。那一刻我才真正意识到Model-Optimizer模型优化器不是一个可以随便选默认值的组件它决定了你的模型是训练得又快又稳还是在一个不理想的状态里白白烧算力。这篇博文想把自己这几年在优化器上的理解整理成一份可复用的经验先讲清楚优化器到底在做什么、主流优化器的原理区别再给出一套可以直接参考的分场景选型配置最后把那些真正踩过的坑和最实用的排错思路写下来。无论你是刚入门深度学习的学生还是已经在工程里反复调loss的老手总有一两段能帮到你。1. 一次loss不降的排查让我重新审视优化器很多人训练模型第一反应是改网络结构、加数据、调loss function很少有人愿意回头查优化器。但优化器恰恰是训练系统里最容易被低估的一环。它做的事看起来简单——根据梯度更新参数可这一套更新规则里藏着收敛速度、稳定性和最终精度的绝大部分秘密。1.1 优化器到底管三件事把训练模型想象成下山。梯度告诉你哪边是下坡学习率决定你每一步走多远而优化器是那个带经验的向导负责组织这群人的步伐。它要同时解决三个问题方向准不准步子迈多大以及怎么在快和稳之间找平衡。方向准不准SGD只依赖当前梯度梯度噪声大的时候方向容易歪Momentum会参考历史方向像惯性一样压住噪声Adam则更进一步对每个参数维度单独缩放更新量。步子迈多大全局统一的学习率只是个起点真正训练时有的参数需要大步快走有的参数必须小步挪动。自适应优化器的核心价值就在这里。快和稳之间步子太大容易震荡甚至发散步子太小又可能卡在某个平台期。优化器的设计目标就是让模型在绝大多数任务上不用精细调参也能稳定收敛。我之前遇到loss卡住的情况本质就是Adam默认学习率1e-3对那个数据集偏大导致参数在最优解附近反复横跳。把学习率降下来之后loss曲线立刻变得平滑。这件事给我的启发是不管模型结构多先进优化器配置不合适一切都白搭。1.2 三类典型训练症状对应哪些优化器问题训练出问题时很多人习惯先怀疑数据和代码但优化器相关的症状其实很有辨识度。我按经验总结了三类最常见的表现。症状一loss震荡不下降。打开tensorboardloss曲线像心电图一样上下乱跳。这种情况大概率是学习率过大或者Adam的beta2设置过低导致梯度方差估计太敏感。先尝试把学习率缩小10倍如果还震荡再看是不是梯度里混入了NaN或异常大值。症状二loss持续下降但速度极慢。跑了十几个epoch下降不到一半这种情况通常是学习率太小或者Momentum设置过大导致更新方向被历史梯度拖住。另外一个容易被忽略的原因是模型输出层的初始化尺度不对导致梯度量级过小优化器一直在做无效更新。症状三前期正常后期停滞。loss在前半段顺利下降到中后段突然不动了换更大的学习率又开始震荡。这种往往是learning rate schedule的问题配合weight decay设置不当。可以尝试把固定学习率换成cosine decay或者根据验证集做early stopping式的学习率衰减。这三类症状基本覆盖了我见过的大部分优化器问题。下次再遇到loss不降别急着改网络结构先看一眼优化器配置。2. 从SGD到AdamW优化器家族的关键分岔路优化器这东西看起来是一堆公式实际上背后是几代研究者的思考脉络。我刚开始用PyTorch的时候只会无脑选Adam后来踩了坑才认真去搞清楚SGD、Momentum、RMSProp、Adam和AdamW之间到底差在哪里。2.1 SGD和Momentum最可靠的基线最原始的SGDStochastic Gradient Descent更新规则极其简单参数沿着负梯度方向移动每次移动距离由学习率控制。公式大概是param - lr * grad。它的问题也很明显在梯度噪声大或者loss landscape崎岖不平的时候更新方向会来回抖动收敛速度非常慢。Momentum的改进是引入一个速度变量把历史梯度的指数滑动平均叠加到当前更新方向上。更新规则变成两步v mu * v - lr * gradparam v。这个mu通常设0.9相当于让参数更新带上惯性可以冲过一些小坑和局部极小点在训练CNN时效果立竿见影。我自己的经验是Momentum把SGD从能用变成了好用。尤其是在ResNet这类结构稳定的CV模型上SGD-M配合cosine学习率衰减训练效果往往比Adam更扎实最终精度也更高。原因并不玄学SGD-M对参数的更新更均匀不会像自适应方法那样过度放大某些小梯度参数从而保留了更好的泛化能力。2.2 Adam凭什么成为事实标准Adam把Momentum和RMSProp的思想合并了。它维护两个状态一阶矩估计m相当于带惯性的平均梯度二阶矩估计v相当于梯度平方的滑动平均。每一步更新时先用当前梯度更新m和v然后做偏差校正最后用m_hat / (sqrt(v_hat) eps)作为每个参数的缩放后更新量。这种自适应机制的妙处在于某个参数的历史梯度一直很小它的更新步长会自动放大历史梯度很大的参数更新步长会被压缩。所以Adam几乎不需要手动调节学习率普通任务用默认的1e-3就能跑出像样的结果这对于工程调试和快速出baseline非常友好。但Adam也有代价。它对梯度的二阶矩估计依赖滑动窗口在训练后期可能造成更新步长过小导致模型收敛到不够理想的解。另一个更隐蔽的问题是它和L2正则的相互作用直接在Adam上叠加weight_decay会出现耦合效应这也是AdamW出现的原因。2.3 AdamW简单改动背后的深刻修正AdamW最核心的改动是把权重衰减从损失函数里的L2正则项里抽出来直接加到参数更新步骤中。传统做法是在loss里加0.5 * wd * param^2这样L2正则的梯度会和数据梯度一起被Adam的自适应缩放处理而AdamW是直接在更新时让参数整体乘以(1 - lr * wd)再做常规的Adam更新。这个区别听起来只是个工程细节实际影响很大。L2正则经自适应缩放后不同参数的实际衰减效果不均匀而解耦后的weight decay对每个参数一视同仁行为更可预测。现在训练Transformer类模型我基本上无脑用AdamW把weight_decay设到0.01到0.1之间效果显著优于在Adam上加L2。2.4 其他重要成员Adagrad、RMSProp、LAMB、LARSAdagrad按参数的历史梯度平方累积来缩放学习率适合稀疏特征场景但累积值只会越来越大后期可能直接学不动。RMSProp用指数滑动平均替代全量累积解决了Adagrad的衰减问题是Adam的前身。NAdam在Adam基础上把一阶矩的更新也做了类似Nesterov的修正收敛速度略快但提升有限。LARS和LAMB专门为大批量训练设计。LARS通过layer-wise的自适应缩放解决大batch下SGD-M的不稳定LAMB则把同样的思路给到Adam在512甚至几千的batch size下预训练模型时非常好用。AdaFactor省内存版Adam用一个低秩分解近似二阶矩适合超大模型但需要仔细调参。这几种优化器没有绝对优劣关键是看场景。训练CNN基线优先SGD-MTransformer类任务优先AdamW超大batch预训练再考虑LAMB或LARS。3. 三个核心超参数的直觉学习率、momentum与weight decay说到优化器调参绕不开的就是学习率、momentum和weight decay这三个旋钮。很多教程只告诉你推荐设多少但很少有人解释它们背后的数学直觉。其实想通了之后调参就不是碰运气而是有方向的调试。3.1 学习率从lr finder到warmup与cosine decay学习率是全局步长是最重要的超参数。它有一个最大稳定学习率的概念超过这个值训练必然发散低于它很多训练慢得让人失去耐心。实操中我常用一个叫lr finder的方法从一个很小的lr开始每个step指数增大同时记录loss画出来会发现loss先下降后上升拐点附近就是合适的初始lr。举个例子假设batch size是256我用lr finder发现最大稳定lr在1e-2到3e-2之间那训练初始lr就可以取1e-2再配一个warmup逐渐过渡。warmup是给大批量训练设计的因为训练初期梯度方向噪声大、模型参数还没进入稳定区域一上来就用大lr很容易把参数推到险峻区域。一般warmup 5%到10%的总step数是比较稳妥的。训练中后期我会用cosine decay让学习率沿余弦曲线平滑降到接近0。相比固定lr或step decaycosine decay的好处是前期保持较高的探索能力后期逐渐收敛在图像分类和NLP微调任务上都能带来稳定提升。3.2 beta1和beta2两个滑动窗口的尺度直觉Adam里beta1和beta2一旦被固定到0.9和0.999就很少有人动但它们其实决定了优化器看多长的历史。beta1是0.9时一阶矩平均的窗口大约有10步beta2是0.999时二阶矩平均的窗口约1000步。窗口越大估计越平滑但反应越迟钝。beta20.999的好处是能稳定估计稀疏梯度场景下的梯度方差比如在推荐系统或NLP的embedding中。如果发现loss震荡得厉害可以试一下把beta2调小到0.99或0.98让梯度方差估计更快适应当前变化训练会更稳。eps也值得一提。Adam的分母加了eps防止除零很多框架默认是1e-8。如果梯度的量级本身很小或者你对精度有更高要求把eps调大一些到1e-6或1e-4可以减少非常小参数维度上的无效更新有时候能意外地提升收敛效果。3.3 weight decay不是所有weight_decay都等价weight decay的本意是让参数在每一轮更新时整体缩小一点相当于给参数长度施加一个惩罚防止模型过拟合。在SGD里weight_decay设置为5e-4到1e-4是常见做法但在Adam里直接设置weight_decay效果会受到二阶矩缩放的影响不同参数的实际惩罚强度差异很大。这也是我强烈建议用AdamW的原因。当你把weight_decay和优化器解耦后可以把它当作一个更可靠的旋钮来调。对Transformer微调任务weight_decay通常可以从0.01开始对图像分类的CNN模型0.05甚至0.1也不少见。一个直观的验证方法是训练完查看权重范数如果模型在验证集上过拟合明显可以适当加大weight_decay如果模型欠拟合或loss迟迟降不下去就减小它。这里还有一个很容易踩的坑PyTorch里优化器的weight_decay参数在很多优化器实现里默认加在梯度上等价于L2正则而不是解耦的AdamW逻辑。想要真正用AdamW必须使用torch.optim.AdamW这一类原生解耦实现而不是torch.optim.Adam顺手加个weight_decay。4. 分场景选型参考从CV到NLP再到生成模型优化器选型没有银弹但每个领域确实都有经过大量实践验证的默认配置。我按照任务类型整理了一套选型思路特别标注了推荐学习率和weight decay范围可以当作起点直接用。4.1 CV分类与检测SGD-M仍然能打很多刚接触PyTorch的读者可能觉得Adam是万能药但在图像分类和检测任务上SGD-M配合cosine schedule依然是主流基线。ResNet-50在ImageNet上的经典配置是初始lr0.1batch size256momentum0.9weight_decay1e-4训练90个epoch。如果batch size改成512lr可以按比例提升到0.2注意同步调整warmup。在检测任务上我常用SGD-M配warmup。一个原因是检测模型通常包含backbone和head两部分学习率需要区分设置backbone的lr可以低一些head的lr可以高一些。用SGD-M的更新相对平滑这种分层配置更稳定。如果换成Adam一旦lr偏大head部分很容易先出NaN。当然如果你只是想快速验证一个新模型结构是否有效用AdamW开一个较小学习率也完全没问题。只是最终追求更高精度时再切回SGD-M调一版对比。4.2 NLP与TransformerAdamW是不可替代的主场Transformer类模型用AdamW几乎是行业共识。原因在于这类模型不同参数模块的梯度尺度差异极大embedding层和attention层的梯度可能差好几个数量级只有自适应方法才能高效地同时训练它们。微调BERT或GPT类模型时我通常用初始lr在1e-5到3e-5之间weight_decay取0.01warmup占比约6%再配cosine decay。如果做全量预训练学习率会高一些需要结合batch size和模型规模仔细调试。这里有个经验Transformer微调非常敏感学习率超过5e-5很容易直接loss爆炸翻车几次之后我就把它当铁律了。另一点NLP里经常出现稀疏激活的embedding特征Adam的beta20.999能很好地稳定那些低频参数的更新幅度。这是SGD-M很难替代的。4.3 GAN、扩散模型和生成模型分开操心两个网络生成类模型的优化器配置有个特殊性生成器和判别器或者扩散模型的denoiser它们的训练节奏不一样不能简单共用一个优化器配置。我在训练GAN时通常给判别器一个稍高的学习率生成器保持较低两个网络都使用Adam或AdamWbeta1可以调到0.5左右因为训练GAN时一阶矩窗口过大容易让更新方向过于平滑不利于生成器逼近真实分布。扩散模型则更接近标准Transformer结构优先AdamW即可。这类模型最需要注意的是loss的稳定性。建议开启gradient clipping把梯度范数限制在1.0以内配合动态调整学习率。很多生成模型训练崩溃根本不是结构问题而是优化器配置和梯度裁剪没配合好。4.4 大批量预训练LAMB与LARS的用武之地当batch size从256放大到4096甚至更大时普通优化器会出现一个经典问题每个step的梯度噪声降低但梯度方向更偏平均模型容易收敛到尖锐极小值泛化变差。这时候LARS和LAMB这类支持大面积batch的优化器就有价值了。LARS的核心思想是对每一层做local learning rate缩放LAMB则是在Adam基础上叠加layer-wise adaptation。我在大规模预训练时用过LAMB效果是在保持精度的前提下把batch size推到上千训练效率提升非常明显。但这个优化器对lr也很敏感初始化lr通常要比普通Adam高5到10倍必须搭配足够长的warmup。我把常用任务推荐配置整理了一个表大家可以先按这个跑一版再手动微调。任务类型推荐优化器学习率建议weight_decay备注CNN图像分类SGD-M cosine0.1 ~ 0.3 (batch 256)1e-4 ~ 5e-4ResNet系经典配置目标检测SGD-M warmupbackbone 0.01head 0.11e-4分层学习率更稳Transformer微调AdamW1e-5 ~ 3e-50.01大于5e-5极易崩Transformer预训练AdamW / LAMB1e-4 ~ 1e-30.01 ~ 0.1大批量选LAMBGANAdamG: 1e-4D: 2e-40beta1可设0.5扩散模型AdamW1e-4 ~ 2e-40.01配合梯度裁剪1.05. 实测翻车记录学习率、权重衰减与混合精度的连环坑调优化器这些年我踩过的坑加起来能写一本小册子。这里挑几个最有代表性的把完整排查链路写出来不一定是最快的捷径但至少能帮你少走弯路。5.1 学习率过大导致NaN从loss爆炸开始排查有一次训练一个深层Transformer第一个step loss就是NaN。我第一反应是数据里有脏值检查半天没发现问题后来看训练日志发现学习率是默认的1e-3而这个模型对lr极其敏感实际需要1e-4级别。排查NaN的套路应该是先把学习率降低10倍或100倍如果loss恢复正常说明是学习率过大如果还是NaN再检查输入数据和loss函数。另外一个常见原因是模型初始化方式不当比如没有加残差连接时把输出层初始化范围设得过大。优化器这一步是最容易被忽视的但往往也是最容易解决的。如果想更严谨一点可以做一次learning rate扫描以指数方式从小到大跑一小段训练记录每个lr下的loss变化。这样你能在几分钟内找到模型能接受的学习率区间。我现在每接触一个新模型架构都会先用这个方法探一下底基本不会再出现开局就NaN的情况。5.2 weight_decay设置不当验证集准确率持续下降另一个高频问题是weight_decay太大导致模型欠拟合。我见过有人从某个推荐配置里复制了wd0.1在图像分类任务上训练发现训练loss降得特别慢验证集一开始往往不错然后反而持续下降。排查时可以先做两组对照实验一组wd0一组wd1e-4分清是优化方向问题还是正则过强问题。再检查框架里的实现方式确认用的是解耦weight_decay还是等价于L2正则。特别是PyTorch里torch.optim.SGD(weight_decay0.0005)和torch.optim.AdamW(weight_decay0.01)的含义是不同的不搞清楚这条调参就是瞎试。我也习惯把wd当作一个事后调节器来用先跑通一个baseline看训练集和验证集准确率的差距再决定加大还是减小weight_decay。如果train精度低优先调lr和模型容量而不是乱动wd。5.3 混合精度训练优化器状态需要单独考虑用混合精度FP16训练时优化器的状态通常是FP32的master weight梯度在FP16下计算完会累积到FP32再更新FP32的master参数。这个过程中最容易被忽略的是loss scaling。如果loss scaling设置不合理梯度可能被下溢成0模型直接停止更新loss看起来却不崩。我的做法是开启动态loss scaling让框架根据梯度是否溢出自动调整scale同时把优化器的eps适当调大因为在FP16下非常小的梯度很容易被scale到0或溢出。另一个和优化器相关的问题是混合精度下Adam的m和v估计存在额外噪声所以遇到loss抖动比FP32训练更频繁时不要急着怀疑模型先检查优化器的eps和beta2。5.4 分布式训练梯度同步后优化器更新的一致性分布式训练时每个rank各自计算梯度通过allreduce汇总平均后再调用优化器step。如果哪里写错了同步逻辑就会导致不同rank的优化器状态不一致模型表现怪异。最典型的例子是gradient accumulation和optimizer step的配合。假设我用8卡每卡batch size为32想要等效batch size为256那么累积8个micro-step再step一次。但此时学习率要不要放大取决于你基准batch size是多少。如果基准是单卡32却因为累积了8倍梯度而把lr也调大8倍大概率训练不稳。我建议固定一个batch size作为训练基准lr都按它来算改动分布式规模时优先使用warmup和lr scaling rule来适配而不是凭感觉调大学习率。优化器状态在分布式下需要和梯度同步一起保证一致性任何一步疏忽都会让整个实验失去可信度。6. 新优化器观察与我的实操建议优化器这个领域这两年其实很热闹Lion、Sophia、AdEMAMix这些新名字不断冒出来社交媒体上也经常有人晒指标。我个人的态度是保持关注但不过度追逐。Lion最吸引人的地方是把Adam的两个动量状态简化成了符号函数和EMA内存占用大幅下降训练速度也快。我试过一次在图像分类任务上和AdamW精度接近但学习率需要重新搜索不能直接沿用。Sophia则把二阶信息引入更新方向在大模型预训练上能省不少step但实现复杂度和显存开销都不低。至于AdEMAMix这类双动量混合方法目前更多是在特定任务上有报道还不到通用替换的时候。我的建议是新优化器再香也先在自己的baseline任务上跑三组实验对比一组用当前默认优化器一组手动调参的新优化器一组只改lr schedule保持原优化器。很多模型效果的提升其实只是lr schedule的功劳而不是优化器本身。最后再分享一个小技巧我每次跑新项目都会在实验记录里固定优化器版本和关键超参因为PyTorch不同版本对SGD和Adam的实现细节有微妙差异升级框架之后最好重新验证一遍否则实验结果很容易对不上。优化器这个东西看起来是训练脚本里不起眼的几行代码但在它上面花时间做实验是回报率很高的投资。