哪个优化器最好这问题我几乎每周都会被问一次。按惯例我会反问一句你的 batch size 是多少如果对方回答不上来那讨论优化器基本没有意义就像不考虑路况只问买越野车还是轿车好最后大概率得到一堆无法落地的建议。真正在训练里摸爬过的人都知道优化器和 batch size 从来不是独立的两件事情。batch size 决定了梯度估计的噪声水平而优化器恰恰又是靠梯度来更新参数的二者叠加在一起才会出现“我换了个优化器效果差了一截”这类困惑。所以这篇文章我打算换一个角度不是列一堆优化器的优缺点列表而是从 batch size 出发把什么场景该用什么优化器、学习率该配多大、踩过哪些坑一次讲透希望能帮你少走几趟弯路。1. 先说结论优化器之间没有“最好”只有“匹配”1.1 核心需求解析到底在选什么很多人在选优化器时只看一个指标最终准确率。但准确率是后验结果真正决定训练曲线走向的是两个东西梯度质量和参数更新策略。梯度质量由数据决定。batch size 越小每次计算用的样本越少梯度越“抖”噪声越大batch size 越大梯度越接近全量梯度的真值噪声越小。参数更新策略由优化器决定。SGD 系只会按当前梯度方向以固定学习率迈步Adam 系则会根据历史梯度自动缩放每一步的步长。理解了这两点你就能想明白一个关键事实不同优化器对梯度噪声的承受能力是不同的。一个对梯度噪声极其敏感的优化器配上小 batch可能训练曲线狂抖一个依赖梯度精细度的优化器配上大 batch也可能因为梯度太平滑而走不远。所以选优化器的本质是让你的更新策略匹配当前 batch size 下的梯度统计特性。1.2 batch size 才是那个被你忽略的变量我在前面强调过batch size 决定了梯度噪声水平这个噪声对训练的影响比大多数人想象的要大。先说噪声的数学来源。设每个样本的梯度为 (g_i)当前 batch 的平均梯度为 (\bar{g})那么梯度的方差大致按 (1/B) 衰减其中 (B) 是 batch size。也就是说batch size 从 32 变成 128梯度噪声立刻降了几倍更新方向会变得更加稳定。生产环境里很少有人同时记录梯度的方差变化但其实它对训练的每一步都有实际影响loss 曲线的抖动幅度、精度是否跳高、是否在局部极小值处停住背后都是噪声在起作用。有人会问既然噪声大不好那干脆把 batch 设大不就行了事情没那么简单。梯度噪声在训练中并不全是坏事它给参数更新带来了随机扰动这种扰动在一定条件下能帮模型跳出尖锐的极小值盆地最终泛化更好。这正是业界一直存在“大 batch 泛化差”讨论的原因之一——大 batch 的梯度更准但也更容易走到一个看似平坦、实则过拟合的区域。优化器在这里又插了一脚SGD 老老实实沿着梯度走噪声大的时候天然有探索行为Adam 则通过二阶矩归一化把不同参数的更新尺度拉平噪声被部分“抹平”小 batch 的优势也被削弱了。1.3 两条主线的碰撞简单画一下整个故事的主线。第一条线是 batch size 的梯度噪声曲线从大噪声到小噪声对应小 batch 到大 batch。第二条线是优化器的噪声容忍特性有的优化器对噪声敏感有的优化器对噪声钝感。两条线叠加之后会形成几个常见组合小 batch SGD梯度噪声大SGD 不缩放、不修正每一步都受当前 batch 的随机波动影响像是在凹凸不平的路上骑着自行车走路线曲折但不容易陷在原地。小 batch AdamAdam 会对梯度做指数滑动平均和尺度归一化相当于给自行车加了减震和导航抖动明显下降但是原本属于小 batch 的“探索性”也被削减。大 batch SGD梯度几乎不抖更新方向稳定像是走上了一马平川的直路但如果学习率没跟上就会一直以同样的步幅慢慢走训练效率低。大 batch AdamAdam 的归一化在这种场景下优势不大因为梯度本身已经很稳定但它有可能把更新步长算得过大造成后期震荡。所以你看优化器好不好取决于它和你当前的 batch size 是否顺路。判断顺不顺路最好先从你已经确定使用的 batch size 出发。2. 小 batch sizeSGD 系与 Adam 系的较量2.1 小 batch 的真正优势梯度噪声与隐式正则小 batch 一般指 batch size 在 2 到 64 这个范围。训练模型时尤其是视觉模型很多人习惯从 32 或 64 开始跑原因之一是显存够用另一个原因是小 batch 训练在不少任务上泛化表现并不差。我自己的理解是小 batch 的梯度噪声相当于一个隐式正则项。每次参数更新时方向不是朝着精确的梯度方向走而是有一个随机偏转。这个偏转如果幅度合适会让模型在损失曲面上走出更宽泛的路径不容易扎进某个过窄的沟里。很早之前某团队在公开分享里就提到过类似结论他们用小 batch 加较大的学习率训练出了泛化能力相当好的模型很多人以为秘诀在数据增强实际上随机梯度噪声贡献了相当一部分。当然噪声不是免费的午餐。小 batch 也意味着收敛不稳定least loss 可能要经历更多轮次才稳定。而且使用某些自适应优化器时噪声会被“滤掉”一部分隐式正则效果也要打个折扣。2.2 SGDMomentum 在小 batch 下的表现SGD 加 Momentum 是我在小 batch 场景下最先会尝试的组合。Momentum 解决的是 SGD 抖动过大的问题它让更新方向不仅依赖当前梯度还依赖历史的梯度累积像滚雪球一样越滚越有惯性。在小 batch 条件下单步梯度噪声大但 Momentum 将这些噪声做了时间维度的平均方向性就出来了训练曲线不会失控。我踩过的一个坑是 momentum 系数配得太大。默认值通常是 0.9对于小 batch 训练没问题但如果数据分布很不均匀0.9 的惯性会让参数在 loss 曲面陡峭区域停不下来出现 loss 反复横跳。建议从 0.9 起步如果曲线抖得厉害降到 0.85 甚至 0.8 看看。小 batch 配 SGD 时还有一个常见误操作学习率照搬 Adam 的默认值。SGD 对学习率的敏感度远高于 AdamAdam 用 1e-3 能正常收敛的任务SGD 用 1e-3 很可能发散。我通常给 SGD 的学习率设在 0.01 到 0.2 之间具体要看任务和 batch size先从 0.1 试再二分法调整每一步都观察前 200 轮的 loss 走势。2.3 Adam 系在小 batch 下的实测表现Adam 系列在 NLP、推荐、多模态领域几乎是默认选项。它对小 batch 的适应能力很强因为一阶矩让更新方向平滑二阶矩让不同参数的更新尺度不至于差太多。在小 batch 下Adam 训练出来的模型通常比 SGD 更容易达到一个不错的 baseline这就是为什么大家都喜欢用它做快速验证。但 Adam 在小 batch 下并非没有代价。它在接近收敛时可能出现 loss 震荡原因在于二阶矩估计在小样本上偏大导致有效步长偏大。实际训练里我习惯评估模型时选一段窗口内表现最好的 checkpoint而不是用最后一轮。另外 Adam 在在小 batch 场景下的 weight decay 要注意很多框架里 Adam 的 L2 正则与 weight decay 没有直接对应直接用了效果会偏弱或者偏强。现在几大深度学习框架也都支持解耦权重衰减的 AdamW这是替代 Adam 的比较稳妥的选择。2.4 小 batch 的避坑提醒小 batch 场景下最容易出问题的其实是数据读取和预处理环节。batch 小时每个 batch 的统计量不稳定如果用了依赖全局统计量的机制比如某些 normalization 方式很容易产生偏差。实践里可以把 batch 设到 16 或 8 测试一下如果训练曲线异常跳动优先检查是不是数据预处理中的均值方差不一致而不要一味地怀疑优化器。另外小 batch 下梯度裁剪也有讲究。Adam 对梯度量级有归一化能力梯度裁剪倒不是必须但 SGD 对极端梯度非常敏感偶发一个异常样本就可能带崩整条曲线。如果你只能用 SGD建议把全局梯度范数裁剪在 5.0 左右先跑通再微调这个值在大多数图像任务里都能避免发散。3. 大 batch size从崩溃到 LAMB/LARS 的救场3.1 为什么大 batch 容易训不动、甚至直接发散大 batch 一般指 batch size 在 256 以上现在很多大规模训练甚至用 2048、4096、8192 甚至更大。大 batch 的优势是训练吞吐高GPU 利用率好梯度方向稳定。但随之而来的问题很现实模型训不动或者直接训练失败。理论原因在之前已经提过大 batch 使得梯度噪声极小模型很容易被“推向”尖锐的极小值区域。尖锐的极小值泛化通常较差同时在后续训练时只要学习率稍大参数就会在陡峭边缘振荡造成 loss 忽高忽低。还有另一个原因大 batch 会改变损失曲面的有效几何结构让某些原本对优化器友好的路径变得不可达。这就好比导航重新规划了路线可是那条路根本不适合你的车开上去就颠簸。我亲身经历过的典型情况把 batch size 从 128 提到 1024其他一切不变第一轮迭代就出现 NaN。当时第一反应是学习率太大降到原来的四分之一虽然不再 NaN但 loss 下得非常慢最终效果还不如原来的小 batch。换了带 warmup 的方案之后才勉强正常。这些现象都指向一个根源大 batch 必须从头适配学习率和优化器不是简单翻倍 batch size 就能白捡吞吐量的。3.2 学习率缩放到底该怎么算关于学习率缩放最早被广泛讨论的是一次经验法则线性缩放。核心思想很简单batch 变大每个 batch 里累计的梯度信息更多如果学习率不变更新步长相对于有效梯度信息会变小收敛变慢所以学习率应该按比例放大。形式化地写如果基准配置是 batch size (B_0) 和学习率 (\eta_0)新配置 batch size (B)那么理论学习率 (\eta) 可以取 (\eta_0 \times (B / B_0))。举个例子原本 batch 128 配 lr 1e-3扩到 512 时理论 lr 应该是 4e-3。但线性缩放不是万能的。当 batch size 增长特别大比如几百到几千时线性缩放会让学习率变得过大直接发散。这时候平方根缩放更稳妥(\eta \eta_0 \times \sqrt{B / B_0})。还拿上面的例子平方根缩放给的是 2e-3明显温和得多。选择哪种缩放我的标准是这样如果只是从 64 扩到 256线性缩放没问题如果从 256 扩到 1024 以上或者任务本身对超参敏感先用平方根缩放再配合 warmup 观察前几百轮。还可以做一个简单校验训练前几十步内 loss 不应该出现爆炸性上升如果出现了就回到更小的学习率。3.3 大 batch 下的优化器选型大 batch 场景下纯粹的 SGD 会显得很吃亏因为梯度稳定后SGD 更像一个不带地图的司机learning rate 稍微没调好就偏航。Adam 比 SGD 稳定但它对大 batch 的适应性也不是天然就好关键在于它的二阶矩归一化可能把更新步长算得偏大尤其是在训练后期。专门为大规模分布式训练设计的优化器比如 LARS 和 LAMB把大 batch 的使用体验往前推了一大步。它们的核心思路是 layer-wise 自适应的学习率对每一层的参数根据其梯度和权重的比例计算专属学习率使不同层不至于因为量级差异而训练失衡。在目标检测、图像分类、大规模语言模型预训练这类场景我用 LAMB 跑过 4096 的 batch size训练收敛明显比 AdamW 更平滑而且对学习率的选择没有那么敏感。不过 LARS/LAMB 也不是万能。它们引入的额外超参会增加调参成本而且如果你只需要单卡或双卡训练分布式带来的收益远小于超参调试的成本我建议优先用 AdamW没必要为了追新而换。3.4 warmup 不是可选项是必选项大 batch 训练的另一个铁律是 warmup。为什么需要 warmup因为大 batch 在训练早期就遭遇了非常精确的梯度而模型参数还是随机初始化状态损失曲面又陡峭又复杂此时如果学习率一开始就很高步长会直接飞出去。warmup 让学习率在前若干步从一个很小的值线性升到目标值等于给参数一个从平庸到靠谱的缓冲过程。具体实现上多数框架都有内置的 warmup 参数。我一般用前 1% 到 5% 的总步数完成 warmup比如总步数 10000warmup 设 200 到 500 步。如果学习率目标很高比如线性缩放到 4e-3 或更高warmup 步数就多给一些宁可多花一点时间在热身阶段也别让前几十步把网络训练坏。4. 实操指南用 batch size 当路标来选优化器4.1 三个典型 batch size 区间与对应方案把 batch size 分成三个区间来看实际操作会清晰很多。区间一2 到 64。典型任务是微调、少量样本训练、在线学习。这种情况下推荐 SGD Momentum 或 AdamW。如果样本质量不高、噪声大优先 SGD Momentum配合 0.85 的 momentum 能平滑不少如果任务偏 NLP 或者你不知道怎么调 SGD那就 AdamW默认超参基本能跑不需要大量干预。区间二64 到 512。这是大多数单人项目和中等规模团队的标准区间。在这个区间里SGD Momentum 和 AdamW 都能用甚至可以说各有千秋。我习惯先同时跑两个小实验相同 batch size分别用 SGD Momentum 和 AdamW各跑几百轮看 loss 下降曲线和验证集表现。如果差距不大直接选 AdamW因为在后续修改模型结构、增加数据增强时AdamW 的鲁棒性更高。区间三512 到 8192 及以上。基本上进入了大 batch 世界。优化器层面优先考虑带自适应调节的版本如果训练任务又大又吃分布式吞吐那 LAMB/LARS 基本是必须的如果规模刚好在 512 到 1024 之间也可以先用 AdamW 配合线性缩放跑通再对比是否换 LAMB。这里的关键配套是 warmup 和目标学习率不要单独只动优化器。4.2 一张速查表照抄下面这张表是我从多个项目里总结出来的速查配置可以直接当起点。注意“起点”两个字很重要实际还是要根据 loss 曲线微调。batch size 区间推荐优化器初始学习率参考warmup 步数备注2-32SGD Momentum / AdamWSGD: 0.01-0.05AdamW: 1e-4 到 3e-4可省略注意数据加载器和 normalization 统计量不稳定的问题32-128AdamW / SGD MomentumAdamW: 3e-4SGD: 0.05-0.1100 步以内最常见的区间优先跑通流程128-512AdamW / SGD Momentum按 batch 比例适度缩放一般从 3e-4 出发建议加线性缩放可以用但别超过 4 倍512-2048AdamW / LAMB平方根缩放起步配合 warmup必须加优先跑小规模的 LAMB 对比实验2048 以上LAMB / LARS极保守起步如 1e-4 到 5e-4必须加且步数适当放大强调分布式吞吐优化别死磕单卡这张表里的学习率普通情况下可以跑出不错的效果但它不是一个保证值。你的任务、数据、模型架构都有影响我把表放在这里的意义是让你少试几组魔幻组合而不是替你终结所有调参工作。4.3 我的实测流程从 baseline 到生产我刚接手一个新任务时不会一上来就大规模调超参。第一步固定 batch size 为 32优化器选 AdamW学习率 3e-4跑一个短周期。这个组合小、快、稳能迅速暴露模型结构和数据上的问题。模型能正常达到一个baseline之后再决定要不要换大 batch。如果目标是提升训练吞吐量我会先把 batch size 翻倍到 64再线性缩放学习率到年左右 6e-4跑通再说。第二步从 64 到 128继续线性缩放。到 256 附近我会停下来比较当前配置与最初配置的效果差距。如果差距明显我不会急着扩大 batch而是先回退一步在当前的 batch 下重新优化学习率和 momentum。还有一点实践经验在生产训练里不要为了“显存刚好能塞下最大 batch”就把 batch 设到最大。batch size 要匹配你的显卡数量和分布式方案找到吞吐拐点比最大 batch 更关键。GPU 利用率、通信开销、data pipeline 都会影响总吞吐。一次训练用 batch 512 和 1024 的总吞吐可能几乎一样但效果上 1024 的调参难度高不少这种收益不划算。5. 常见问题与排查实录5.1 大 batch 一冲就 NaN大 batch 训练第一轮迭代就 NaN优先级最高的问题就是学习率和初始化。我的排查步骤是先看是不是学习率太高把学习率降一个数量级比如从 1e-3 降到 1e-4观察前 20 轮如果还在 NaN再看梯度里有没有异常值输出当前层的梯度范数最后再检查数据看看有没有 NaN 样本进入 batch。一个比较容易忽略的现象当 batch 变大时现有的数据增强逻辑可能引入了重复样本或相关性极高的样本这也会让梯度异常。还有某些 normalization 层在 batch 很大时统计量稳定了但与之前小 batch 训练时的统计量完全不同导致极端激活值出现。遇到这类问题不应盲目认为是优化器的问题先把数据和网络输出检查一遍再调超参。5.2 loss 不降或降得很慢这种情况往往不是因为优化器选错了而是学习率没跟上 batch size 的变化。举一个具体例子原本 batch 64 配 lr 1e-3扩到 256 之后还保持 1e-3loss 下降明显变慢原因前面说过梯度信息多了但步长没变等效于每步的推进变小了。解决方法是按残留公式缩放从 64 到 256线性缩放到 4e-3如果怕不稳用平方根缩放到 2e-3。但也要注意另一面有的任务在扩 batch 后 loss 曲线确实更平滑可收敛精度反而更低这时就要考虑是不是优化器的探索能力不够可以试着换回 SGD Momentum 或调大 momentum。5.3 batch 翻倍后效果变差这个问题的本质其实是泛化变差。大 batch 收敛到了过拟合程度更高的尖锐极小值这在视觉任务里尤其常见。如果只是精度低一两个百分点最简单有效的办法是把 batch size 往回退然后用数据增强、Dropout 等正则手段来补效果而不是硬扛。如果你想在保持大 batch 的情况下提升效果可以考虑加更强的权重衰减或者学习率退火。一个大 batch 训练里后期的学习率衰减速度直接影响最终收敛位置我在实践中发现余弦退火配合大 batch 往往要优于等间隔下降效果能追回不少差距。5.4 微调场景下该怎么选微调通常算小 batch 场景但问题是预训练模型已经在一个大类分布上收敛过直接用小 batch 和自适应优化器很容易破坏原有特征结构。我的做法是先用很小的学习率跑比如 2e-5 到 5e-5batch size 32 到 64优化器选 AdamW关掉 or 极度减小权重衰减。如果微调的损失函数与原预训练任务差异很大我建议把某些层的学习率单独控制通常最后几层的学习率可以放得大一点前面的特征层稳步保底。另外要特别小心优化器的 epsilon 参数某些模型在低精度推理时对 epsilon 敏感实测中建议把 epsilon 从默认的 1e-8 提到 1e-6 以增强稳定性这个细节在混合精度训练里尤其重要。6. 写在最后选优化器的最终思路说了这么多我想强调的只有一句话优化器从来不是孤立变量它的好坏要放到 batch size、学习率、训练任务组成的大上下文里判断。我个人的拿手做法是每个新任务先跑一个 AdamW 小 batch 的短实验确认模型和数据没问题然后根据目标 batch size 范围选择主优化器和配套学习率最后用 warmup、学习率调度和必要的正则手段处理大 batch 或微调场景下的特殊问题。这套流程不复杂但能避免大量无效换优化器的折腾。如果非要给一个最通用的起点单卡环境、batch 64 左右、AdamW、学习率 3e-4、先跑通再从曲线出发做下一步决策。这不是什么高深技巧却是很多项目里最常被忽略的第一原则先让训练跑起来再谈优化器好不好。