#二、逐题详细解答
#177. SGD、Momentum、Adam、AdamW 的核心区别是什么?
#知识点
- 一阶梯度下降
- 速度项 / 指数滑动平均
- 自适应学习率
- decoupled weight decay
#详细解答
先看最基础的 SGD。它的想法最直接:当前梯度指向哪里,就往反方向走一点,所以更新规则几乎就是“参数减去学习率乘梯度”。它的优点是简单、可解释、状态轻;缺点是遇到不同维度梯度尺度差异很大、噪声很重或峡谷型 loss surface 时,容易震荡、收敛慢、调参也更敏感。
Momentum 在 SGD 上加了一个“速度”概念。它不会只盯当前一步梯度,而是把过去几步梯度做指数滑动平均,再沿这个平均方向更新。这样做的好处是:真正稳定的下降方向会被不断积累,来回摆动的噪声会被部分抵消,所以训练通常更平滑、也更快。
Adam 再往前走一步:它既记一阶矩(类似 Momentum 的平均梯度),也记二阶矩(梯度平方的滑动平均),然后用二阶矩去缩放更新步长。直觉上,梯度总是很大的参数维度会自动缩小步子,梯度总是很小的维度会自动放大步子,所以它在尺度不均、稀疏梯度、多模块同时训练的场景里通常更好用。
AdamW 则是工程上更标准的大模型版本。很多人会把它误解为“带 weight decay 的 Adam”,但关键不只是“有 decay”,而是“decoupled”。它把参数衰减从梯度项里单独拿出来做,让正则化语义更清晰,也避免和 Adam 的自适应缩放纠缠。今天大模型训练里大家提优化器,默认说的很多时候其实就是 AdamW,而不是老式 Adam。
#178. 为什么 Adam 往往前期收敛更快,但泛化未必最好?
#知识点
- 自适应步长
- 早期下降更快
- 坐标级缩放
- 泛化与平坦极小值
#详细解答
Adam 往往前期收敛更快,核心原因是它会根据每个参数维度的历史梯度统计,自适应调整步长。对于那些梯度特别大、特别抖的维度,它会自动踩刹车;对梯度很小的维度,它又会自动放大更新。所以在训练刚开始、参数尺度很不均匀、网络还没进入稳定优化阶段时,Adam 往往比 SGD 更省心,也更快看到 loss 往下掉。
但“更快下降”不等于“最终泛化一定更好”。一个常见经验是:自适应优化器更擅长快速找到一个能把训练集 loss 压下去的区域,但这个区域未必是最平坦、最稳健、最能泛化的解。很多论文和经验报告都发现,在视觉模型或某些监督任务里,训练后期切回 SGD 或直接用调得很好的 Momentum SGD,有时能拿到更好的泛化。
面试时最好不要把这个问题说成绝对结论。更稳的讲法是:Adam 往往在前期优化效率和易用性上更强,但是否泛化更差,要看任务类型、模型规模、正则化、学习率日程以及你是否真的把 SGD 调到了同等认真程度。大模型训练里大家更常用 AdamW,更多是因为它在超大规模场景下的工程稳定性和调参效率占优,而不是因为“它理论上一定最强”。
#179. AdamW 为什么要把 weight decay 从梯度更新里解耦?
#知识点
L2正则 vs weight decay- adaptive scaling 干扰
- 正则强度失真
- 参数收缩单独执行
#详细解答
在普通 SGD 里,把 L2 正则项加进梯度,和做 weight decay 在很多情况下看起来差不多;但到了 Adam 这种自适应优化器里,两者就不再等价了。原因在于:如果你把 lambda * w 直接加进梯度,这部分“正则梯度”也会一起被二阶矩缩放。于是不同参数因为历史梯度统计不同,实际承受的衰减力度也会不同,weight decay 的语义就被扭曲了。
AdamW 的做法是把这件事拆开:先按 Adam 规则处理真正的数据梯度,再单独做一次参数收缩,例如 w <- w - lr * wd * w。这样一来,weight decay 就重新变成了“和参数值本身成比例的明确收缩”,不会再被自适应学习率隐式放大或缩小。
这件事在大模型训练里很重要,因为你往往要同时管理预训练稳定性、泛化和参数范数控制。如果正则化强度随着不同参数组乱飘,后续调学习率和调 decay 会非常混乱。所以 AdamW 的价值不是一个教科书小修正,而是把优化器行为重新拉回“更好调、更可解释”的状态。
#180. RMSProp、Adafactor、LAMB、Lion 各自更适合解决什么问题?
#知识点
- 非平稳梯度
- 因子化二阶矩
- 大 batch 训练
- 低状态更新
#详细解答
RMSProp 可以看作很多自适应优化器的早期代表。它主要维护梯度平方的滑动平均,用来按维度归一化更新步长,因此很适合梯度尺度变化大、非平稳的任务。虽然今天在大模型预训练里不如 AdamW 常见,但它的核心思想——“用二阶统计稳定步长”——仍然影响了后来的许多方法。
Adafactor 的重点不在“更快”,而在“更省状态”。标准 Adam 要给每个参数保存完整的一阶、二阶矩,而 Adafactor 会对大矩阵参数的二阶统计做因子化近似,因此显著减少 optimizer state 内存。这在超大模型、超大 embedding 或资源受限训练里很有价值。代价是:实现更复杂,调参也往往没有 AdamW 那么无脑稳。
LAMB 的关键词是“大 batch”。它会在 layer-wise 层面做归一化和缩放,使得超大 batch 训练时每层更新幅度更可控。你可以把它理解成:不仅看全局梯度,还看这一层参数范数和更新范数的匹配关系。它在一些大规模 BERT 训练场景里比较常见。
Lion 更像最近几年对“能不能把状态做得更轻”的探索。它用 sign-based 更新和动量思想来减少状态和运算,理论上更轻、更省,但通常对超参更敏感,也还没有在大模型主流预训练里完全替代 AdamW。所以面试时最稳的总结是:RMSProp 重在自适应步长,Adafactor 重在省状态,LAMB 重在大 batch 稳定,Lion 重在更轻量的更新形式。
#181. 优化器状态为什么会吃掉这么多显存?怎么快速估算?
#知识点
- 一阶矩 / 二阶矩
- master weights
- 参数倍数估算
- 全参训练显存大头
#详细解答
优化器状态吃显存,最直接的原因是:很多优化器不仅要存参数本身,还要为每个参数再存几份历史统计。以 Adam/AdamW 为例,通常至少有一份一阶矩 m 和一份二阶矩 v。如果你在 mixed precision 下训练,还常常会保留一份 FP32 master weights 作为高精度更新副本。于是参数不是“一份就够”,而是很容易扩成多份。
一个很常见的数量级估算是:如果参数用低精度存,比如 BF16/FP16,但 optimizer state 和 master weights 用 FP32,那优化器相关内存经常能达到参数本体的数倍。也就是说,一个看上去“模型权重才几十 GB”的模型,真正全参训练时,显存大头可能根本不在权重,而在 optimizer states。
这也是为什么很多大模型训练方案一上来就要讲 ZeRO-1、FSDP、8-bit optimizer 或 Adafactor。因为当模型规模一上来,优化器状态往往比你直觉里更先成为瓶颈。面试里如果你能顺手把“参数、梯度、优化器状态、激活”这几块一起串起来讲,说明你不只是知道优化器公式,而是真的理解训练内存结构。
#182. 为什么大模型预训练里最常见的是 AdamW,而不是纯 SGD?
#知识点
- 稳定性优先
- 调参成本
- 模块异质性
- 工程成熟度
#详细解答
大模型预训练通常不会优先选纯 SGD,核心不是因为 SGD 过时了,而是因为大模型训练的优化环境过于复杂:网络很深,模块很多,参数尺度差异大,梯度噪声重,训练时间长,而且一次训练成本极高。此时大家更需要的是一个“默认就比较稳、在大多数子模块上都不太容易出事”的优化器。
AdamW 恰好满足这个需求。它有自适应步长,能在不同参数维度上自动调节更新尺度;它有动量统计,能让训练更平滑;它的 decoupled weight decay 又让正则化更好调。更重要的是,围绕 AdamW 的工程生态最成熟:warmup、cosine decay、gradient clipping、mixed precision、参数分组这整套经验几乎都已经标准化了。
所以在大模型预训练里,选择 AdamW 往往不是因为“它最优”,而是因为在综合工程风险、训练稳定性、调参成本和复现经验之后,它仍然是目前最稳妥的默认方案。
#183. 什么时候会考虑 Adafactor、8-bit optimizer 或其他省状态优化器?
#知识点
- optimizer state 成为瓶颈
- 资源受限训练
- 显存与稳定性权衡
- 大模型长训场景
#详细解答
当你发现训练真正卡住的不是激活,而是 optimizer state 时,就该认真考虑省状态优化器了。典型信号包括:模型参数明明能放下,但一开 optimizer 就爆显存;ZeRO/FSDP 已经用了,还是被状态拖死;或者你做的是资源受限微调,希望在单机上尽可能省内存。
这时常见选择有两类。第一类是像 Adafactor 这样从算法层面减少状态存储,通过因子化近似压缩二阶矩;第二类是 8-bit optimizer,把原本 FP32 的优化器状态做低比特量化存储。两者都能显著省状态,但代价也不同:前者更偏算法替换,后者更偏工程压缩;前者可能改变优化行为,后者则可能引入量化误差和实现复杂度。
所以这类方案的正确定位不是“更先进的优化器”,而是“当显存瓶颈来自 optimizer state 时的专项武器”。如果你的训练本来就稳定、资源也够,很多团队还是会优先选经验最丰富的 AdamW。
#184. mixed precision 训练里,master weights、loss scaling 和 optimizer 有什么关系?
#知识点
FP16/BF16下溢风险FP32master copy- gradient unscale
- optimizer step 数值稳定
#详细解答
mixed precision 训练的目标是省显存、提吞吐,但低精度带来的第一大风险就是数值不稳定。尤其在 FP16 下,很多很小的梯度可能直接下溢成 0,或者在累积时丢失精度。为了解决这个问题,许多实现不会直接用低精度权重做最终更新,而是维护一份 FP32 master weights,把真正的 optimizer step 落在这份高精度副本上。
loss scaling 则是在梯度产生之前先把 loss 放大,使得反向传播出来的梯度在低精度范围里不至于太小。等到真正执行 optimizer step 前,再把梯度反缩放(unscale),然后做梯度裁剪、溢出检查和参数更新。也就是说,loss scaling 和 optimizer 的关系非常紧:它不是训练前后无关的包装,而是直接影响你能否安全执行那一步更新。
面试时如果问这个问题,最稳的回答顺序是:为什么低精度会不稳 -> 为什么需要 FP32 master weights -> 为什么需要 scaling/unscaling -> 为什么这些步骤必须和 optimizer step 串在一起。
#185. 如果训练不收敛,怎么判断是优化器问题,还是学习率、batch size、数据或实现问题?
#知识点
- 最小复现
- 学习率 / warmup / clipping
- 数值溢出
- 数据与实现隔离
#详细解答
遇到“不收敛”,最忌讳一上来就换优化器,因为优化器往往不是第一嫌疑人。更稳的排查方法,是先把问题拆层。第一层看数值:有没有 NaN/Inf、有没有 gradient overflow、loss scaling 是否频繁回退。第二层看学习率和调度:初始 lr 是否太大、warmup 是否不足、weight decay 是否过重、gradient clipping 是否缺失。第三层再看 batch size 和数据:是不是 batch 太小导致噪声过大,或者数据本身有污染、label 错、分布突变。最后才去怀疑优化器类型和它的 betas/eps 等超参。
一个很好用的原则是做最小隔离:缩小模型、固定一小段数据、只跑几百步、保持单卡和最简单配置,看 loss 是否还能稳定下降。如果最小版本都不行,多半是数据、实现或学习率问题;如果最小版本正常,放大后才坏,才更像优化器超参、并行、mixed precision 或 batch 相关问题。
所以“判断是不是优化器问题”的高分答案,不是报一个经验,而是体现出你知道排查顺序:先排实现和数值,再排日程和 batch,最后才轮到优化器本身。
#186. 手写一个 optimizer step 时,最容易写错哪些细节?
#知识点
- bias correction
eps位置- decoupled weight decay
- grad clipping / zero grad / unscale 顺序
#详细解答
手写 optimizer step 时,最常见错误其实不是公式背错,而是工程细节顺序错。比如写 AdamW 时,把 weight decay 直接加进梯度,结果又退化成了 Adam + L2;又比如忘了做 bias correction,导致前几步一阶、二阶矩估计明显偏小;再比如把 eps 放错位置,或者先更新参数再更新动量状态,都会让行为和标准实现不一致。
mixed precision 场景下还会多一层坑:如果你在 unscale 之前就做梯度裁剪,或者 overflow 发生后还照常 step,训练就会莫名其妙漂掉。再往下还有 zero_grad(set_to_none=True)、参数分组里不同 weight decay / lr、冻结参数要不要跳过更新,这些都是真实工程里经常踩的点。
所以面试时如果被问“实现 optimizer 容易错哪”,高分回答不是只说一个公式,而是能把“数学细节 + 更新顺序 + mixed precision + 参数分组”这四类问题都点到。