Skip to content
AI.info

Training and optimization

Momentum and Nesterov Dynamics

Understand how velocity buffers smooth stochastic gradients, accelerate persistent directions, and create new failure modes when the objective changes.

By the end you can

Analogy

A heavy cart that remembers its motion

Repeated pushes in one direction build speed in a loaded cart. Alternating pushes partly cancel, and the cart in the corridor barely moves.

A cart also stops when the pushing stops. Optimizer velocity does not. It is a stored number that survives a learning-rate jump, an unfrozen backbone, and a checkpoint, so it can keep pushing along a direction the run has already left. Persistence, smoothing, and overshoot after the desired direction changes are three views of that same stored number.

The rest of this lesson replaces the cart with published functions, published tables, and the update rules two frameworks actually ship. Every claim the analogy suggests has been measured. Two of them turn out to have limits the analogy cannot show.

Momentum turns recent gradient history into state that influences future updates.

Velocity is a memory of transformed evidence

Classical momentum combines the previous velocity with the current gradient, then updates parameters using the new velocity. The coefficient determines how slowly old directions decay. Persistent gradients reinforce one another, while high-frequency variation is smoothed. The stored state can also continue pushing after a sharp turn in the objective.

The update is old, and its promise is exact. B. T. Polyak published it in 1964 as the heavy-ball method, in the form x_{k+1} = x_k − α∇f(x_k) + β(x_k − x_{k−1}). Tuned optimally, with α = 4/(√L+√m)² and β = ((√κ−1)/(√κ+1))², it converges on quadratics with factor (√L−√m)/(√L+√m). Gradient descent's factor is (L−m)/(L+m). Ghadimi and colleagues at KTH state the payoff plainly: “This convergence factor is always smaller than the one associated with the gradient iterates, and significantly so when the Hessian of the objective function is poorly conditioned.” Lessard and colleagues tabulate the same optimal tuning and note that the bounds are tight.

There is a condition attached, and deep networks do not meet it. Polyak reached the result by a local argument, and, in the KTH group's words, “this local analysis requires twice differentiability of the objective functions”. A deep network is not a twice continuously differentiable strongly convex objective. On the problems in this course the guarantee is gone. Only the measurements remain.

Those measurements arrived for deep learning in 2013, and they came with their own condition. Sutskever and colleagues showed that stochastic gradient descent with momentum trains deep and recurrent nets when it “uses a well-designed random initialization and a particular type of slowly increasing schedule for the momentum parameter”. The ceiling of that schedule, µmax, was drawn from {0.999, 0.995, 0.99, 0.9, 0}. The autoencoders ran for 750,000 updates with minibatches of 200. Table 1 gives Nesterov a training squared error of 0.074 at µmax=0.999 on CURVES, against 0.48 with no momentum. On MNIST it gives 0.73 at µmax=0.99, against 2.1. On FACES, 7.7 at µmax=0.999, against 36.4. Classical momentum never beat 0.10 on CURVES at any ceiling. Their own summary of the table: “It also shows that larger values of µmax tend to achieve better performance and that NAG usually outperforms CM, especially when µmax is 0.995 and 0.999.”

The winning number belongs to the schedule, not to the optimizer. Lucas and colleagues re-ran MNIST autoencoders in 2018 “using a set-up similar to that of Sutskever et al.”, but with the coefficient held fixed and drawn from {0.0, 0.9, 0.99, 0.999}. Held fixed, 0.99 was optimal for both variants: best training MSE 2.51±0.06 for classical momentum against 1.52±0.02 for Nesterov. The runs at 0.999 were unstable. That is the value that had won under a slowly increasing schedule. Same coefficient, different schedule, opposite result.

Momentum reduces some noise by remembering it, not by making gradients exact.

Visual

How a momentum buffer evolves

This sequence repeats at every optimizer step. Frameworks disagree about where in it the learning rate enters. PyTorch multiplies the rate in only at the final parameter update: v_{t+1} = µ·v_t + g_{t+1}, then p_{t+1} = p_t − lr·v_{t+1}. Keras folds it into the buffer one step earlier: velocity = momentum * velocity - learning_rate * g, then w = w + velocity. The five steps are the same. What is stored in the buffer is not.

