想象一个冬天的早晨,你推着一颗大雪球站在山谷的雪槽顶端。雪槽两侧是又陡又滑的石壁,槽底却平坦得几乎看不出坡度。如果你每走一步都停下来,低头看看脚下哪个方向最陡,然后朝那里踢一脚,会发生什么?雪球刚被踢向左边石壁,又被反弹回来的力推向右边石壁——它在两条陡壁之间来回弹跳,累得气喘吁吁,却几乎没有向谷底前进。这就是没有记忆的代价:每一步都被“眼前的坡度”牵着走,忘了自己是从哪儿来的。 有经验的滚雪球高手会怎么做?先用力推一把,让雪球滚起来。滚起来的雪球有惯性:撞到石壁时,旧方向不会瞬间消失,而是在摩擦与反弹之间达成平衡,最终画出一条平滑的弧线滑向谷底。这个“惯性”,就是动量。 本文要讲的动量法(Momentum),正是给普通梯度下降装上这样一个“速度记忆”:把历史梯度的方向按指数加权累积起来,抑制峡谷地形中的锯齿震荡,同时加速平坦方向的探索。我们还会看到,动量系数 β 如何像路面的摩擦力一样决定“记得多久”,以及 Nesterov 版本如何让雪球“先探身看一步再蹬地”。读完你会发现,深度学习训练中最常用的加速技巧,其实就藏在儿时滚雪球的直觉里。

岗位关联

动量法是最优化理论的核心课之一,也是深度学习框架中优化器的默认引擎。掌握它,你能理解 Adam 的一阶矩、读懂训练曲线上的震荡,并在面试与实战中快速定位“为什么 loss 不降”的问题。

目录
  1. 可视化演示
  2. 优化困境:没有记忆的雪球
  3. 核心思想:给梯度装上速度记忆
  4. 更新公式:先定速度再迈步
  5. 系数解读:摩擦力 β 的刻度
  6. 对比标准SGD:陡壁卸力,长坡蓄力
  7. Nesterov加速:先探身再蹬地
  8. 实践要点:把雪球滚进真实训练
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

动量法在梯度下降中引入历史梯度方向的指数加权累积,像物理动量般抑制震荡、加速收敛。文章推导动量更新公式与系数衰... 切换模式查看不同维度。

本节配有交互动效(进入视口后自动加载,约 3KB)。

动量法的基本:核心原理 动态展示关键流程与数据流动 交互控件调节参数实时渲染 f(x) = transform(x) 核心概念的可视化呈现

优化困境:没有记忆的雪球

想象你推着一颗大雪球站在雪槽顶端。槽底几乎水平,两侧却是陡峭石壁。如果你每一步都低头看脚下、只朝最陡的方向踢一脚,雪球就会在左右石壁之间来回弹:踢向左壁,反弹向右,再踢向左……折腾半天,雪球还在原地附近打转。机器学习的“峡谷地形”和这条雪槽一模一样:损失函数在一个方向上变化剧烈(陡壁),在另一个方向上却非常平缓(槽底),这种“一陡一缓”的地形被称为病态(ill-conditioned)地形。

普通梯度下降(SGD)正是那个“走一步看一步”的雪球。它每次只根据当前位置的梯度迈一小步,没有任何历史记忆:

在陡峭方向,一步跨太大就冲过头,下一步又被拽回来,形成锯齿状震荡;在平缓方向,梯度又太小,走得像蜗牛。这里的 η 是学习率,决定每步迈多大——可问题恰恰在于:调大 η 想加快平缓方向,陡峭方向立刻震荡甚至发散;调小 η 想稳住陡峭方向,平缓方向又慢得让人绝望。这就是“学习率两难”。

所以真正的问题不是步子该迈多大,而是“走每一步时完全忘了自己是从哪来的”。一个没有记忆的雪球,注定在雪槽里弹来弹去——要改变命运,得让雪球记住自己刚才的方向,这就是动量法登场的理由。

