跳到正文
DEV Community· Syed Abdul Hanan·· 2 小時前AI 評分52

梯度下降中的 Momentum 如何越過淺谷與小凸起?

How does a rolling ball skip small bumps?

AI 導讀

這篇教學説明,Momentum 透過累積過往梯度形成速度,令更新過程得以越過普通梯度下降會停住的淺谷;Nesterov 則在前瞻位置計算梯度,以減少窄谷中的擺動。在同一窄谷、學習率 η = 0.015 且損失降至 0.001 以下的設定中,普通梯度下降、Momentum 和 Nesterov 分別需要 298、73 和 18 步。

正文

Momentum, step by step: give gradient descent a memory, and it rolls past the traps that stop it.

Plain gradient descent looks only at the slope under its feet. Every step is

w ← w − η ∇L(w)

and nothing else. That makes it simple, but it also makes it forgetful: the moment the ground goes flat, it stops. Momentum fixes this with one extra number per weight, a velocity that remembers the slopes it has already rolled down. The examples below follow the CS878 lectures on gradient descent and scaling the optimization, and every number comes from running the update rule.

The trap

Take one weight and a loss with two dips:

L(w) = 0.12 (w − 2.5)² − 0.55 · exp(−(w + 1)² / 0.12)

Start at A, w = −3.5, where the loss is 4.32. There is a shallow dip B at w = −0.904 (loss 0.881) and the real minimum C at w = 2.5 (loss 0). Between them sits a bump only 0.13 higher than B.

Plain gradient descent with η = 0.1 takes big steps on the steep slope, smaller and smaller ones as it nears B, and by step 21 it has arrived. At B the gradient is zero, so every step after that is zero too. At step 50, at step 100, it is still in B, at a loss of 0.88.

Plain gradient descent stops in the shallow dip B: the gradient is zero there, so learning stops.

Plain gradient descent stops in the shallow dip B: the gradient is zero there, so learning stops.

Add a velocity

Momentum keeps a velocity v and moves along it:

  • v_t = β v_(t−1) + ∇L(w_t)
  • w_(t+1) = w_t − η v_t

With β = 0.9, each step keeps 90% of the old velocity and adds the new gradient. (This is the form PyTorch uses. Lecture notes often write v = βv + (1 − β)∇L, which only rescales the learning rate.)

Run it from A with the same η = 0.1. By step 6 the ball is near B and its velocity is about 6. The gradient at B is zero, but the velocity isn't, so the ball keeps going: it clears the bump at step 7, overshoots all the way to w = 4.71, swings back without ever returning to the bump, and settles in C by step 89.

Momentum carries the ball over the bump; plain GD's ghost is still stuck in B.

Momentum carries the ball over the bump; plain GD's ghost is still stuck in B.

What v remembers

Unroll the velocity and it becomes a weighted sum of every gradient so far:

v_t = ∇L_t + β ∇L_(t−1) + β² ∇L_(t−2) + …

The latest gradient counts fully, the one before 90%, then 81%, 73%, 66% and so on. The weights add up to 1/(1 − β) = 10, so momentum remembers about ten steps. With β = 0.1 they would be 1, 0.1, 0.01: it forgets almost at once. In practice β is usually around 0.9.

Eight bars, heights β^k, sum 1/(1 − β) = 10: gradients that agree stack toward 10; gradients that flip cancel, staying within ±0.53.

Eight bars, heights β^k, sum 1/(1 − β) = 10: gradients that agree stack toward 10; gradients that flip cancel, staying within ±0.53.

Agree or cancel

That memory does two different things depending on the gradients:

  • When they agree (+1, +1, +1 …), they stack: v grows 1, 1.9, 2.71, 3.44 … toward 1/(1 − β) = 10. The step grows up to ten times.
  • When they flip sign (+1, −1, +1 …), they cancel: v goes 1, −0.1, 0.91, −0.18, 0.84, −0.25 … and settles at about ±1/(1 + β) ≈ 0.53. The step stays small.

A narrow valley

Now two weights and a valley that is steep across and almost flat along: L = ½(w₁² + 50 w₂²), starting at (−4, 1), where the loss is 33. Count the steps until the loss drops below 0.001, with η = 0.015:

  • Plain GD: 298 steps. A bigger rate doesn't help: at η = 0.045, each step multiplies the across direction by 1 − 0.045 · 50 = −1.25 and it blows up. So plain GD has to crawl along the floor.
  • Momentum (β = 0.9): 73 steps. The along direction keeps agreeing, so it builds speed there. But the across direction overshoots and swings from side to side.

The narrow valley: plain GD crawls along the floor; momentum is faster but swings across.

The narrow valley: plain GD crawls along the floor; momentum is faster but swings across.

Nesterov: look before you step

Nesterov momentum changes one thing: it takes the gradient where the velocity is about to carry the weight, not where the weight is now.

v_t = β v_(t−1) + ∇L(w_t − η β v_(t−1))

If that look-ahead point is already uphill, the gradient there points back, and the step brakes before it overshoots. On the same valley, Nesterov needs 18 steps, with almost no swing.

Nesterov looks ahead: the gradient at the look-ahead point brakes the swing. 298 · 73 · 18.

Nesterov looks ahead: the gradient at the look-ahead point brakes the swing. 298 · 73 · 18.

Try it in PyTorch

Every weight in a network gets its own velocity, with the same shape as the weight. In PyTorch it is one line:

opt = torch.optim.SGD(model.parameters(), lr=0.015,
                      momentum=0.9, nesterov=True)

And the velocity itself, with gradients that flip sign:

v, out = 0.0, []
for g in [1, -1, 1, -1, 1]:
    v = 0.9 * v + g
    out.append(round(v, 2))
print(out)

It prints [1.0, -0.1, 0.91, -0.18, 0.84]. Change every g to 1 and v climbs toward 10.

Key takeaways

  • Plain gradient descent has no memory: it stops wherever the slope is zero, even in a shallow dip.
  • Momentum keeps a velocity, v = βv + ∇L, and steps along it, so it can roll through flat spots and over small bumps.
  • v is a sum of past gradients weighted by β^k, about 1/(1 − β) = 10 steps of memory at β = 0.9.
  • Agreeing gradients stack (up to 10×); flipping ones cancel. That is why momentum speeds up along valleys.
  • Nesterov takes the gradient at the look-ahead point, so it brakes before overshooting: 298 → 73 → 18 steps in the narrow valley.

This article is part of Deep Learning, Visually by Logit Solutions AI: short animated explainers that cover one idea at a time, each with a written version like this one.

來源:DEV Community · dev.to