FigureProcess · 5 steps
  1. 1

    Observe a gradient

    The current batch produces a direction under the present parameters.

  2. 2

    Decay prior velocity

    Earlier directions retain a coefficient-controlled influence.

  3. 3

    Add current evidence

    The new gradient modifies the running direction.

  4. 4

    Scale the velocity

    The learning rate converts optimizer state into a parameter update.

  5. 5

    Carry state forward

    The next step begins with memory of previous motion.

Key idea

A high coefficient increases memory and tuning sensitivity

Long memory can accelerate smooth directions. It can also amplify oscillation or delay adaptation. The best coefficient depends on gradient correlation, learning rate, schedule, and curvature. So do not interpret momentum and learning rate independently. That is not advice, it is a measurement. Smith opens the cyclical-momentum section of his hyperparameter paper with it: “Momentum and learning rate are closely related. The optimal learning rate is dependent on the momentum and momentum is dependent on the learning rate.”

His Table 1 trains ResNet-56 on CIFAR-10 for 95 epochs at total batch size 512, with weight decay 1e-4 and a cyclical learning rate of 0.08–0.8 at stepsize 41 epochs. Only the momentum schedule changes. Momentum decreasing 0.95→0.8 gives 92.0±0.2%. A constant 0.95 gives 92.1±0.1%. A constant 0.9 gives 91.4±0.3%. Momentum increasing 0.9→1.0 gives 91.4±0.1%. A constant 0.85 gives 90.8±0.3%. One hyperparameter, the same learning-rate cycle, a 1.3-point spread in final accuracy. Smith's own reading is narrower than the spread suggests: “a cyclical momentum of 0.95-0.85 provides an equivalent result as to the optimal choice of 0.95, which is better than the accuracy results from using a lower value.” The coupling is already a default in the tools. PyTorch's OneCycleLR ships cycle_momentum=True with base_momentum=0.85 and max_momentum=0.95, where “momentum is cycled inversely to learning rate”. fastai's fit_one_cycle defaults to moms=(0.95, 0.85, 0.95).

Two models with identical weights but different momentum buffers are different training states. Resuming them can produce different next updates immediately. Save optimizer state, schedule position, scaler state, and parameter-group definitions when continuation matters. When only inference matters, record that the optimizer state was intentionally discarded.

The same coefficient after a rate change therefore means two different things, and the published equations tell you which one you have. PyTorch's torch.optim.SGD defaults momentum to 0. It builds velocity from the raw gradient and scales at the update: v_{t+1} = µ·v_t + g_{t+1}, then p_{t+1} = p_t − lr·v_{t+1}. Its documentation carries the warning in a Note: “The implementation of SGD with Momentum/Nesterov subtly differs from Sutskever et al. and implementations in some other frameworks.” The same Note adds a second difference, one that survives no reset: “Moreover, the initial value of the momentum buffer is set to the gradient value at the first step. This is in contrast to some other frameworks that initialize it to all zeros.” Keras's SGD publishes the other convention: velocity = momentum * velocity - learning_rate * g, then w = w + velocity, and with nesterov=True, w = w + momentum * velocity - learning_rate * g. Read your own optimizer's documented update rule before you transfer a coefficient between libraries.

More memory is valuable only when recent directions remain relevant.

Comparison

Classical momentum and Nesterov intuition

Implementations vary, so verify the exact update rule in your framework. Verify the risk column too. Overshoot after a turn is not a metaphor about carts: heavy-ball run with Polyak's own optimal parameters can fail to converge on a strongly convex function.

The counterexample is one-dimensional and fully explicit. Lessard and colleagues built it in 2016, with m=1 and L=25 and a gradient of 25x for x<1, x+24 for 1≤x<2, and 25x−24 for x≥2. On it, the iteration x_{k+1} = (13/9)x_k − (4/9)x_{k−1} − (1/9)∇f(x_k) falls into an attractive period-3 cycle from any start in 3.07 ≤ x0 ≤ 3.46. The cycle sits at p = 792/1225 ≈ 0.65, q = −2208/1225 ≈ −1.80 and r = 2592/1225 ≈ 2.12, and the iterates never leave it. Their caption to Figure 6: “The iterates tend to a limit cycle, so the Heavy-ball method does not converge for this particular strongly convex function.”

The KTH group hit the same wall independently, on their own example, with gradient 50x+45 / 5x / 50x, µ=5 and L=50, for every start with x0 < −0.8 or x0 > 0.15: “Heavy-ball iterates with optimal step-sizes ... do not converge for the example in (32)”. Goujaud and colleagues generalised it in Mathematical Programming in 2025: for any condition number and any parameters, heavy-ball is either not accelerated, or there exists a smooth strongly convex function and an initialization on which it does not converge. Nesterov-style lookahead is the standard response to exactly this behaviour. On the autoencoder benchmarks above, it was the variant that won.