θt+1=θt−η∇f(θt)\displaystyle \theta_{t+1} = \theta_t - \eta \nabla f(\theta_t)
  1. 参数位置 $\theta_t$表示第 $t$ 步时模型参数所在的位置,也就是雪球当前停在哪个坐标上。
    θt\theta_t
  2. 学习率 $\eta$决定每步迈多大,相当于踢雪球那一脚的力度。
    η\eta
  3. 梯度 $\nabla f(\theta_t)$损失函数在当前位置最陡峭上升的方向,把它反过来就是下山方向。
    ∇f(θt)\nabla f(\theta_t)
  4. 完整一步普通 SGD 每步沿“负梯度方向”走 $\eta$ 那么远,完全没有引入任何历史信息。
    θt+1=θt−η∇f(θt)\theta_{t+1}=\theta_t-\eta\nabla f(\theta_t)

核心思想:给梯度装上速度记忆

有经验的孩子滚雪球时,不会每一步都停下来重新判断方向。他们会先使劲推一把,让雪球滚起来。滚起来的雪球有一种“惯性”:即使右侧突然有一块凸起的石头把它往左顶,它也不会完全停下往左窜,而是带着之前向下的速度,稍微偏一点继续向前。动量法的核心思想,就是给梯度下降装上这样一个“速度记忆”。

每次更新时,我们不只看着当前的梯度,还把过去积累的速度按一定比例保留下来,再叠加上当前梯度的贡献。这个累积下来的东西叫速度变量 $v$(velocity),它的更新逻辑是一句朴素的话:新速度 = 旧速度 × 摩擦保留 + 当前梯度 × 学习率。

这里的 $\beta$ 叫动量系数(或衰减系数),相当于路面的摩擦力:$\beta$ 越大,旧方向保留得越多,雪球越“记仇”;$\beta$ 越小,旧方向消失得越快。注意它是“指数加权”地混合历史,而不是简单平均:越久远的梯度,被 $\beta$ 乘的次数越多,影响力越小——就像你回忆自己走过的路,昨天的事清晰,十天前的事模糊。

有了速度记忆,雪球碰到石壁时不会完全转向:左边撞来的力量会被历史向下的趋势抵消一部分,轨迹自然就平滑了。这正是我们想要的——不是更强的推力,而是正确的“记性”。

vt=β vt−1+η ∇f(θt)\displaystyle v_t = \beta\, v_{t-1} + \eta\, \nabla f(\theta_t)
  1. 新速度 $v_t$这一步更新完成后雪球的“速度”,它同时携带历史方向与今天的推力。
    vtv_t
  2. 摩擦保留 $\beta v_{t-1}$旧速度按比例 $\beta$ 保留下来,相当于路面的摩擦力。
    β vt−1\beta\,v_{t-1}
  3. 今天推力 $\eta \nabla f(\theta_t)$当前梯度的贡献,学习率 $\eta$ 控制这一脚有多狠。
    η ∇f(θt)\eta\,\nabla f(\theta_t)
  4. 两部分相加惯性 + 推力 = 新速度,这就是动量法唯一的新增公式。
    vt=βvt−1+η∇f(θt)v_t=\beta v_{t-1}+\eta\nabla f(\theta_t)

更新公式:先定速度再迈步

给雪球装上速度后,完整的动作要分两步:先更新速度(考虑摩擦和新推力),再按这个速度移动雪球。很多人以为动量法只是“换了个更大的学习率”,其实它是把“每一步的位移”从“当前梯度”换成了“累积速度”:

对比普通 SGD 的 $\theta_{t+1} = \theta_t - \eta\nabla f(\theta_t)$,唯一的区别就是用速度 $v_t$ 取代了 $\eta\nabla f(\theta_t)$。训练刚开始时 $v_0=0$,前几步动量法几乎和 SGD 一样;但随着一步步积累,如果方向一直没变,$v$ 会越来越大,雪球越滚越快;如果方向突然反了,$v$ 不会立刻反转,而是慢慢“刹车”再掉头——这就是它能抑制震荡的原因。

工程上还有两个细节:参数更新减去的是最新算好的 $v_t$,而不是 $v_{t-1}$;速度变量只有一个数,几乎不占内存,计算量零增加,效果却有质的改变。

