← All tutorials

SGD, Momentum and Nesterov

How memory speeds up and calms the step.

On this page

1 Gradient descent and SGD 2 Momentum 3 Nesterov momentum 4 Saddle points and minibatch noise 5 SGD and momentum in PyTorch 6 Failure modes 7 References
SGDone step size
remembers direction
Momentumvelocity
reads slope ahead
Nesterovbrakes earlier
divides by size
AdaGrad, RMSProp, AdamAdaptive Optimizers

Each optimizer adds one idea to the one before; each arrow names it.

An optimizer turns each step's gradient into a weight update. It runs once per training step on one minibatch, a small random batch of training examples, and keeps a little state, such as momentum's velocity, between steps.

forwardloss on one batch backward()fills .grad opt.step()moves the weights next batch optimizer state kept0 to 2 copies of the weights
Figure 1. One step per minibatch; optimizer state carries over.

1 Gradient descent and SGD

Every figure in this series uses one loss, L = 5x² + 0.2y², started at (−3.5, 5). I call its shape, a long narrow valley, the ravine; it stands for the ill-conditioned loss of a real network, where one direction is far steeper than another. Its numbers are illustrative, computed by script. Its first step at learning rate α 0.15:

Steep x gets a big step, flat y a tiny one.
axisgradientstep
x−35+5.25
y2−0.30

Step downhill by an amount proportional to the slope (Gradient Descent, section 1.1).

The gradient descent step
θ ← θ − α·∇L(θ)
θ the weights; ∇L the uphill direction and its steepness; the minus turns it downhill; α converts slope into distance.

Steep places get big steps, flat places tiny ones. SGD computes ∇L on a minibatch instead of the whole data set, so each step is cheaper and a little noisy. Below, SGD fits the mean squared error of a linear model (Linear Regression, section 2).

import numpy as np
rng = np.random.default_rng(0)
X = rng.normal(size=(256, 3))
y = X @ rng.normal(size=3)
w = np.zeros(3)
lr, bs = 0.1, 32  # α, batch
for i in range(0, 256, bs):
    xb = X[i:i + bs]
    yb = y[i:i + bs]
    err = xb @ w - yb
    grad = 2 * xb.T @ err / bs
    w = w - lr * grad
  1. 1Data, zero weights, α and the batch size.
  2. 2Takes the next minibatch of rows.
  3. 3Slope of the batch's mean squared error.
  4. 4Steps every weight by the same α.

1.1 The steep direction sets the learning rate

Five steps at α 0.1512345start1x flips sign2y shrinks 6% per stepα 0.25, above the limit 0.2 on xx −3.5x 5.25x −7.88x 11.813x grows 1.5× per step−13.513.5x
Figure 2. ① x flips and halves; ② y shrinks 6%; ③ past α 0.2, x grows.

Along one axis of curvature h (how fast the slope grows), each step multiplies the distance to the minimum by one number.

One axis at a time
xt+1 = xt − α·h·xt
This is the gradient descent step on one axis. xt is the distance from the minimum after t steps, and the slope there is h·xt.
xt+1 = (1 − α·h)·xt
So each step multiplies the distance by 1 − α·h: −0.5 on x and 0.94 on y at α 0.15. It must stay between −1 and 1, so α must stay below 2h, and the steepest axis sets that limit, 0.2 here.

Even at α 0.19, just under the limit, y needs 59 steps to reach 1% of its start. One α cannot suit both axes; momentum below and per-axis step sizes (Adaptive Optimizers) are the two fixes.

2 Momentum

Momentum keeps a velocity v, a running sum of past gradients in which each older gradient is shrunk by the momentum factor μ every step.

Velocity v for a steady gradient of 1, μ 0.911/(1 − μ) = 1005101102030step t6.51 at t 10
Figure 3. A steady push builds velocity toward ① 10 times one push.
Velocity
v ← μ·v + ∇L(θ)
μ·v is the memory of past pushes, shrunk by μ each step; ∇L is today's push.
vt = ∇Lt + μ·∇Lt−1 + μ²·∇Lt−2 + …
Written out, a push from k steps ago still counts μk. A steady gradient adds up to 11 − μ times itself, 10 at μ 0.9.

Sutskever et al. 2013 train deep networks with momentum 0.9 and higher, so the velocity can reach 10 times one gradient. On the ravine at α 0.05, μ 0.9:

y steps keep growing; x crosses 0 at step 2, yet its steps stay positive until step 5.
tx stepy step
1+1.750−0.100
2+2.450−0.188
3+1.855−0.263
4+0.392−0.326
5−1.121−0.376
The momentum step
θ ← θ − α·v
The gradient descent step with the velocity in place of today's gradient.