FigureComparison · 2 columns

Classical momentum

Build velocity from the gradient at the current parameter location.

  • View: accumulate present direction
  • Benefit: smooth and accelerate
  • Risk: overshoot after turns
  • Check: framework sign convention

Nesterov-style update

Evaluate or approximate the gradient after looking ahead along momentum.

  • View: correct anticipated motion
  • Benefit: earlier response to turns
  • Risk: implementation differences
  • Check: optimizer documentation

Example

When useful memory becomes stale memory

Optimizer state can outlive the regime that created it, and the cost of that has been measured on three benchmarks at once. Sutskever and colleagues report it in Table 2 of the 2013 paper, “The effect of low-momentum finetuning for NAG”: “We found it beneficial to reduce µ to 0.9 (unless µ is 0, in which case it is unchanged) during the final 1000 parameter updates of the optimization without reducing the learning rate”. The learning rate was left alone. Only the memory length changed, and only for the last 1,000 of 750,000 updates. Nesterov's training squared error fell from 0.096 to 0.074 on CURVES, from 1.20 to 0.73 on MNIST, and from 10.83 to 7.7 on FACES. The coefficient that was correct for the bulk of the run was actively costing accuracy at the end of it.

There is a theoretical counterpart, and Smith relays it. Liu and colleagues show via a diffusion approximation that momentum helps escape saddle points but hurts convergence near optima, so that “a large momentum helps escape saddle points but can hurt the final convergence, implying that momentum should be reduced at the end of training”. Smith's own recommendation is different. He prefers cyclical momentum to a terminal drop, and reports finding “a small improvement with cycling over only decreasing the momentum”. The five transitions below create the same mismatch mid-run.

  • Learning-rate jump: A restart raises the scale while the velocity still reflects the previous phase — and if your buffer absorbs the rate, the two are entangled. Goyal and colleagues at Facebook showed the two momentum forms are equivalent only at a fixed rate, and prescribed rescaling the buffer by eta_{t+1}/eta_t after a change. They call it the momentum correction: “Remark 2: Apply momentum correction after changing learning rate if using (10).” Skip it when the rate is raised, and the history term is too small and training destabilises. With their warmup in place, ResNet-50 trained at minibatch 8192 on 256 GPUs in one hour with no loss of accuracy. PyTorch's rate-outside form is the one they label (9), and it needs no correction; the Keras-style rate-inside form is (10), and it does.
  • Fine-tuning transition: Unfreezing a backbone introduces parameters without comparable momentum history, so a single coefficient governs buffers of very different ages within one optimizer.
  • Objective change: Adding a task or changing loss weights leaves buffers aligned with the old objective. At a high coefficient that misalignment decays slowly — the same long memory that bought 0.074 instead of 0.48 now points the wrong way.
  • Data shift: A curriculum phase changes batch composition while velocity continues the previous direction, so the first steps after the switch are partly a reply to batches the run has stopped seeing.
  • Checkpoint resume: Loading weights without matching optimizer state produces a different trajectory than true continuation — and in PyTorch a freshly created buffer is not zero, since “the initial value of the momentum buffer is set to the gradient value at the first step”.

Visual

Audit momentum behavior during a transition

Start here when a previously stable run becomes erratic after a phase change. Step 4 separates the two diagnoses in this lesson. One is excessive scale after a rate jump, which the momentum correction factor eta_{t+1}/eta_t addresses in the rate-inside convention. The other is genuinely stale direction memory, which the 2013 autoencoder runs fixed by lowering the coefficient with the learning rate left unchanged.

FigureProcess · 5 steps
  1. 1. Plot velocity norms

    Compare optimizer-state magnitude with current gradient and parameter norms.

  2. 2. Mark regime changes

    Annotate unfreezing, curriculum shifts, restarts, and loss-weight changes.

  3. 3. Compare reset variants

    Test whether resetting selected buffers improves the transition.

  4. 4. Lower the rate briefly

    Separate excessive scale from genuinely harmful direction memory.

  5. 5. Verify resume fidelity

    Confirm checkpoint weights, optimizer state, scheduler, and step counter align.

Key takeaways