短短两行公式,就像给雪球装上了记忆和惯性的双引擎。在 PyTorch 里,这两行就是 torch.optim.SGD(..., momentum=0.9) 背后发生的事——你只需要多传一个参数,雪球就从“走一步看一步”变成了“一路滚下山”。

vt=βvt−1+η∇f(θt)θt+1=θt−vt\begin{aligned} v_t &= \beta v_{t-1} + \eta \nabla f(\theta_t) \\ \theta_{t+1} &= \theta_t - v_t \end{aligned}
  1. 速度更新先按“旧速度折扣 + 当前梯度”算出新速度,相当于先决定这一步要滚多快。
    vt=βvt−1+η∇f(θt)v_t=\beta v_{t-1}+\eta\nabla f(\theta_t)
  2. 参数更新参数沿速度方向移动,位移量就是 $v_t$ 本身。
    θt+1=θt−vt\theta_{t+1}=\theta_t-v_t
  3. 减法方向速度带着“下山趋势”,所以是减去 $v_t$;如果 $v_t$ 为负(冲过头在往回走),减去负数等于上坡回拉,自然产生“刹车”。
    −vt-v_t
  4. 初始值训练起步时速度为零,所以前几步动量法几乎与普通 SGD 行为一致。
    v0=0v_0=0

系数解读:摩擦力 β 的刻度

同样是滚雪球,有人喜欢把雪球捏紧一点(摩擦小),有人喜欢松散一点(摩擦大)。$\beta$ 这个旋钮决定雪球“记得多久”:设成 0.5,雪球刚滚两步就把来路忘光,跟普通 SGD 没什么区别;设成 0.9,它能记住大约最近十步的趋势;设成 0.99,它几乎把过去一百步都记在心上。把速度公式一层层展开,就能看清各个历史梯度到底占多少比重:

意思是:每一步的梯度都要乘以 $\beta$ 的某个次方,越久远次方越大、权重越小。权重序列 $\beta^0, \beta^1, \beta^2, \dots$ 按等比数列(几何级数)衰减,所以这种累积叫指数加权移动平均(EMA)。它的“有效记忆长度”大约是:

$\beta=0.9$ 时有效记忆约 10 步,这是绝大多数任务的默认值;0.95 到 0.99 适合特别长、特别平滑的训练;$\beta$ 太大(如 0.999),雪球对路上新出现的拐弯反应迟钝,容易冲过头甚至发散。所以 $\beta$ 不是越大越好,而是“刚刚好记得住路况”最好。

调 $\beta$ 就像调节雪球的路面摩擦力:太滑刹不住,太涩滚不动。0.9 这个默认值,是无数次实战中“既记得住来路、又跟得上变化”的甜蜜点。

vt=η∑i=1tβ t−i ∇f(θi)\displaystyle v_t = \eta \sum_{i=1}^{t} \beta^{\,t-i}\, \nabla f(\theta_i)
11−β\displaystyle \frac{1}{1-\beta}
  1. 递推展开把 $v_t=\beta v_{t-1}+\eta g_t$ 一层层往回代,每个历史梯度都会被乘上 $\beta$ 的若干次方。
    vt=η∑i=1tβt−igiv_t=\eta\sum_{i=1}^{t}\beta^{t-i}g_i
  2. 权重几何衰减相隔 $j$ 步的梯度权重是 $\beta^j$,越久远权重越小,且按等比数列衰减。
    β t−i\beta^{\,t-i}
  3. 有效记忆长度把权重 $\beta^j$ 对 $j$ 求和,得到约 $1/(1-\beta)$,这就是动量“记住”几步的粗略答案。
    11−β\frac{1}{1-\beta}
  4. 取值直觉$\beta=0.9$ 时约记 10 步,$\beta=0.99$ 时约记 100 步——记得越久,响应越慢。
    β∈[0,1)\beta\in[0,1)

对比标准SGD:陡壁卸力,长坡蓄力

