资讯动态

深度学习优化器全解析:从SGD到AdamW的演进与调参实战

发布时间:2026/10/17 7:43:24 来源:尧图企业网站定制
模型训练跑不动、收敛慢、效果差很多人第一反应是调网络结构或者加数据但说实话优化器往往才是那个被忽视的隐形推手。同样的模型、同样的数据换一个优化器loss曲线可能完全是两个世界。我从SGD一路用到AdamW中间踩过不少坑这篇文章就把深度学习优化器的演进脉络、背后的数学直觉、以及实际训练中的调参经验一次性讲清楚希望能让正在被loss振荡、不收敛、spike折磨的读者少走点弯路。1. 整体脉络优化器演进的底层驱动力要理解优化器为什么从最简单的SGD一路演变到今天的AdamW得先看清这条线索每一次优化器的迭代本质都是在解决前一个版本留下的短板。最原始的SGD方向准但步子死板于是有了Momentum给它装上惯性Momentum解决了峡谷震荡但所有参数共用一个学习率又不合理于是AdaGrad出现给每个参数单独配学习率AdaGrad的累积平方和导致学习率过早衰减到零RMSProp用指数移动平均来替代解决了这个问题Adam把Momentum和RMSProp一结合既有一阶动量又有二阶动量成了深度学习的事实标准。再往后Adam在正则化项上存在数学瑕疵AdamW把权重衰减和梯度更新真正解耦在大模型时代全面接管。优化器核心机制解决的问题代表性适用场景SGD随机梯度下降单步参数更新最基本的优化框架简单模型、调试baselineMomentum SGD历史梯度方向累积振荡、局部极小值CV分类、部分经典网络AdaGrad按参数历史梯度平方和缩放学习率不同参数频率差异稀疏特征场景早期NLPRMSProp指数移动平均的梯度平方AdaGrad学习率过早归零非平稳目标、RNN训练Adam一阶动量二阶动量自适应综合收敛速度与稳定性CNN、RNN、Transformer等主流场景AdamW解耦权重衰减与梯度更新Adam正则化失效问题预训练大模型、B站类推荐模型这个演进过程有个明显的趋势从一刀切走向差异化。SGD对每个参数一视同仁学习率像一个全局旋钮而后续优化器逐渐学会在训练过程中动态判断哪些参数走得慢了要推一把哪些参数震荡太厉害要踩一脚刹车。一句话总结这条主线优化器的进化史就是一部从盲目更新走向感知与自适应的历史。理解这条主线后后面所有细节就顺理成章了。2. 从SGD到SGDMomentum梯度下降的朴素起点与惯性突围2.1 朴素SGD方向正确但效率堪忧SGD的核心思想用一句话说就是沿着loss下降最快的方向挪一小步。公式是 $$ \theta_{t1} \theta_t - \eta \nabla L(\theta_t) $$其中 $$\eta$$ 是学习率$$\nabla L$$ 是当前点的梯度。朴素走法在loss曲面平坦区域会极其折磨梯度很小每一步都像在平地上挪动蚂蚁腿训练一万步loss还是纹丝不动。而在陡峭的峡谷区域梯度方向剧烈变化参数来回震荡loss像神经病一样上下乱跳。实际的SGD收敛过程可以想象成蒙着眼睛下山脚下感觉坡度最陡的方向就迈一步但山脊两侧的坡度常常是反复横跳的。这里要补充一个初学者容易忽略的点SGD的每一笔是用一个batch的梯度估计全量梯度的。batch有随机性所以梯度本身带着噪声这个噪声既是坏事也是好事——坏事是它会让loss曲线不平滑好事是它有助于跳出局部极小值。2.2 Momentum给下山者装上一个惯性轮解决SGD震荡和平坦区慢速问题的最直接思路是引入历史梯度方向。这就有了Momentum$$ v_t \gamma v_{t-1} \eta \nabla L(\theta_t) $$$$ \theta_{t1} \theta_t - v_t $$$$ \gamma $$ 一般取0.9意思就是让参数更新方向不仅看当前梯度还要看前几步积累的速度。可以理解为推一个很重的铁球下山铁球一旦滚起来不会因为局部坡度变化就立刻转向而是借着惯性冲过去。好处有两点在峡谷中抑制震荡在平坦区域加速前进。我在实际项目里观察到的效果是Momentum把ResNet这类模型在ImageNet类任务上的收敛epoch数大概缩短了四分之一到三分之一尤其在训练初期loss下降的速度会明显更快。Nesterov Momentum是变体$$ v_t \gamma v_{t-1} \eta \nabla L(\theta_t - \gamma v_{t-1}) $$它会在计算梯度前先预跳一步相当于一个带前视的惯性轮。直观感受是它比标准Momentum更敏锐在梯度转变方向的场景下能提前减速实际使用中收敛略微稳定一些但并没有质的飞跃。2.3 SGD家族的致命短板一马平川的学习率SGD和Momentum最大的问题不是方向而是学习率对所有参数一视同仁。深度学习模型的参数量动辄百万千万不同参数出现频率、梯度尺度千差万别。用一个全局学习率去适配所有参数就好比一个老师对全班学生布置一模一样难度的作业——基础好的吃不饱基础差的跟不上。稀疏场景下的问题更突出。比如推荐系统的Embedding层有些特征出现频率极高梯度信息丰富需要更小的学习率防止参数剧烈波动有些长尾特征出现频率极低梯度稀疏需要更大的学习率尽快收敛。如果统一用一个学习率Embedding参数的更新就会顾此失彼最终导致部分特征的表示学习不充分。正是这个一刀切的痛点催生了自适应学习率优化器。3. 自适应学习率的崛起AdaGrad、RMSProp与Adam3.1 AdaGrad给每个参数按历史梯度配学习率AdaGrad的思想很直接对于每个参数用它的历史梯度平方和来缩放当前学习率。更新公式为$$ \theta_{t1} \theta_t - \frac{\eta}{\sqrt{G_t \epsilon}} \odot g_t $$其中 $$G_t$$ 是历史梯度平方的累积和。梯度大的参数累积项大学习率自然被压低梯度小的参数累积项小学习率相对放得更大。这在稀疏特征场景下效果显著频繁出现的特征学习率自动变小罕见特征则保持较大的更新步长。但AdaGrad的问题也出在这个累积上。平方和从训练开始就在单调累积分母越滚越大学习率最终趋近于零。训练到后期模型基本陷入锁死状态想继续精调也动不了。这在凸优化问题里也许勉强能忍但在非平稳的深度网络训练中这几乎等于判了死刑。3.2 RMSProp用滑动平均修复梯度消失问题RMSProp的改进非常巧妙既然累积整个历史的平方和会爆炸那就只累积最近一段时间的梯度信息。$$ E[g^2]_t \rho E[g^2]_{t-1} (1-\rho) g_t^2 $$其中 $$\rho$$ 通常取0.9或0.99然后参数更新为 $$ \theta_{t1} \theta_t - \frac{\eta}{\sqrt{E[g^2]_t \epsilon}} \odot g_t $$。用指数移动平均替代全量累积RMSProp的学习率不会单调递减到零而是能根据近期梯度的大小动态调整。这背后的直觉是让最近一段时间的梯度统计量来决定当前参数的更新步长而不是让远古时期的梯度来绑架现在的决策。RMSProp在RNN训练里表现非常出色要知道RNN的梯度在时间维度上极其不稳定经常要么爆炸要么消失RMSProp的自适应缩放能力正好能顶住这种剧烈波动。3.3 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 $$再对 $$m_t$$ 和 $$v_t$$ 做偏差校正因为它们在训练初期偏向于0。最后更新为$$ \theta_{t1} \theta_t - \frac{\eta}{\sqrt{\hat{v}_t}\epsilon}\hat{m}_t $$默认经验值 $$\beta_10.9$$、$$\beta_20.999$$、$$\epsilon10^{-8}$$。Adam的工程意义在于它几乎是开箱即用的它天然适应不同尺度的参数能够处理稀疏梯度收敛速度比SGD快得多。尤其在Transformer架构出现后Adam基本成了标配自注意力机制对学习率极其敏感SGD在那上面几乎无法有效训练。但我必须指出Adam的一个隐蔽缺陷它在训练后期容易出现loss在平台期附近反复振荡。原因在于二阶动量 $$v_t$$ 的滑动平均估计了历史梯度的方差这实际给更新量引入了一个随机波动因子。到了训练后期梯度接近零这个波动相对就显得大了参数就在最优点附近来回抖动。另一个更深层的问题是正则化。主流框架在Adam上实现L2正则通常是在loss里直接加权重惩罚项但这在数学上会与Adam的一阶动量累积产生耦合导致正则化强度被扭曲。这就是接下来AdamW登场的核心原因。4. AdamW解耦权重衰减与大模型时代的优化器新常态4.1 权重衰减与L2正则化看起来一样但本质上不同要理解AdamW必须先分清两个概念权重衰减和L2正则化。权重衰减的形式是在参数更新后直接乘一个衰减系数$$ \theta_{t1} (1 - \lambda\eta)\theta_t - \eta m_t $$L2正则化的形式是在loss上加上权重二范数惩罚$$\tilde{L} L(\theta) \frac{\lambda}{2}|\theta|^2$$再求梯度更新。在SGD下这两种操作是等价的$$\theta_{t1} \theta_t - \eta(\nabla L \lambda\theta_t) (1 - \lambda\eta)\theta_t - \eta\nabla L$$。这就是很多框架用L2正则等价替代weight decay的原因。但在Adam里这个等价性被打破了。Adam里L2正则项的梯度 $$ \lambda\theta_t $$ 会进入动量 $$m_t$$ 的滑动平均导致正则项的影响被放大了约 $$1/(1-\beta_1)$$ 倍默认约10倍。同时自适应学习率会把正则项梯度除以二阶动量 $$v_t$$ 的平方根进一步扭曲正则强度。结果是使用L2正则的Adam实际正则效果不可控一阶和二阶动量的累积让正则项作用在参数上的比例变得莫名其妙。4.2 AdamW的核心让权重衰减回归纯粹AdamW的修正极其简单把权重衰减从梯度计算中彻底剥离直接作用在更新后的参数上。更新公式变为$$ v_t \beta_2 v_{t-1} (1-\beta_2)g_t^2 $$$$ \hat{v}_t \frac{v_t}{1-\beta_2^t} $$$$ \theta_{t1} \theta_t - \eta\left(\frac{m_t}{\sqrt{\hat{v}_t}\epsilon} \lambda\theta_t\right) $$注意这里的区别$$ \lambda\theta_t $$ 不再参与动量和二阶动量的计算而是作为一个独立的衰减项叠加在自适应更新量之外。这样保持了权重衰减的原意无论梯度状态如何参数每步都会按固定比例向零收缩起到稳定的正则化作用。这个改变带来一系列正面效果参数更新与正则项互不干扰权重衰减系数 $$\lambda$$ 可以直接解释为每步参数实际被缩小到原来的 $$1-\eta\lambda$$ 倍超参含义更清晰训练更加稳定尤其在预训练大模型和长训练日程中不会出现后期loss飘忽不定甚至发散的情况泛化性能普遍更好因为正则项的作用回归了本意。实际效果上AdamW并不总是比Adam大幅提高精度但在大模型和Transformer类架构中它的稳定性和可控性优势是压倒性的。我个人的体会是从Adam切换AdamW之后最明显的变化不是指标暴涨而是训练过程情绪稳定不再动不动就loss spike。4.3 优化器演进的最新方向大模型时代的变体研究AdamW并不是终点。大模型训练中优化器的内存开销成了瓶颈AdamW需要保存一阶动量、二阶动量和参数本身每个参数就要占3份显存。对于7B甚至更大的模型优化器状态占用的显存可能超过模型权重本身。于是出现了两个主流方向的变体一是低秩近似方向。通过对二阶动量做低秩分解来压缩存储这在减少内存的同时保持训练质量但实现复杂度高需要精细的数值稳定性处理。二是分块更新方向。借鉴稀疏更新的思想每步只更新一部分参数对应的优化器状态从而大幅降低显存需求。代价是收敛速度有一定的损失。另一个趋势是自适应学习率的修正。经典Adam的二阶动量在过去一段时间内可能不稳定导致学习率缩放异常。近年出现的一些修正思路是引入更平滑的二阶矩估计或者在训练后期切换到SGD风格更新以改善收敛阶段的行为。说白了大模型时代优化器的核心矛盾已经从如何快速收敛转向如何在有限显存下稳定完成超长训练。这也是为什么现代大模型训练基本清一色启用AdamW配合显存优化方案而不是追求新的花哨算法。就目前看还没有哪个变体能全面替代AdamW的主流地位。5. 动手实践优化器选型、调参与代码实现5.1 怎么选不同任务场景的优化器配置很多初学者喜欢无脑上Adam或AdamW觉得效果好省事。但真实项目中选型要结合任务特点来。纯CV分类任务尤其是数据量不太大的情况下效果稳定的SGD加Momentum用0.9配合Cosine退火往往能和Adam系列打平甚至更优而且超参更鲁棒。原因在于CNN的梯度分布相对均匀自适应学习率带来的收益有限而SGD的泛化性优势却显得实实在在。NLP、Transformer类架构、大规模预训练、推荐系统等场景无脑用AdamW就好。尤其预训练阶段因为训练步数极其漫长AdamW的稳定性和可控性优势在长日程中体现得淋漓exhausted尽致。推荐系统里Embedding特征大多是稀疏的自适应优化器对梯度的动态缩放几乎是刚需。如果显存紧张或推理部署对内存敏感可以考虑做分块更新的优化器相当于用少量精度损失换取一倍以上的显存节省。5.2 学习率与关键超参从理论到实操的取值策略学习率是优化器里最重要也最容易翻车的参数。基本原则学习率设太小模型慢慢折磨你学习率设太大训练一步就爆。对于SGD常用初始学习率通常在0.01到0.1之间配合Momentum取0.9。对于AdamW初始学习率通常在1e-4到3e-4之间大模型预训练往往更保守取1e-4甚至更低。warmup几乎成了Transformer训练的标配。原理是训练初期二阶动量 $$v_t$$ 的统计量还不可靠直接用较大学会率容易使梯度方向偏离先从一个很小的学习率起步逐步增长到目标学习率等动量和方差统计量稳定了再全力冲刺。实践中常听到的前5%步数做warmup就是这个意思。关于 $$\beta_2$$如果任务中梯度波动很大比如GAN训练、RNN长序列把 $$\beta_2$$ 调大到0.99甚至0.995可以进一步平滑二阶动量。代价是收敛略慢但稳定性显著提升。我在训练GAN时曾遇到过震荡很严重的情况调整 $$\beta_2$$ 之后明显稳定很多。$$\epsilon$$ 这个参数经常被忽视但它直接保护了数值稳定性防止二阶动量接近零时除出天文数字。现代框架的默认值大多为1e-8或1e-7如果遇到loss出现NaN可以试着把它调到1e-6甚至1e-5看看情况。5.3 从零手写关键优化器理解内部机制的另一种方式只靠调包很难真正理解优化器的内部运作。我自己曾经用NumPy实现过SGD、RMSProp和Adam对每个细节都有了更深的体感。给出一个简明的Adam参考实现import numpy as np def adam_update(params, grads, m, v, t, lr1e-3, beta10.9, beta20.999, eps1e-8): 单步Adam更新 updated [] for p, g in zip(params, grads): m[p] beta1 * m[p] (1 - beta1) * g v[p] beta2 * v[p] (1 - beta2) * (g ** 2) m_hat m[p] / (1 - beta1 ** t) v_hat v[p] / (1 - beta2 ** t) updated.append(p - lr * m_hat / (np.sqrt(v_hat) eps)) return updatedAdamW在手写时只需要把权重衰减从梯度计算里挪出来放在最后独立执行def adamw_update(params, grads, m, v, t, lr1e-3, beta10.9, beta20.999, eps1e-8, wd0.01): 单步AdamW更新解耦权重衰减 updated [] for p, g in zip(params, grads): m[p] beta1 * m[p] (1 - beta1) * g v[p] beta2 * v[p] (1 - beta2) * (g ** 2) m_hat m[p] / (1 - beta1 ** t) v_hat v[p] / (1 - beta2 ** t) # 注意权重衰减独立于梯度自适应项直接作用于参数 updated.append(p - lr * (m_hat / (np.sqrt(v_hat) eps) wd * p)) return updated这两段代码看似差别不大实际行为差异显著。手写之后你会真正意识到AdamW的简练形式背后是正则化语义的深刻修正。5.4 常用框架下的优化器配置速查PyTorch Lightning / HuggingFace Trainer直接引用AdamW优化器类设置好学习率和权重衰减系数即可框架会自动配合warmup调度器。分布式训练注意初始化和保存优化器状态时的随机种子一致性否则断点续训会出现梯度和动量统计量不匹配的问题。混合精度训练优化器参数通常需要以FP32精度维护要和模型权重精度分开管理。下面给一个适配多数场景的初始配置参考超参数推荐初始值说明学习率1e-4AdamW / 0.01-0.1SGD不收敛则降一半发散则降一个量级Beta10.9一般不用动Beta20.999梯度波动大时调到0.99Epsilon1e-8出现NaN时调到1e-6或更大权重衰减系数0.001-0.1推荐0.01起步过小正则不起作用过大会损害模型容量Batch Size尽量大增大batch时记得同步调整学习率6. 常见问题与排查技巧实录6.1 Loss不下降卡在一个奇怪的高位这是最常被小白的锅甩给模型结构的问题但优化器的嫌疑往往更大。先检查学习率如果学习率太大会导致参数在能量较高的震荡区反复横跳loss降不下去如果太小则训练速度慢到看起来像没在学。我的排查方法是用一个极小的子集比如32个样本先做过拟合实验如果loss能降到很低说明优化器工作正常问题在全量数据的学习率或batch size设置上。再检查权重衰减系数。曾经有一次我把权重衰减设成1.0模型loss直接卡住不动因为每一步参数都被强衰减扯向零模型基本失去了表达能力。权重衰减从0.01起步把它当成普通超参去调就行。6.2 Loss出现NaN训练瞬间崩溃NaN问题的原因有很多但优化器相关的排查顺序是先看学习率是不是过大造成梯度爆炸再看 $$\epsilon$$ 是否过小二阶动量接近零时数值不稳定再看混合精度下的梯度溢出。一次实际经历中我遇到的NaN是FP16混合精度下的梯度下溢造成的损失函数在输出层产生极小梯度被量化成0后权重衰减又能继续更新最终导致loss爆掉。解决办法是开启loss scaling并确保二阶动量以FP32保存。6.3 训练后期Loss反复振荡下不了平台期这个现象在Adam里非常典型。处理思路有三种一是逐步降低学习率配合余弦退火或线性衰减二是提高 $$\beta_2$$让二阶动量估计更平滑三是切换到带权重衰减的AdamW并配合小学习率。我自己的经验是训练后期把学习率按步数线性衰减到初始值的1/10比一直保持恒定要好得多。平台期的loss振荡大部分时候是学习率没退火造成的不一定是优化器选错了。6.4 训练初期损失下降很快但验证集完全不涨优化器导致的训练-验证gap大往往与正则化设置有关。检查一下权重衰减系数是否过小、是否有数据增强、以及模型的归一化层是否正常工作。从优化器角度说所有权重衰减系数从0.01开始调如果验证集也没有变化那问题大多不在优化器上。7. 一点个人总结与选型建议这两年做模型训练最深刻的一个体会是优化器不是拿来即用的魔法而是一套需要理解并调校的系统。SGD系列像传统的手工锻造每个细节都有讲究调好了很出彩AdamW则是工业流水线的标准件稳妥可靠但如果不理解权重衰减和动量的关系就随手开用出了问题很难排查。如果你正在带一个新项目我的建议是默认方案选AdamW初始配置按1e-4的学习率和0.01的权重衰减开始训练配合warmup和cosine退火调度。如果你发现模型收敛了但效果还不够好再回溯检查SGDMomentum是否更适合当前任务。优化器领域当然还在继续演进新的内存优化方案、更稳定的自适应机制不断出现但万变不离其宗所有设计都是在梯度方向、步长估计与正则控制之间寻求更好的平衡。理解经典系列的演进逻辑再去看任何新论文都会快很多。

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

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

免费获取报价 →
↑