
开篇先说一个比较反直觉的观察大模型训练里真正决定你loss曲线“气质”的往往不是网络结构也不是数据配比而是优化器那几行参数。很多人把Transformer代码从GitHub上拉下来数据、模型、学习率都照抄唯独优化器随便填了个Adam结果loss不降、梯度爆炸、loss spike频发懵圈半天也不知道问题出在哪。作为刚跑完一条7B模型训练链路的人我这次专门把优化器这一环拆开讲清楚。本文会围绕大模型训练中优化器的演进、Adam与其变体的实际工程配置、以及Muon这种新方向的实验价值展开顺带聊一聊大家经常忽视的“曲线塑型”——也就是学习率调度器。1. 优化器到底在解哪道题1.1 损失曲面上“下山”的三种走法优化器要解决的核心问题可以简化成一句话在高维参数空间里找到让loss下降的方向和步伐。这个问题的难度在于大模型的参数动辄几十亿上百亿损失曲面不是我们脑子里想象的那种二维碗状它是一个极端复杂的超高维地形。大部分优化器做的事本质上是“梯度下降”的改良版。最基本的SGD按梯度反方向走步长等于学习率乘梯度。它的缺点是明显且致命的——如果某个维度梯度很大它就会冲过头如果某个维度梯度很小又挪不动步子。大模型里参数分布跨度极大有的嵌入层梯度稀疏且微小有的中间层梯度巨大一个三维球面模型用SGD训练LLM几乎等于拿一把固定尺子去量各种尺寸的桌子总会有一堆地方不合适。动量方法Momentum解决了一部分问题。它给梯度加了个“惯性”让优化轨迹更平滑能冲过局部极小值但本质上还是所有参数共用同一个学习率。这套路在CV的小模型上够用放到LLM这种几十亿参数的场景里就显得粗糙。而以Adam为代表的自适应学习率优化器干脆放弃“所有参数统一步长”的想法给每一个参数都配一个动态步长。这在两个维度上同时解决了问题——既照顾了稀疏梯度又抑制了大梯度带来的震荡。大模型训练能真正跑起来Adam系功不可没。1.2 为什么SGD在大模型身上越来越吃力我见过不少刚接触LLM训练的人第一反应是“SGD最经典就用它了”。如果模型只有几百万参数、数据量也不大确实没问题。但一旦参数量上到B级SGD的短板就会被无限放大各层梯度量级差异巨大固定学习率必然顾此失彼训练序列长梯度噪声大SGD对噪声的鲁棒性弱学习率调整窗口窄warmup稍微给高一点就直接一步迈过稳定区实际训练中SGD在7B模型上的表现是loss降到一定程度后开始锯齿状抖动进一步调低学习率能稳住但收敛速度慢得让人失去耐心。相比之下Adam不仅收敛快对超参的容忍度也高得多。这就是为什么现在主流开源项目里默认优化器几乎清一色是Adam或AdamW。2. Adam家天下统治LLM训练十年的核心机制2.1 自适应学习率每个参数各有各的步长Adam的全称是Adaptive Moment Estimation它的核心机制是同时维护两个状态量梯度一阶矩估计等价于动量和梯度二阶矩估计对应梯度平方的滑动平均。先看更新公式简写m_t beta1 * m_{t-1} (1 - beta1) * g_t v_t beta2 * v_{t-1} (1 - beta2) * g_t^2 m_hat m_t / (1 - beta1^t) v_hat v_t / (1 - beta2^t) param param - lr * m_hat / (sqrt(v_hat) eps)每次迭代Adam把历史梯度做了一次带衰减的累积然后用二阶矩的平均值去“归一化”更新量。直观理解就是如果一个参数的梯度一直很大v_hat就涨上去了分母变大那这一步的实际更新量就被压小如果一个参数的梯度一直很小分母变小更新量就被放大。用大白话说Adam在做的是不论你梯度强还是弱我都能给你一个相对合适的步长。这在大模型里至关重要。Embedding层参数的梯度分布极其稀疏大量参数长时间收不到有效梯度而输出层的梯度却密集且量级大。同一套学习率要让这两类参数都正常工作只有自适应步长能做到。2.2 AdamW、beta、eps、weight decay这些超参数该从哪调起Adam虽然好用但直接把weight_decay加到Adam上会有问题。Adam自己带了自适应学习率而权重衰减项在这个框架下没有得到同样的“归一化”导致两个机制互相干扰。AdamW的核心改动是把权重衰减从梯度计算中剥离直接作用在参数更新之后公式就变成param param - lr * (m_hat / (sqrt(v_hat) eps) weight_decay * param)这在7B量级模型上带来的是更干净的loss下降曲线尤其是预训练后期AdamW的收敛稳定性与最终指标普遍优于经典Adam。现在几乎所有的LLM训练代码都用AdamW如果你看到某个框架默认Optimizer写的是Adam建议先确认它底层是不是已经做成了AdamW的解耦形式。关于超参数我直接给一版经过验证的推荐起点超参数推荐值原因lr1e-4 ~ 3e-47B量级再大容易梯度爆炸再小收敛过慢beta10.9动量衰减系数基本很少有人动beta20.95 ~ 0.98比默认的0.999更激进能缓解后期loss的不稳定eps1e-8 ~ 1e-6太小会出数值问题太大则丢失自适应效果weight_decay0.01 ~ 0.10.01是常见起点WSD调度时可试更小beta2是很多人忽略掉的关键旋钮。默认0.999代表二阶矩的估计窗口非常长前期的梯度信息会影响很久在长序列训练里容易让更新方向滞后。我实测过把beta2从0.999改到0.95在部分数据集上loss下降明显更顺。2.3 分布式训练下优化器状态的耦合与同步到了多卡训练这个级别优化器就不再只是数学公式和几个超参数的事它还要负责把梯度在设备间同步好。现在主流方案是DDPData Parallel加All-Reduce或者ZeRO阶段式分片。All-Reduce对优化器的影响是——每个rank上的优化器状态理论上应该是同步更新的只要初始参数一致、训练数据顺序一致、All-Reduce没丢梯度优化器状态就会保持一样。这背后有个容易踩坑的点如果开了梯度累积gradient accumulation务必要在所有rank的同一批微批次上同步累积。实践中我遇到过某次rank 2的梯度累积顺序被打乱结果是loss曲线出现周期性规律异常排查了很久最后发现是DataLoader的shuffle在不同rank上没有固定随机种子导致。另外ZeRO把优化器状态切分到了不同GPU上每个rank只更新自己负责的那部分参数。这种场景下优化器引入的顺序就变得很关键——参数更新前必须完成梯度的Reduce-Scatter否则你优化器拿到的梯度不完整更新出来的参数状态直接错乱。3. Adam的光鲜与暗面显存账、泛化差、loss spike3.1 一比八的显存账Adam或者说AdamW对显存的索取是很多初学者没有概念的。算一笔账Trainable Parameters里每1个FP32参数AdamW需要额外的8字节优化器状态——4字节给一阶矩m4字节给二阶矩v加上模型本身的4字节FP32权重副本再加上参数梯度的4字节总占用达到参数量×16字节。而纯SGD加Momentum呢只需要参数量×12字节。听起来差距不大但在7B这个量级上区别是28GB和56GB的差距。这也是为什么LLM训练几乎一定要配合混合精度AMP和参数分片来做。实际工程里最常用的组合是BF16保存参数和梯度FP32保存优化器状态。这样单个参数在显存里的开销大约是8字节优化器状态2字节模型权重省了一块不小的空间。如果你用的是DeepSpeed ZeRO-3或FSDP优化器状态会被继续切分到各卡上显存压力进一步下降。3.2 为什么自适应优化器的泛化经常不如SGD这里有一个比较扎心的研究结论Adam在训练集上的收敛通常比SGD更快但在验证集上的泛化表现尤其是小数据量的情况下往往不如SGD配合精细调度的结果。最主流的解释集中在Adam对梯度做的是“逐参数归一化”这种操作会破坏梯度方向的一致性——它保留的是梯度符号而非幅度信息导致优化轨迹过于曲折最终收敛到的平坦度不如SGD。大模型领域之所以仍然用AdamW是因为在十亿参数以上的规模里泛化差异被数据和正则手段弱化了Adam的稳定性和超参鲁棒性反而成了更稀缺的价值。如果你做的是领域模型微调数据量不大而之前的经典SGD基线表现很好别急着把优化器换成AdamW。先想想训练稳定性谁更强——这个问题的答案直接决定你该选哪种优化器。3.3 混合精度下优化器的“隐藏炸弹”BF16混合精度训练下优化器状态必须保留FP32精度。很多人在这一步会犯一个错误把优化器状态也转成BF16来省显存。表面上看loss曲线还能跑但训练后期会出现精度塌陷式的loss spike因为BF16只有8位尾数二阶矩和动量在这样的精度下会把小数部分完全截断等于是让优化器在“用整数做决策”。另一个容易踩的点是梯度裁剪gradient clipping的阈值。优化器里的max_grad_norm我见过很多版本有人设0.5有人设1.0还有人不设。我的经验是在7B量级上设1.0基本够用但如果你开了gradient accumulation需要等累积完再统一裁剪而不是每个微批次都剪一次。逐个微批次裁剪会严重低估梯度的真实测量导致实际更新步长过大。4. Muon别急着唱衰Adam但确实有新东西4.1 从梯度里提取“方向”而不是“大小”最近一段时间Muon优化器在个别大模型训练实验中出现得越来越频繁。它的基本思路是基于动量的方向信息使用Newton-Schulz迭代提取参数更新方向的正交基。简单来说Muon不去做逐元素的归一化而是把更新向量往“近似正交”的方向上投影然后再乘以一个全局学习率。这个思路的吸引人之处在于它试图重新强调梯度的方向结构而不是Adam那种只盯着单参数独立幅度的做法。直观地类比一下Adam像是一个给每个学生单独定KPI的班主任Muon则是先协调全班踩点同一套节奏再统一推进。从实验结果看Muon在部分语言模型任务上表现出了与AdamW相当甚至更好的收敛速度和最终精度尤其是当模型宽度较大时。但这类实验大多还停留在科研和小规模复现的层面工程成熟度与AdamW的生态完全不在一个量级。4.2 Newton-Schulz迭代在优化器里的角色如果只看代码Muon的核心改动其实在“对更新矩阵做正交化”。内层用的Newton-Schulz迭代通常只需要几次就能把矩阵推向正交。这个操作的作用是确保每次参数更新的“旋转分量”是被抑制的只保留“拉伸分量”显著的部分从而做到更干净的几何更新。这里也解释了一个现象——为什么Muon需要把参数组织成二维矩阵做更新。它天生就不是给Embedding这种形状随意的张量设计的权重矩阵化的场景才能发挥它的投影优势。对Transformer里的QKV矩阵和FFN权重Muon的效果相对理想对其他零散的小参数通常还是回退到Adam。4.3 现阶段复现Muon要注意什么如果你想去跑一版Muon作为实验组有几个实际工程层面的问题先想清楚现有训练框架对Muon原生支持较少大概率需要手写Optimizer耦合到Trainer里分布式场景下Newton-Schulz迭代涉及矩阵计算通信模式与Adam的All-Reduce不太一样需要验证扩展性学习率调度器在Muon下的行为目前没有公认标准不要照搬Adam的cosine策略我自己在300M规模的模型上试过Muon结论是能收敛最佳效果与AdamW接近但没有明显拉开差距。在更大参数规模下的收益目前还在等更多实验数据。如果你是做训练的建议把它当作一个“技术雷达”保持关注而不是立刻全量切换。5. 真正负责“曲线塑型”的是学习率调度器5.1 一个调度器三段式warmup、主训练、退火很多人在配优化器的时候只关心选哪个优化器和设置学习率却把调度器当成一个可选的附属品。这是对“曲线塑型优化器”这个词最大的误解。我理解的曲线塑型指的就是用调度器控制学习率曲线从而控制loss曲线的形态。一套主流的LLM训练调度器通常由三个阶段构成Warmup阶段学习率线性从0上升到峰值。作用是把稳定的大更新量先憋住等激活值、梯度分布都建立起来之后再逐步放开。主训练阶段学习率保持在峰值附近或恒定平台。这是模型学习能力最强的阶段也是最容易发生loss spike的区间。调度器在这个阶段越稳训练质量越可控。退火阶段学习率快速衰减到接近0。这一阶段的目标是净化模型把它从前期的不稳定学习中修复过来让loss曲线走向低点。这三个阶段的长度比例通常由迭代总数决定。如果你有一百五十万步的总预算warmup放到两三千步大部分时间段保持恒定最后留出5%~10%的迭代做退火是一个通用性很强的方案。5.2 常见调度器对比cosine为什么是默认首选实际工程里最常用的几个调度器是这样的调度器行为适用场景linear decay峰值线性降到0微调任务预算紧张cosine decay峰值为1的余弦曲线平滑下降预训练大多数场景npm上默认首选constant decay先恒定后快速下降WSD风格训练one-cycle先用极短时间升温再快速降温小规模微调不容易适配大模型cosine调度器之所以成为默认主要是因为它在主训练阶段保持相对高的学习率退火前的下降曲线非常平缓而在后半段又给出了一个平滑而充分的“软着陆”让模型在最后一轮迭代期间逐步收敛而不是突然被压低学习率导致参数摆动。但我自己的体会是WSD的变体warmup-stable-decay在纯预训练任务上越来越值得试。做法是训练的前90%阶段恒定学习率最后10%退火到接近0甚至可以退火后再恢复训练。这种安排的好处是第一阶段模型充分探索退火阶段再清理激活值和参数噪声loss曲线的整体形状非常干净。5.3 loss曲线“形状”异常时先查优化器还是先查调度器训练中遇到loss异常大部分人的第一反应是改学习率调调度器但优化器状态才是更重要的“暗病”来源。我的排查顺序是先检查优化器状态是否和预期一致——尤其看二阶矩v_hat里是不是积了一大片异常大的值再看max_grad_norm裁剪逻辑与梯度累积顺序最后才动调度器举个例子我在训练中遇到过一种loss表现前期下降正常后期突然周期性翘起。最开始怀疑调度器退火不对调了好几版调度参数都没用。后来打开优化器检查二阶矩发现某个Transformer层的v_hat数值比其他层大了一千倍原因是该层输入出现了一个OutlierAdam的sqrt(v_hat)分母被撑爆学习率几乎被清零参数卡死在局部区域。这种情况你不管怎么调调度器都没用要么加强grad clipping到这一层单独处理要么在输入侧加LayerNorm的epsilon稳定内部值。还有一个常见场景是loss曲线在warmup结束时出现“悬崖式下降后回弹”。这通常不是调度器的问题而是优化器的bias correction在早期大步长下还没进入稳定状态。这里我建议warmup步数和beta2不要同时拉极端值。beta2为0.95配很长的warmup整体更新会过于激进回弹概率明显上升。在实际操作里我最常对刚接手训练工程的同事说的一句话是“优化器选型只占1%的功夫剩下99%都是超参协调。”AdamW配cosine调度也好Muon配WSD也罢关键是你要理解每个旋钮分别在控制什么以及它们之间的耦合关系。如果你现在要跑一个新实验我的建议是先照抄一套已经有成功案例的完整配置。别混搭——不要用AdamW的配置表去跑Muon也不要用开源库里SGD的调度策略套到LLM预训练上。等训练稳定了再逐步去调beta2、weight_decay和退火阶段的长度每一项只动一个变量同时记录loss曲线与梯度统计的变化。大模型训练跑起来之后时间成本和试错成本都很贵优化器这个环节看似基础值得在前期的配置阶段一次性做对。