回到那条雪槽。普通 SGD 在陡壁间来回弹跳,动量法却能画出一条平滑弧线,差别到底在哪?用羽毛球来类比:普通 SGD 像接一个来势凶猛的球,每一拍都要全力回击,来回对抽精疲力尽;动量法像用球拍“卸力”,把来球的力量先接着,再顺着自己的节奏送回去。数学上看得更清楚。在陡峭的 y 方向上,梯度符号每步交替(先推向左,再推向右),速度是历史梯度的加权和,对交替出现的 $+g, -g, +g, -g, \dots$,加权和会收敛:

正负号互相抵消,速度只保留很小一部分,震荡被“平均”掉了。而在平缓的 x 方向上,梯度符号始终相同,求和是:

同向分量不断叠加,速度越滚越大,相当于把学习率放大了 $1/(1-\beta)$ 倍,平缓方向因此加速前进。一个方向“互相抵消”,一个方向“越加越强”——动量法同时解决了震荡和加速两个问题,所以它不是在两个方向上做同样的让步,而是让每个方向的表现都更合理。

用大白话说:在陡壁上,雪球用惯性“卸掉了”左右互搏的力气;在长坡上,雪球把每一段向下的力都攒了起来。一卸一攒,雪球自然又快又稳。

vt(y)=η∑i=1tβt−igi(y)  ⟶  ηg∑j=0∞(−β)j=ηg1+β\displaystyle v_t^{(y)} = \eta \sum_{i=1}^{t} \beta^{t-i} g_i^{(y)} \;\longrightarrow\; \eta g \sum_{j=0}^{\infty} (-\beta)^j = \frac{\eta g}{1+\beta}
∑j=0∞βj=11−β\displaystyle \sum_{j=0}^{\infty} \beta^j = \frac{1}{1-\beta}
  1. 交替方向抵消陡方向上梯度符号每步反转,加权和是一个正负交替的几何级数,部分和有界。
    vt(y)=ηg∑j=0∞(−β)j=ηg1+βv_t^{(y)}=\eta g\sum_{j=0}^{\infty}(-\beta)^j=\frac{\eta g}{1+\beta}
  2. 同向叠加加速缓方向上梯度符号不变,几何级数求和放大为 $1/(1-\beta)$。
    ∑j=0∞βj=11−β\sum_{j=0}^{\infty}\beta^j=\frac{1}{1-\beta}
  3. 一消一涨的对比$1/(1+\beta)<1$ 而 $1/(1-\beta)>1$,这就是“陡壁卸力、长坡蓄力”的数学来源。
    11+β  与  11−β\frac{1}{1+\beta}\;\text{与}\;\frac{1}{1-\beta}
  4. 直观结论动量让“来回抵消”的方向变平缓,让“持续一致”的方向变有力。
    ∣v(y)∣≪∣v(x)∣|v^{(y)}|\ll |v^{(x)}|

Nesterov加速:先探身再蹬地

滑雪运动员滑过一个弯道时,不会等到身体被甩出去才反应——他们会先探身,把重心移到前方一两米处,在那个“预判位置”上发力转弯。动量法虽然已经会“记住来路”,但它有个小毛病:速度太大时容易刹不住、冲过头。1990 年前后,Yurii Nesterov 提出一个漂亮的修正:不要用当前位置 $\theta_t$ 的梯度,而是先用当前速度“前瞻”一下,算一算自己大概会滚到哪,再在那个前瞻位置取梯度:

这相当于在蹬地之前先探身看路:如果前方马上要上坡,前瞻位置的梯度会提前提醒速度慢下来,避免冲过头;如果前方仍是下坡,前瞻位置的信息让加速更果断。因此 Nesterov 加速梯度(NAG)通常比标准动量收敛更快,尤其在接近最小值时,它的“刹车”更早、超调更小。

标准动量是“边跑边修正”,Nesterov 是“先看一步再跑”。同样是那个雪球,Nesterov 版的雪球多了一双眼睛——在每一脚蹬出之前,先探身看看下一步的雪况。