Directions that agree add up; directions that flip cancel. The same mechanism speeds y and makes x overshoot.

import numpy as np

theta = np.array([-3.5, 5.0])
h = np.array([10.0, 0.4])    # curvature of x and y
v = np.zeros(2)
lr, mu = 0.05, 0.9           # α, μ
for t in range(60):
    grad = h * theta
    v = mu * v + grad
    theta = theta - lr * v
  1. 1The ravine, its start, zero velocity, α and μ.
  2. 2Reads today's slope.
  3. 3Shrinks v by μ and adds the slope.
  4. 4Steps by α times the velocity.
At μ 0.9 the built-up step is about 10 times α times the gradient.
knobraise itlower itdefault
μ (momentum)more build-up, longer coasting, more overshootcloser to SGD; 0 is SGD0, often 0.9

2.1 Momentum keeps moving after the slope vanishes

Gradient 1 for 20 steps, then 0; α 0.101020positiongradientstops127.9coasting0204060step
Figure 4. ① The gradient stops; ② the glide then adds 7.9 more.

The last pushed step is 0.878. Once the slope is gone, each step is μ times the one before.

How far momentum coasts
total coast = α·v·μ1 − μ
α·v is the last step; the steps after it are μ, μ², … times it, which sum to μ1 − μ = 9 last steps.

In multitask training a gradient balancer edits each task's gradient and can remove a direction; the same glide carries it back into the step (Gradient Balancing Inside the Training Loop, section 8.1).

3 Nesterov momentum

Nesterov reads the slope where the velocity is about to carry the weights, not where they are now.

Step 2 on the steep axis x, μ 0.9, α 0.05−2−101minimumθ −1.751lookahead −0.175momentum reads slope −17.5Nesterov reads −1.752momentum lands 0.73Nesterov lands −0.09
Figure 5. ① Lookahead, ② momentum lands at 0.7, ③ Nesterov at −0.09.
Nesterov momentum
v ← μ·v + ∇L(θ − α·μ·v)
θ − α·μ·v is where the remembered velocity alone would take you; the gradient there is a preview.
θ ← θ − α·v
The step itself is momentum's, unchanged.

The brake starts one step earlier, because Nesterov reads a slope ten times gentler at the lookahead than momentum reads at θ. At α 0.15 and μ 0.9 Nesterov diverges on this ravine while momentum does not, because its earlier reading of the steep slope makes it more sensitive to a large α.

Figure 6. ① y after 60 steps; ② x's largest overshoot.

4 Saddle points and minibatch noise

1gradient (0, 0)2a nudge on yuphill on xdownhill on y
Figure 7. ① Zero gradient, no step; ② a nudge along y escapes.
A saddle point
L(x, y) = x² − y²
Uphill along x, downhill along y.
∇L(0, 0) = (0, 0)
At the centre the gradient descent step is zero.

Exact gradient descent started on the x axis stops at the centre. A minibatch gradient is never exactly zero, so its noise nudges the weights along y and they escape. The DQN agent learns from batches of 64 earlier moves drawn at random from its memory, so every gradient it follows is this kind of noisy minibatch gradient (Deep Q-Networks, section 6).

5 SGD and momentum in PyTorch

Both run once per step; momentum keeps one buffer the size of the weights.

opt = torch.optim.SGD(model.parameters(), lr=0.05, momentum=0.9)
opt_nag = torch.optim.SGD(model.parameters(), lr=0.05, momentum=0.9, nesterov=True)
  1. 1The momentum buffer is the velocity v.
  2. 2The same with Nesterov momentum.

6 Failure modes

Most of these trace back to α or μ.
symptomlikely causefix
loss oscillates or divergesα above 2/h on the steepest directionlower α
flat directions crawlα held down by the steep directionmomentum or an adaptive optimizer
weights overshoot and swingμ too highlower μ
diverges only with nesterov=Truelarge α with Nesterovlower α
training stalls on a plateaua saddle or very flat regionmomentum; smaller batches add noise

7 References

  1. Robbins, H., and Monro, S. (1951). A stochastic approximation method. Annals of Mathematical Statistics.
  2. Polyak, B. T. (1964). Some methods of speeding up the convergence of iteration methods. USSR Computational Mathematics and Mathematical Physics.
  3. Nesterov, Y. (1983). A method for solving the convex programming problem with convergence rate O(1/k2). Doklady Akademii Nauk SSSR 269(3), 543-547; English translation in Soviet Mathematics Doklady 27.
  4. Sutskever, I., et al. (2013). On the importance of initialization and momentum in deep learning. ICML.
  5. PyTorch documentation, torch.optim (SGD, momentum and nesterov settings).