JOVANA
Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

动量、Adam 与学习率

朴素的梯度下降只能在损失曲面上小心翼翼地一步步爬行。本篇带你认识那些把爬行变成又快又稳的下降的技巧——动量、Adam 这类自适应优化器、以及学习率调度——并诚实地告诉你该如何调参。

为什么朴素梯度下降还不够

到现在你已经掌握了核心动作:随机梯度下降读取一个小批量,计算损失的梯度,然后把每个参数朝下坡方向轻推一小步。重复几百万次,原则上你就能抵达一个不错的解。但实际中,朴素的 SGD 就像在浓雾中下山,每一步都朝当下最陡的方向迈——而这条简单规则有两个恼人的失败模式,会浪费掉大量的训练时间。

第一是峡谷。许多损失曲面形如又长又窄的山谷:横向很陡,纵向几乎平坦。最陡方向指向谷壁而非谷底,于是 SGD 在两壁间来回弹跳,前进得慢得令人抓狂。第二是噪声:因为每一步用的是不同的小批量,梯度会抖动,即使在简单的坡面上路径也会曲折往复。这两个问题有同一个解法——设法把最近的若干步做平均,让一致的方向被强化、随机的抖动被抵消。

动量:让小球有点重量

动量借用了一个物理比喻。与其把参数看成沿每个梯度瞬移的无质量质点,不如想象一颗沉重的小球在山坡上滚下。这颗球保有一个速度——一段关于它一直朝哪个方向走的运行记忆——而梯度只是去轻推这个速度,而非独断整个步子。一致的下坡推力会累积成真正的速度,而峡谷里左右的抖动因为不断变号,大体会相互抵消。

# v starts at zero. beta is the momentum (e.g. 0.9)
v = beta * v + (1 - beta) * grad   # update the running velocity
param = param - lr * v             # step along velocity, not raw gradient
动量维护一份梯度的指数移动平均。beta=0.9 大致意味着每一步都记得最近约十个梯度。

唯一的旋钮 `beta`(常取 0.9)控制过去有多重要:越大意味着球越重、惯性越大、运动越平滑,但也越容易冲过头——它可能在掉头前越过谷底。这种冲过头通常是优点而非缺陷,因为它能帮助球滑过那些会困住胆小优化器的小坎和浅局部凹陷。一种常见的改良叫 Nesterov 动量,它在落子前先朝前探一步,从而稍微抑制冲过头。

自适应优化器:每个参数各有步长

动量解决的是*方向*问题。自适应优化器攻克的是另一个问题:对于一个有些参数梯度极大、有些极小的模型,用单一的全局步长是不合适的。AdaGrad是第一个流行的答案。它为每个参数维护其历史梯度平方的累加和,并把该参数的步子除以这个和的平方根——于是经常出现大梯度的权重得到小而谨慎的步子,很少更新的权重得到大步子。这对稀疏数据极好,但累加和只增不减,于是步子会缩向零,学习最终停滞。

RMSprop用一个小改动解决了停滞:它不再永远累加所有历史梯度平方,而是维护它们的*指数移动平均*。旧梯度会逐渐淡出,于是每个参数的步长能随训练进入新地形而增大或减小,学习永不停摆。RMSprop 本质上就是带有一段短滑动记忆的 AdaGrad——它至今仍是个稳妥的选择,尤其适合循环网络。

Adam——是 *Adaptive Moment Estimation*(自适应矩估计)的缩写——是你几乎能在每个现代配方里见到的主力。它的诀窍很简单,就是把上面两个想法合二为一:它既保有动量那种梯度的移动平均(“一阶矩”,给出方向并平滑),*又*保有 RMSprop 那种梯度平方的移动平均(“二阶矩”,给出逐参数的缩放)。一个小小的偏差修正项让早期步子在两个平均值尚未热身完毕前保持靠谱。结果就是一个开箱即用、大多时候直接能用的优化器——这正是它得以接管一切的原因。

学习率调度与预热

即使是出色的优化器也需要合适的步长,而最佳步长会随训练而变化。学习率是你要设定的最重要的单个数字——太大,损失会爆炸或振荡;太小,训练则慢如蜗牛。深层的洞见是:没有任何一个*常数*是理想的——训练初期你想迈大步去覆盖地形,但接近极小值时你想迈微小而谨慎的步子,以免永远在它周围弹跳。学习率调度做的事很简单,就是随训练推进改变学习率。

最常见的形状有*阶梯衰减*(在几个里程碑处把学习率砍为十分之一)、*余弦衰减*(沿余弦曲线平滑地把学习率滑降到接近零)、以及*指数衰减*。余弦衰减是大模型的现代宠儿,因为它温和的收尾往往能落在更平坦、泛化更好的区域。无论你选哪种,原理都一样:开局大胆,收尾温柔。

预热则是开局阶段一个反直觉的相反操作:在最初的几百到几千步里,你把学习率从接近零*逐渐升高*到峰值,然后才开始衰减。为什么?在初始化时模型是随机的,Adam 的方差估计也不可靠,所以一个全尺寸的步子可能把权重炸开,损失再也回不来。预热让优化器的运行平均值先稳定下来,再放心交给它去迈大步。对于训练大型的、用 Adam 训练的 Transformer,先预热再余弦衰减几乎是放之四海的默认配方。

实用调参:到底该怎么做

理论之外,调参很大程度上是有纪律的试错。好消息是,搜索空间远比看上去要小:把学习率大致调对,其余大多数旋钮几乎都无关紧要。下面是一套最省算力的可靠操作顺序。

  1. 从一个公认好用的默认值起步:Adam(或 AdamW),学习率 3e-4,beta 取 0.9/0.999。仅凭这一组就能把很大一部分模型训练到尚可的程度。
  2. 先单独把学习率调好。在十的幂上扫描——比如 1e-2、1e-3、1e-4——每个跑一小段。挑出损失仍能平滑下降、不出现尖刺的最大那个学习率。
  3. 盯住损失曲线,而不只是最终数字。损失爆炸或出现 NaN,说明学习率太高;损失沿着近乎水平的直线缓降,说明它太低。
  4. 在峰值学习率定好后再加调度:前约 2–5% 的步数做预热,然后余弦衰减到接近零。这通常能白赚一点精度提升。
  5. 到这一步才去动批量大小、权重衰减或 beta——并记住那条粗略规则:更大的批量允许你调高学习率。

几句诚实的警告。著名的“3e-4 是 Adam 的最佳学习率”是个梗,不是定理——它是个不错的*起点*,仅此而已。要警惕:在极小的试验性运行里看起来完美的学习率,一旦把模型或数据放大,往往就偏高了。还有,训练损失的收敛不等于大功告成:一个模型完全可以漂亮地收敛到某个过拟合的点上——而这正是本阶下一篇要直面的那场战斗。