vt=βvt−1+η ∇f(θt−βvt−1),θt+1=θt−vt\displaystyle v_t = \beta v_{t-1} + \eta\, \nabla f\big(\theta_t - \beta v_{t-1}\big),\qquad \theta_{t+1} = \theta_t - v_t
  1. 前瞻位置先用当前速度 $\beta v_{t-1}$ 预估自己会滚到哪,得到“前瞻点” $\tilde\theta_t$。
    θ~t=θt−βvt−1\tilde\theta_t=\theta_t-\beta v_{t-1}
  2. 在新位置取梯度梯度改在前瞻点计算,相当于提前感知前方路况。
    ∇f(θ~t)=∇f(θt−βvt−1)\nabla f(\tilde\theta_t)=\nabla f(\theta_t-\beta v_{t-1})
  3. 速度与参数更新速度仍按同一套路合成,参数更新形式不变。
    vt=βvt−1+η∇f(θ~t)v_t=\beta v_{t-1}+\eta\nabla f(\tilde\theta_t)
  4. 与标准动量的区别标准动量在“脚下”看路,Nesterov 在“一步之后”看路,所以刹得更早。
    θt+1=θt−vt\theta_{t+1}=\theta_t-v_t

实践要点:把雪球滚进真实训练

真实世界的训练比雪槽复杂得多:批量数据带来梯度噪声,网络层数深,损失面布满大大小小的“雪包”。但动量的经验依然管用——它是深度学习训练中最常用的加速器之一。实践中可以直接套用的第一点:默认配置就是 $\beta=0.9$,PyTorch 里写 torch.optim.SGD(params, lr, momentum=0.9),TensorFlow/Keras 的 SGD 同样带 momentum 参数。

第二点,动量与学习率是“联手”的盟友。假设梯度方向恒定不变,速度会稳定在一个值:

也就是说,动量把有效学习率放大了 $1/(1-\beta)$ 倍,所以加了动量后可以适当调大学习率——但不要盲目翻倍,要观察训练曲线后再定。训练初期还可以用 warm-up(学习率从小逐渐变大),等速度建立起来后再进入正常节奏,避免一开始就冲过头。

第三点,理解动量是理解现代优化器的钥匙:Adam 的核心更新里,一阶矩就是“动量成分”(对应另一套 $\beta_1$),二阶矩是“梯度平方的动量”。对于语言模型、大模型微调,常用 Adam/AdamW;对于图像分类、目标检测等 CV 任务,SGD + 动量仍然宝刀不老。

回头看那颗雪球:普通 SGD 是“撞了南墙才回头”,动量是“带着记忆滚下山”,Nesterov 是“先看路再蹬腿”,而 Adam 则是给每一段历史都配了把尺子。所有这一切,都是为了让雪球更快、更稳地滚到谷底——这正是优化器存在的意义。

v∞=η1−β g\displaystyle v_\infty = \frac{\eta}{1-\beta}\, g
  1. 稳态速度梯度方向恒定时,速度会趋向一个稳定的 $v_\infty$,不再每步变化。
    v∞=η1−β gv_\infty=\frac{\eta}{1-\beta}\,g
  2. 等效放大学习率$v_\infty$ 相当于把学习率放大了 $1/(1-\beta)$ 倍,这就是动量“加速”的定量解释。
    11−β>1\frac{1}{1-\beta}>1
  3. 与学习率联动因此加了动量后,可以(在观察训练曲线后)适当调大学习率,而不是机械地减半。
    v∞∝ηv_\infty\propto\eta
  4. 记忆长度回顾同样的 $1/(1-\beta)$ 还告诉我们动量记住了约多少步历史,用于判断调参方向。
    Neff=11−βN_{\text{eff}}=\frac{1}{1-\beta}

AI 应用场景

图像分类模型训练(CV 基线)

阶段:模型训练与优化器选择

解决的问题:在大规模图像数据集上训练 ResNet 等网络时,批量样本引入的梯度噪声和损失面的狭长峡谷会让普通 SGD 震荡、收敛慢;动量法平滑噪声、加速收敛,让学习率可以设得更大而不发散,相当于给雪球装上了惯性缓冲。

