
干这一行久了你会发现很多模型训练的“玄学问题”追根溯源都出在优化器上。损失不降、训练震荡、收敛到最后精度差一口气大多数人第一时间去调网络结构、调数据增强却忽略了一个最基本的事实优化器Model-Optimizer才是那个决定模型参数如何更新、如何逼近最优解的“方向盘”。这篇文章我想系统聊一聊模型优化器这件事。不是教科书式的原理复读而是结合我这些年实际跑训练、调模型踩过的坑说说优化器的选型逻辑、参数调优的实操方法以及那些文档里不会告诉你的细节。不管你是刚入门深度学习的新手还是已经在训练大模型的老手这篇文章应该都能给你一些参考。1. 优化器到底在解决什么问题很多人把优化器当成一个“选好就行”的组件用默认参数一把梭。但如果你不理解优化器在做什么遇到问题的时候就只能瞎猜。所以先花点篇幅把底层逻辑讲清楚。1.1 优化器的本质参数更新策略机器学习模型训练的核心是通过最小化损失函数来找到一组最优参数。这个过程本质上是一个“下山问题”你站在一座山上当前参数位置希望走到山谷底部损失最小点而你走的每一步都由优化器来决策。最基本的策略是随机梯度下降SGD它的更新公式非常简单[ \theta_{t1} \theta_t - \eta \cdot g_t ]其中 ( g_t ) 是当前批次计算出的梯度( \eta ) 是学习率。就这么一个简单的公式衍生出了几十种优化器也埋下了大量训练问题的种子。为什么需要更复杂的优化器因为在实际训练中SGD有两个非常棘手的问题。第一梯度本身是有噪声的每个batch的数据分布都不一样导致梯度方向在“正确方向”附近剧烈摇摆第二损失函数的地形往往不是光滑的碗状而是包含陡坡、峡谷、鞍点、局部极小值等各种复杂地形固定步长很难适应所有区域。这就是优化器要解决的核心问题怎样在保持稳定性的前提下尽可能快地让模型逼近最优解。1.2 学习率的困境为什么固定学习率不靠谱学习率是优化器里最重要的超参数。它决定了每一步走多远。如果学习率设得太小训练会像蜗牛爬行迭代很多轮损失还是慢慢悠悠地下降如果设得太大参数会在最优解附近来回震荡甚至直接发散损失变成NaN。更麻烦的是不同参数对学习率的敏感度完全不同。比如神经网络中靠近输入层的参数和靠近输出层的参数它们的梯度尺度往往差好几个数量级。用同一个学习率去更新所有参数必然会导致一部分参数更新过快震荡另一部分参数更新过慢停滞。这是优化器演进的核心驱动力让每个参数拥有自己的、自适应的更新步长。明白了这一点你再看Adam、RMSProp这些优化器的设计思想就会觉得非常自然。2. 主流模型优化器的演化与选型逻辑优化器的演化史其实就是深度学习训练稳定性不断提升的历史。每次新的优化器出现都在解决前一代的某个具体痛点。2.1 从SGD到动量法解决梯度噪声问题纯SGD的问题在于梯度噪声太大。一个自然的想法是用过去一段时间内梯度的“平均方向”来代替当前时刻的梯度方向这样随机噪声就会被平滑掉。这就是动量Momentum方法的雏形。它引入了一个速度项 ( v )更新公式变成[ v_{t1} \gamma v_t g_t ] [ \theta_{t1} \theta_t - \eta \cdot v_{t1} ]动量项的引入让优化在梯度方向一致的时候加速前进速度累积在梯度方向变化剧烈的时候减速缓冲避免震荡。我在实际训练中感受很明显加了动量之后训练曲线的抖动明显变小收敛速度也有可感知的提升。动量的超参数 ( \gamma ) 通常取0.9这是一个很稳的经验值。有些任务里取0.95只适合极小批量训练新手不建议乱动。2.2 Adam与RMSProp自适应学习率时代动量法解决了“方向”问题但没有解决“步长”问题。不同参数的梯度尺度差异依然巨大尤其是在深层网络中。RMSProp的做法是对每个参数维护一个梯度平方的指数移动平均用这个值来归一化学习率。梯度大的参数学习率变小梯度小的参数学习率变大。这样每个参数就有了自己的自适应步长。Adam算是集大成者它结合了动量法一阶矩估计和RMSProp二阶矩估计用梯度的一阶矩来控制方向用二阶矩来控制步长。如果你用默认参数学习率0.001训练一个中小规模模型Adam基本上开箱即用不需要怎么调参。Adam的适用场景非常广NLP、CV、语音、推荐系统只要是中小规模数据Adam几乎都有不错的表现。它的容错率高不会因为学习率设置稍微不当就完全跑飞。2.3 AdamW与LAMB大模型的优化器答案这里必须说一个很多人不知道的坑Adam自带的权重衰减实现方式其实是有问题的。原始Adam在做L2正则化的时候梯度的正则项会被二阶矩归一化导致实际的正则效果与设定的权重衰减系数不一致。AdamW把权重衰减和自适应步长解耦直接在参数更新时单独减去权重衰减项。看起来只是一个实现细节的改动但在预训练任务上AdamW的泛化性能明显优于Adam。这也是为什么现在几乎所有开源大模型、预训练模型都在用AdamW而不是Adam。LAMB则是专门为大规模分布式训练设计的优化器。它在AdamW的基础上增加了逐层的学习率归一化解决了大batchsize训练时学习率难以放大的问题。如果你在跑BERT、GPT这类大规模预训练且batchsize达到数万级别LAMB几乎是唯一的选择。3. 模型优化器参数调优实战选好了优化器只是第一步。真正拉开训练效果差距的是参数怎么调。这一部分我直接讲我实际跑训练时的操作方法和判断逻辑。3.1 学习率的设定策略从经验值到调度器先给出一个最常用的基准配置Adam家族优化器初始学习率取3e-4到1e-3这个区间在大多数任务上都是安全的。SGD类优化器因为缺少自适应步长学习率要降一个到两个数量级通常在1e-3到1e-2区间。但这只是起点。真正提高训练效果的是学习率调度器。我自己的习惯是分三个阶段来操作试跑阶段固定学习率跑50到100个step观察损失曲线的下降速度。如果损失上升或者剧烈震荡说明学习率偏大降到之前的1/3再试如果损失下降过于平缓说明学习率偏小加倍再试。正式训练阶段使用带warmup的调度器。前几百步让学习率从极小值线性上升到目标值减少初始阶段对模型预训练权重的破坏随后按照训练进度逐步衰减最常用的是余弦退火Cosine Annealing或Step Decay。微调阶段如果模型在验证集上指标趋于平缓可以手动把学习率除以10再续训通常还能收获一波提升。关于warmup的步数我的经验是数据量越大warmup步数越长。小数据集几千样本warmup 50步就够了大数据集百万级warmup步数建议占到总步数的2%到5%。3.2 权重衰减与正则化的平衡权重衰减weight decay是防止过拟合的重要武器。在AdamW中权重衰减系数通常设置在0.01到0.1之间。我在CV任务中常用0.05在NLP任务中常用0.01。这里有一个很常见的误区有人以为权重衰减越大越好。实际上权重衰减过大会让模型欠拟合尤其是在数据量本身不大的时候过强的正则化会让模型学不到足够的特征。判断权重衰减是否合适的经验方法跑两个对比实验一个不设置权重衰减一个设置0.01对比验证集指标和训练集指标之间的差距。如果训练集指标明显高于验证集说明过拟合可以增大权重衰减如果两者的指标都低说明欠拟合应该减小权重衰减。梯度裁剪也是优化器调优中容易忽略的一环。尤其是在训练大模型或使用大学习率时梯度爆炸是家常便饭。我一般将梯度范数裁剪到1.0如果训练不太稳定会进一步缩到0.5。这个操作几乎不增加计算成本却能让训练稳定很多。3.3 批量大小与优化器的联动batchsize的大小会影响优化器的参数选择这一点经常被忽视。小批量16-32训练时梯度噪声比较大动量项能起到很好的平滑作用此时学习率不宜设大大批量128以上训练时梯度估计更接近真实梯度可以适当增加学习率但要注意增加warmup步数来缓冲。一个粗略的参考规律batchsize翻倍学习率可以乘以1.4到1.6倍。这是我基于线性缩放规则Linear Scaling Rule的实际经验值当然这个规律需要配合warmup使用才能保证稳定性。另外大批量训练时Adam一族的优势没有小批量时那么明显。因为我实测下来大批量场景下梯度本身已经比较稳定SGD动量的表现往往不会输给Adam甚至在泛化性上更好。如果你的任务是大batchsize场景不妨对比一下SGD-Momentum和AdamW的效果再做决定。4. 训练实战中的优化器调试记录这一部分我挑选了三个在真实训练中最常见的问题场景记录我的排查思路和解决过程希望能给你一些参考。4.1 损失震荡问题排查有次训练一个图像分类模型用的AdamW学习率1e-3。前200步损失稳步下降到了200步之后损失曲线开始剧烈震荡像锯齿一样上上下下完全无法收敛。我排查的思路是先看梯度范数是否异常。打印出来的梯度范数在正常范围内排除梯度爆炸再看是否是数据问题随机抽样了几个batch单独跑前向和反向也没有问题。最后问题出在学习率上。200步之后模型参数逐渐接近一个较优区域1e-3的学习率在这个区域就偏大了导致参数在最优解附近反复横跳。解决方案是把学习率降到3e-4并加上余弦衰减震荡问题消失最终的验证精度还涨了0.8个百分点。这个案例的关键教训是固定学习率训练时不能只看前期的下降速度还要关注后期是否震荡。如果训练中后期出现锯齿状震荡优先怀疑学习率偏大。4.2 收敛过慢的排查另一个经常遇到的问题损失确实在下降但速度慢得像在爬行。这种时候很多人的第一反应是加大学习率但往往会发现加大之后训练就崩溃了。我用一个文本分类模型复盘一下排查过程。用的是AdamW默认学习率1e-4注意不是我前面推荐的3e-4训练了3000步损失从2.0只下降到1.2指标一直上不去。我挨个排查学习率果然是设低了1e-4对Adam来说偏保守提到3e-4。优化器类型这个任务其实模型容量不大数据量也不大Adam和AdamW差别不大但AdamW在稳定性上更好。batchsize只有16偏小。梯度噪声大收敛自然慢。提到32之后曲线明显平滑了。综合调整之后同样3000步损失从2.0降到了0.7左右。这个案例说明收敛慢往往是多个因素叠加的结果不要单独拧某一个超参数要从学习率、batchsize、数据质量三个维度一起排查。4.3 显存占用优化优化器那一块的大头训练大模型时显存不够用是常态。很多人只知道模型参数和激活值占显存却忽略了优化器状态也是一个显存大户。以Adam为例它需要为每个参数额外保存一阶动量类似参数大小的张量和二阶动量同样大小再加上参数本身的梯度意味着优化器状态所占的显存至少是模型参数大小的2倍。这也是为什么我经常建议如果你做的是自己的小项目显存有限可以试试SGDMomentum它会省掉二阶矩的那一块显存。在7B规模的模型上AdamW需要6倍于参数大小的显存参数梯度一阶动量二阶动量而SGDMomentum只需要2倍。如果你一定要用AdamW但显存不够可以考虑8bit优化器如bitsandbytes库实现的8位Adam能把优化器状态的显存占用降到原来的1/4左右。我在64GB显存的机器上成功跑过7B模型微调用的就是8bit AdamW训练速度有轻微下降大约5%但显存压力大幅缓解。5. 优化器的进阶玩法与常见坑最后这部分聊几个我踩过的比较深的坑和一些进阶技巧。5.1 混合精度训练下的优化器注意事项混合精度训练AMP在现代训练框架里几乎是标配。但在开启AMP之后优化器有个容易忽略的底层问题主权重是以FP32保存的而梯度计算是在FP16下做的。AMP框架会自动处理梯度的缩放gradient scaling但如果你手动写训练循环就容易忘记在更新参数之前做梯度缩放的反缩放导致优化器拿到的梯度是错位的训练直接崩掉。我的建议是不要自己手写AMP的训练循环直接用框架封装好的API。如果你确实需要自定义逻辑务必在优化器step之前调用梯度缩放的反缩放接口并且在clip_grad_norm_之后再做缩放。5.2 优化器状态与断点续训训练到一半中断是家常便饭。但很多人保存checkpoint的时候只保存了模型权重没有保存优化器状态导致续训时动量信息丢失训练效果大受影响。保存优化器状态是断点续训的底线要求。这不仅仅是能继续训练更重要的是保持训练的连续性。我们看一下不保存优化器状态的后果Adam的二阶动量保存了梯度平方的历史信息丢了这个信息续训时的自适应步长会重新计算效果等同于重新训练的前几百步。我的习惯是每次保存模型时同时保存优化器state_dict和随机数生成器的状态。如果是分布式训练还要保存学习率调度器的状态。这套保险下来即使中断在训练的第4999步续训也能无缝衔接。5.3 不同任务场景下的优化器推荐表我自己整理了一个优化器选型参考表不完全严谨但作为初始配置很有参考价值任务场景推荐优化器推荐初始学习率关键备注小规模CV分类几万级数据AdamW3e-4权重衰减0.05配合余弦退火大规模CV预训练百万级数据SGDMomentum0.1配合warmup常用resnet训练配置泛化好中小规模NLP微调AdamW3e-5到1e-4注意BERT类模型学习率不宜过大大模型预训练十亿参数以上AdamW或LAMB1e-4到3e-4必须用AdamW替代Adam强化学习Adam1e-4到3e-4注意梯度裁剪稳定性优先小样本迁移学习AdamW1e-4权重冻结只训练分类头时用高一些这张表的核心逻辑是数据规模越大优化器越简单越稳SGD类模型参数越多越依赖自适应学习率Adam类。如果你的任务不在表里可以找一个最接近的场景做参考然后用前面说的“先试跑调整学习率”的方法找到合适的区间。5.4 两个容易被忽视的优化器细节第一个是关于Adam的epsilon参数。Adam更新时会除以二阶矩的平方根为避免除以0公式里加入了epsilon默认值是1e-8。在混合精度训练中这个值可能太小导致分母过小、更新步长过大训练不稳定。我在AMP训练中会手动把epsilon调到1e-6或1e-7效果有明显改善。第二个是关于exponential moving averageEMA的用法。EMA是一种用参数的平均版本替代最终模型的技术很多大模型训练和半监督学习任务都在用。它不是优化器的一部分但和优化器配合密切。实际操作中EMA的衰减率通常设为0.999或0.99在模型收尾阶段用EMA版本做验证往往比直接用最后一步的参数表现更好。我自己在多个分类任务上验证过这一点EMA版本比普通版本的验证集指标普遍高出0.1到0.5个百分点。这个技巧的成本极低收益却很稳定建议养成习惯。写在最后的一些话从SGD到Adam再到AdamW和LAMB优化器的进化始终围绕两个核心问题怎么走得稳、怎么走得快。理解每一个优化器背后的设计动机比记住那些更新公式更有价值。因为在真正的训练过程中你总会在某个深夜遇到损失不降、指标上不去的问题那时候能帮你快速锁定原因的不是某条公式而是你对这些设计动机的理解深度。我自己的经验是遇到训练问题时先锁定优化器的状态是否正常学习率、梯度范数、权重衰减再考虑模型结构的问题。这个顺序在绝大多数情况下都能快速定位问题。优化器这个东西平时不显山不露水但在关键时刻它就是那个决定你能不能跑完全程的“方向盘”。