具体案例:用 PyTorch 训练 ResNet-50 时,torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9) 是经典配置。相比不带动量的 SGD,同样的 epoch 数下验证精度更高,训练曲线的震荡明显更小,这正是“陡壁卸力、长坡蓄力”在真实数据上的体现。

策略梯度强化学习

阶段:策略优化与更新

解决的问题:强化学习中一条轨迹的回报方差极大,策略梯度相当于“噪声很大的梯度信号”,直接用会让策略参数乱跳。动量相当于给梯度加一个“惯性滤波”,把高频毛刺平均掉,让更新方向更稳定、更接近真实的改善方向。

具体案例:在 PPO/A2C 的实现里,对优势函数估计的梯度做动量累积,训练 Atari 游戏策略时 loss 曲线更平稳,回合奖励的方差下降;许多 RL 框架的优化器默认开启 momentum,就是为了对抗轨迹采样的高方差。

大模型微调中的 AdamW 理解

阶段:预训练 / 微调

解决的问题:新手把 Adam 当黑盒,遇到 loss 震荡不知从何调起;理解了动量(一阶矩)就知道 Adam 的 $\beta_1$ 控制“梯度的记忆”、$\beta_2$ 控制“梯度平方的记忆”,调参方向就有了依据——本质上还是在调“摩擦系数”。

具体案例:微调大语言模型时,若训练 loss 高频震荡,可以降低学习率或把 $\beta_1$ 从 0.95 调回 0.9,增强对近期梯度的响应。这种诊断能力直接来自对标准动量的理解,而不是死记参数。

Python 演示

python52 行
import math A = 0.3    # 缓方向曲率, 峡谷的"长坡"B = 13.0   # 陡方向曲率, 峡谷的"陡壁"  def grad(x, y):    # f = A*x^2 + B*y^2, 梯度为 (2Ax, 2By)    return [2.0 * A * x, 2.0 * B * y]  def loss(x, y):    return A * x * x + B * y * y  def run_sgd(steps, lr):    x, y = 0.3, 0.45    for t in range(steps):        gx, gy = grad(x, y)        x -= lr * gx        y -= lr * gy        if loss(x, y) < 1e-8:            return t + 1    return -1  def run_momentum(steps, lr, beta):    x, y = 0.3, 0.45    vx, vy = 0.0, 0.0    for t in range(steps):        gx, gy = grad(x, y)        vx = beta * vx - lr * gx        vy = beta * vy - lr * gy        x += vx        y += vy        if loss(x, y) < 1e-8:            return t + 1    return -1  def fmt(n):    return str(n) if n > 0 else "未收敛(>500步)"  if __name__ == "__main__":    lr = 0.065    n_sgd = run_sgd(500, lr)    n_mom = run_momentum(500, lr, 0.9)    print("标准SGD : 达到 loss<1e-8 用了 %s 步" % fmt(n_sgd))    print("动量法  : 达到 loss<1e-8 用了 %s 步" % fmt(n_mom))    if n_sgd > 0 and n_mom > 0:        print("动量法比标准SGD快 %.1f 倍" % (n_sgd * 1.0 / n_mom))
目的:在一个二维峡谷函数上同时跑标准 SGD 与动量法,对比两者到达谷底所需的迭代步数,直观验证动量法的加速效果。
  1. B = 13.0 # 陡方向曲率, 峡谷的"陡壁"把 y 方向设成陡壁,x 方向设成长坡,制造一陡一缓的病态地形。
  2. def grad(x, y):返回峡谷函数在 (x, y) 处的梯度,动量法和 SGD 都靠它找方向。
  3. x -= lr * gx标准 SGD 用当前梯度直接更新,没有任何历史记忆。
  4. if loss(x, y) < 1e-8:把“到达谷底”定义成损失足够小,用于公平比较两者步数。
  5. vx = beta * vx - lr * gx动量法把旧速度按 beta 保留、再叠加上今天的梯度,这就是“惯性 + 推力”。
  6. x += vx参数按累积速度移动,而不是按单步梯度移动。
  7. vx, vy = 0.0, 0.0速度从零起步,前几步动量法表现得几乎和 SGD 一样。
  8. print("动量法比标准SGD快 %.1f 倍" % ...)步数相除,胜负一目了然。

常见误区

误区既然动量这么有用,那 β 设成 0.999 甚至 0.9999,记得“更久”,收敛一定更快吧?我直接把 β 调到最大试试。

正解摩擦力太小,雪球刹不住车。β 接近 1 时有效记忆长度 $1/(1-\beta)$ 超长,对地形变化反应迟钝,很容易冲过谷底再折返,甚至发散。0.9 是久经验证的默认值;训练特别长时可试 0.95~0.99,但必须配合学习率一起观察调整。

为何常见:“记得越久越厉害”的直觉很自然,但忽略了下山路上地形一直在变——记忆太长就像眼睛只看远方、不看脚下。

误区动量法是不是把最近 K 步的梯度存下来求个平均,再用这个平均值更新?那我要存很多个梯度,内存开销很大吧?

正解动量法是“指数加权”而不是等权平均:越近的梯度权重指数级越高,新梯度永远以 $\eta$ 直接进入速度。滑动窗口需要存 K 个梯度,指数加权只需要存一个速度变量 v,内存开销是 O(1)。

为何常见:“平均”听起来合理,但没注意到 $\beta^j$ 的几何权重——它不是把历史等量看待,而是“越来越淡忘”。

误区有了惯性,雪球能冲过小坑,所以动量法可以解决局部极小值问题,我不用再担心陷入局部最优了。

正解动量主要解决“震荡”和“加速”两个问题。对尖锐的局部极小它有一定帮助,但高维非凸问题中的局部极小和鞍点仍然可能困住它。真正跳出局部最优通常要依靠随机重启、退火等手段。

为何常见:把“冲过小石子”的直觉推广过头了——小石子能冲过去,大山谷可冲不过去。

误区动量让步伐变大,为了安全,我必须把学习率减半,不然一定会发散。

正解没有这种“必须”。在恒定梯度下速度会稳定在 $v_\infty = \eta g/(1-\beta)$,等效放大约 $1/(1-\beta)$ 倍。实践中可以先保持学习率不变观察,若震荡或发散再按比例降低;盲目减半反而损失了动量的速度优势。

为何常见:把“步子更大”等同于“必须调小学习率”,忽略了两者其实是独立可调的两个旋钮。

面试题

Q1. 动量法中,速度更新公式 $v_t = \beta v_{t-1} + \eta \nabla f(\theta_t)$ 里的动量系数 $\beta$ 的典型默认值是多少?

单选题 · easy

  • A.0.0
  • B.0.5
  • C.0.9← 正确答案
  • D.1.5

答案:C。0.9 是绝大多数深度学习框架的默认值,对应有效记忆约 10 步,是“记得住来路、又跟得上变化”的甜蜜点。0.0 等于没有动量,1.5 超出 [0,1) 范围会发散,0.5 记忆太短效果接近普通 SGD。

Q2. 动量法主要解决标准 SGD 在峡谷地形中的什么问题?

单选题 · easy

  • A.梯度消失
  • B.过拟合
  • C.锯齿震荡← 正确答案
  • D.维度灾难

答案:C。峡谷地形一陡一缓,普通 SGD 在陡峭方向上每步冲过头再被拽回,形成锯齿震荡;动量法用历史速度“卸掉”交替方向的力,让轨迹平滑。梯度消失、过拟合、维度灾难都不是动量法的直接作用对象。

Q3. Nesterov 加速梯度在优化算法中属于哪一类?

单选题 · easy

  • A.二阶优化算法
  • B.一阶动量类优化算法← 正确答案
  • C.贝叶斯推断方法
  • D.随机搜索算法

答案:B。Nesterov 加速梯度仍然是只用到一阶梯度的动量类方法,它是对标准动量的“前瞻”改进,不计算 Hessian 矩阵,也不需要贝叶斯推断或随机搜索。它和标准动量的区别在于算梯度的位置不同。

Q4. 动量系数 $\beta$ 对应的“有效记忆长度”约为多少?

单选题 · mid

  • A.$\beta$ 本身
  • B.$1/(1-\beta)$← 正确答案
  • C.$1/\beta$
  • D.$\eta/(1-\beta)$

答案:B。把权重 $\beta^j$ 对 j 从 0 求和,得到 $1/(1-\beta)$。$\beta=0.9$ 时约记住 10 步,$\beta=0.99$ 时约记住 100 步。$\eta/(1-\beta)$ 是稳态速度公式,不是记忆长度。

Q5. Nesterov 加速梯度与标准动量法最核心的区别是什么?

单选题 · mid

  • A.每步迭代需要计算两次梯度
  • B.先用当前速度前瞻,再在前瞻位置计算梯度← 正确答案
  • C.使用二阶导数信息
  • D.自动把学习率调大

答案:B。NAG 把梯度计算的落点从当前位置 $\theta_t$ 换成了前瞻点 $\theta_t - \beta v_{t-1}$,相当于“先探身看路再蹬地”,只需要计算一次梯度,不需要二阶信息,也不改变学习率。

Q6. 关于动量法更新 $v_t = \beta v_{t-1} + \eta \nabla f(\theta_t)$,下列说法正确的有?

多选题 · mid

  • A.$v_t$ 是历史梯度的指数加权累积← 正确答案
  • B.$\beta$ 越接近 1,历史记忆越长← 正确答案
  • C.参数更新使用 $\theta_{t+1} = \theta_t - v_t$← 正确答案
  • D.加了动量就不需要学习率了

答案:ABC。动量法把历史梯度按 $\beta^j$ 几何衰减地累积起来,β 越大记得越久;参数沿累积速度 v_t 移动。学习率仍然存在于速度更新项中,动量不可能替代学习率。

Q7. 下列哪一项不是动量法的优点?

单选题 · mid

  • A.抑制峡谷地形中的锯齿震荡
  • B.加速平坦方向的收敛
  • C.完全避免陷入局部最优← 正确答案
  • D.平滑批量梯度带来的噪声

答案:C。动量能卸掉交替方向的力、叠加同向分量、平滑噪声,但它不是万能的“跳出局部最优”工具,面对真正的大山谷仍可能被困住。选项 C 把动量法的作用夸大了。

Q8. 关于 Nesterov 加速梯度的特点,正确的有?

多选题 · hard

  • A.在前瞻点 $\theta_t - \beta v_{t-1}$ 处计算梯度← 正确答案
  • B.相当于先预判位置再修正梯度← 正确答案
  • C.一定比标准动量收敛更快
  • D.能提前感知前方坡度变化,刹车更早← 正确答案

答案:ABD。NAG 的梯度落脚点在前瞻位置,能提前感知前方路况、减少超调;“一定更快”是绝对化说法,实践中多数情况更快但不是理论保证,故 C 错。A、B、D 都是对 NAG 的准确描述。

Q9. 如果把动量系数 β 设成 0.999,最可能发生的后果是什么?

单选题 · hard

  • A.收敛一定更快且更稳定
  • B.对地形变化反应迟钝,容易冲过头← 正确答案
  • C.与 β=0.9 几乎没有区别
  • D.等价于使用二阶优化方法

答案:B。β=0.999 时有效记忆约 1000 步,速度几乎“停不下来”,一旦前方地形反转,刹车极慢,容易大幅冲过头甚至震荡发散。它不会自动变成二阶方法,也不可能保证更快更稳。

Q10. 关于动量与学习率的联合调节,下列说法最准确的是?

单选题 · extreme

  • A.加入动量后必须把学习率减半,否则一定发散
  • B.动量偏大时可适当调小学习率,防止冲过头← 正确答案
  • C.动量与学习率完全无关,调一个不影响另一个
  • D.学习率应该设为 β 的倒数

答案:B。稳态速度 $v_\infty = \eta g/(1-\beta)$ 表明动量和学习率会共同决定实际步长:β 大相当于放大有效学习率,因此 β 偏大时适当调小 η 是合理的联动策略。选项 A 的“必须减半”和 C 的“完全无关”都过于绝对,D 没有依据。