AI-310 · Lesson 5 of 12 · 31 min

Momentum, Adam and adaptive methods

Plain gradient descent has two weaknesses that Lesson 1 exposed. In ill-conditioned problems it zigzags across narrow valleys while crawling along them, needing a number of steps proportional to the condition number. And one learning rate must serve every parameter, even when different parameters see gradients that differ by orders of magnitude, as they do across the layers of a deep network. Momentum addresses the first problem by accumulating velocity along consistent directions; adaptive methods address the second by giving each parameter its own effective step size. Adam combines both, and with its weight-decay variant AdamW it is the default optimizer for transformers and most of modern deep learning.

Momentum

The heavy-ball method, due to Boris Polyak (1964), adds a fraction of the previous step to the current one:

\[\mathbf{v}_{k+1} = \beta\mathbf{v}_k - \eta\nabla f(\mathbf{w}_k), \qquad \mathbf{w}_{k+1} = \mathbf{w}_k + \mathbf{v}_{k+1}\]

with momentum coefficient \(\beta\) typically 0.9. The velocity \(\mathbf{v}\) is an exponentially weighted sum of past gradients. Along a direction where the gradient keeps the same sign, such as the long axis of a valley, contributions accumulate, and the effective step approaches \(\eta/(1 - \beta)\), ten times \(\eta\) for \(\beta = 0.9\). Across the valley, where the gradient alternates in sign, contributions cancel and the zigzag is damped. Deep learning frameworks usually implement SGD with momentum in the equivalent form \(\mathbf{v} \leftarrow \beta\mathbf{v} + \mathbf{g}\), \(\mathbf{w} \leftarrow \mathbf{w} - \eta\mathbf{v}\).

On a strongly convex quadratic, heavy ball with optimal parameters, \(\eta = 4/(\sqrt{L} + \sqrt{\mu})^2\) and \(\beta = \big((\sqrt\kappa - 1)/(\sqrt\kappa + 1)\big)^2\), contracts the error by a factor of about \((\sqrt\kappa - 1)/(\sqrt\kappa + 1)\) per step, so the number of iterations scales with \(\sqrt\kappa\) instead of \(\kappa\). For \(\kappa = 10{,}000\) that is the difference between about 100 and 10,000 times \(\ln(1/\varepsilon)\).

Worked problem

Momentum versus gradient descent

For a quadratic with \(\kappa = 100\), compare the per-step contraction factors and the iterations needed to reduce the error by \(10^6\) for gradient descent with its best fixed step and heavy ball with optimal parameters.

Show solution
  1. Gradient descent: \((\kappa - 1)/(\kappa + 1) = 99/101 = 0.980\); iterations \(\ln(10^6)/(-\ln 0.980) = 13.8/0.0200 = 691\).
  2. Heavy ball: \((\sqrt\kappa - 1)/(\sqrt\kappa + 1) = 9/11 = 0.818\); iterations \(13.8/0.201 = 69\).
  3. Optimal \(\beta = (9/11)^2 = 0.669\).

Answer: About 690 iterations for gradient descent and 69 for heavy ball: a tenfold saving, √κ = 10. The heavy-ball guarantee holds for quadratics; for general strongly convex functions Nesterov's method (below) provides it.

Nesterov acceleration

Yurii Nesterov's accelerated gradient method (1983) evaluates the gradient at a look-ahead point:

\[\mathbf{v}_{k+1} = \beta\mathbf{v}_k - \eta\nabla f(\mathbf{w}_k + \beta\mathbf{v}_k), \qquad \mathbf{w}_{k+1} = \mathbf{w}_k + \mathbf{v}_{k+1}\]

The gradient at the point momentum is about to carry the iterate to acts as a correction before overshooting. Nesterov's method provably achieves the \(\sqrt\kappa\) dependence for all smooth strongly convex functions, and for smooth convex functions improves gradient descent's \(O(1/k)\) rate to \(O(1/k^2)\), which is optimal among first-order methods. In deep learning, the practical difference between heavy ball and Nesterov momentum is usually small.

Gradient descent versus heavy-ball and Nesterov momentum on a quadratic with κ = 100
import numpy as np

rng = np.random.default_rng(0)
Q, _ = np.linalg.qr(rng.normal(size=(50, 50)))
eigs = np.logspace(0, 2, 50)                       # curvatures 1 to 100, kappa = 100
A = Q @ np.diag(eigs) @ Q.T
w0 = rng.normal(size=50)
L, mu = eigs.max(), eigs.min()

def run(method, tol=1e-6, max_iter=5000):
    w, v = w0.copy(), np.zeros(50)
    e0 = np.linalg.norm(w0)
    for k in range(1, max_iter + 1):
        if method == "gd":
            w = w - 2 / (L + mu) * (A @ w)
        else:
            sk = np.sqrt(L / mu)
            if method == "heavy ball":                # optimal heavy-ball parameters for a quadratic
                eta, beta = 4 / (np.sqrt(L) + np.sqrt(mu)) ** 2, ((sk - 1) / (sk + 1)) ** 2
            else:                                     # standard Nesterov parameters
                eta, beta = 1 / L, (sk - 1) / (sk + 1)
            point = w + beta * v if method == "nesterov" else w
            v = beta * v - eta * (A @ point)
            w = w + v
        if np.linalg.norm(w) < tol * e0:
            return k
    return max_iter

for m in ["gd", "heavy ball", "nesterov"]:
    print(f"{m:11s} iterations to reduce error by 1e6: {run(m)}")
Output
gd          iterations to reduce error by 1e6: 604
heavy ball  iterations to reduce error by 1e6: 86
nesterov    iterations to reduce error by 1e6: 125
Contour plot of an elongated quadratic valley with two 30-step paths from the same start. Gradient descent with a large step zigzags across the narrow direction and creeps along the long axis, ending well short of the minimum. Heavy-ball momentum swings widely across the valley at first, but its oscillations die out and it reaches the minimum within the 30 steps.
Thirty steps of gradient descent and of heavy-ball momentum on the same valley. Momentum overshoots at first but builds speed along the valley and arrives far sooner.

Adaptive learning rates

Adaptive methods scale each coordinate's step by the inverse of a running estimate of that coordinate's gradient magnitude, a form of diagonal preconditioning learned from the gradients:

  • AdaGrad (Duchi, Hazan and Singer, 2011) divides by the square root of the sum of all past squared gradients, so coordinates with large or frequent gradients get small steps and rare features get large ones. It works well for sparse problems, but its effective step only shrinks, which can stall long training runs.
  • RMSProp (Hinton, 2012) replaces the sum with an exponential moving average, \(\mathbf{s} \leftarrow \rho\mathbf{s} + (1 - \rho)\mathbf{g}^2\) (elementwise), and steps by \(\eta\,\mathbf{g}/(\sqrt{\mathbf{s}} + \epsilon)\), so the step adapts to recent gradient magnitudes without decaying forever.

Adam

Adam (Kingma and Ba, 2015) combines momentum with RMSProp-style scaling. With gradient \(\mathbf{g}_t\) at step \(t\), it maintains moving averages of the gradient and its elementwise square, corrects them for their initialization at zero, and steps:

\[\begin{aligned} \mathbf{m}_t &= \beta_1\mathbf{m}_{t-1} + (1 - \beta_1)\mathbf{g}_t, & \mathbf{v}_t &= \beta_2\mathbf{v}_{t-1} + (1 - \beta_2)\mathbf{g}_t^2 \\ \hat{\mathbf{m}}_t &= \frac{\mathbf{m}_t}{1 - \beta_1^t}, & \hat{\mathbf{v}}_t &= \frac{\mathbf{v}_t}{1 - \beta_2^t} \\ \mathbf{w}_t &= \mathbf{w}_{t-1} - \eta\,\frac{\hat{\mathbf{m}}_t}{\sqrt{\hat{\mathbf{v}}_t} + \epsilon} \end{aligned}\]

Default hyperparameters are \(\beta_1 = 0.9\), \(\beta_2 = 0.999\) and \(\epsilon = 10^{-8}\); large language model training often uses \(\beta_2 = 0.95\) for faster adaptation. Because the step for each coordinate is the ratio of a mean to a root-mean-square, its magnitude is roughly \(\eta\) regardless of the gradient's scale: Adam is approximately invariant to rescaling the gradient of each parameter. That robustness to scale, across layers and parameter types, is the main reason it trains transformers far more reliably than plain SGD.

The bias correction matters early in training. Since \(\mathbf{m}_0 = \mathbf{0}\), after one step \(\mathbf{m}_1 = 0.1\,\mathbf{g}_1\), a tenth of the gradient; dividing by \(1 - 0.9^1 = 0.1\) restores it. For \(\mathbf{v}\), with \(\beta_2 = 0.999\), the uncorrected average would be a thousandth of the true value at first, making early steps much too large; correction prevents that.

SGD, momentum and Adam on the Rosenbrock function across learning rates (final loss after 5000 steps)
import numpy as np

def rosenbrock(w):
    x, y = w
    f = (1 - x) ** 2 + 100 * (y - x * x) ** 2
    g = np.array([-2 * (1 - x) - 400 * x * (y - x * x), 200 * (y - x * x)])
    return f, g

def optimize(method, lr, steps=5000):
    w = np.array([-1.5, 2.0])
    m = np.zeros(2); v = np.zeros(2)
    for t in range(1, steps + 1):
        f, g = rosenbrock(w)
        if not np.isfinite(f) or f > 1e12:
            return float("inf")
        if method == "sgd":
            w = w - lr * g
        elif method == "momentum":
            m = 0.9 * m + g
            w = w - lr * m
        else:                                   # adam
            m = 0.9 * m + 0.1 * g
            v = 0.999 * v + 0.001 * g * g
            m_hat = m / (1 - 0.9 ** t); v_hat = v / (1 - 0.999 ** t)
            w = w - lr * m_hat / (np.sqrt(v_hat) + 1e-8)
    return rosenbrock(w)[0]

for method, lrs in [("sgd", [1e-4, 1e-3, 1e-2]), ("momentum", [1e-5, 1e-4, 1e-3]), ("adam", [1e-3, 1e-2, 1e-1])]:
    res = "  ".join(f"lr={lr:g}: {optimize(method, lr):.2e}" for lr in lrs)
    print(f"{method:9s} {res}")
Output
sgd       lr=0.0001: 4.48e+00  lr=0.001: 6.51e-03  lr=0.01: inf
momentum  lr=1e-05: 4.49e+00  lr=0.0001: 6.38e-03  lr=0.001: 1.99e-19
adam      lr=0.001: 1.12e+00  lr=0.01: 1.68e-17  lr=0.1: 1.09e-08

The Rosenbrock function has a long, curved, narrow valley, a classic test of optimizers. Plain gradient descent diverges at a learning rate of 0.01 and is still far from the minimum at 10⁻⁴. Momentum, well tuned, does extremely well here, but its useful range is shifted about tenfold lower than plain gradient descent's, because momentum multiplies the effective step. Adam reaches very low loss at two of the three rates and is still descending at the third. Every method has a window of workable learning rates; the practical advantage of Adam is that its window depends far less on the scale of each parameter's gradient, which in a deep network varies by orders of magnitude between layers.

Weight decay and AdamW

Weight decay shrinks parameters toward zero at each step, \(\mathbf{w} \leftarrow \mathbf{w} - \eta\lambda\mathbf{w}\), as a regularizer. For plain SGD, this is identical to adding an L2 penalty \(\tfrac{\lambda}{2}\|\mathbf{w}\|^2\) to the loss. For Adam it is not: an L2 penalty adds \(\lambda\mathbf{w}\) to the gradient, which then gets divided by \(\sqrt{\hat{\mathbf{v}}}\), so parameters with large gradient variance are barely regularized while those with small gradients are regularized heavily. Loshchilov and Hutter (2019) showed that decoupling the decay from the adaptive scaling, AdamW, regularizes better:

\[\mathbf{w}_t = \mathbf{w}_{t-1} - \eta\left(\frac{\hat{\mathbf{m}}_t}{\sqrt{\hat{\mathbf{v}}_t} + \epsilon} + \lambda\,\mathbf{w}_{t-1}\right)\]

AdamW with weight decay of about 0.01 to 0.1, warmup and cosine or linear decay is the standard recipe for transformers. Biases and normalization parameters are usually excluded from weight decay.

Worked problem

Adam versus AdamW decay

Two parameters, both equal to 1.0, have gradient root-mean-squares \(\sqrt{\hat v}\) of 10 and 0.01 (and the loss gradient itself is negligible). With \(\eta = 10^{-3}\) and \(\lambda = 0.1\), how much does each shrink in one step under Adam with an L2 penalty, and under AdamW?

Show solution
  1. Adam with L2: the penalty gradient is \(\lambda w = 0.1\). Step \(= \eta \times 0.1/\sqrt{\hat v}\): for the first parameter \(10^{-3} \times 0.1/10 = 10^{-5}\); for the second \(10^{-3} \times 0.1/0.01 = 10^{-2}\) (ignoring momentum averaging).
  2. AdamW: both shrink by \(\eta\lambda w = 10^{-4}\).

Answer: With L2 inside Adam, the shrinkage differs by a factor of 1000 between the two parameters, depending only on their gradient noise; AdamW shrinks both by the same 10⁻⁴. Decoupled decay behaves like the regularizer it is meant to be.

Practical matters

Gradient clipping

Occasional very large gradients, from a bad batch, a numerical spike or a sharp region of the loss surface, can throw a model far off course in one step. Gradient clipping rescales the whole gradient when its norm exceeds a threshold \(c\): \(\mathbf{g} \leftarrow \mathbf{g}\cdot\min(1, c/\|\mathbf{g}\|)\). A threshold of 1.0 is common in transformer training. Clipping by global norm preserves the gradient's direction, unlike clipping each coordinate.

Memory

Adam stores two extra values per parameter, \(\mathbf{m}\) and \(\mathbf{v}\), in addition to the parameters and gradients. For large models, optimizer state is a major part of memory.

Worked problem

Optimizer memory

A 7-billion-parameter model is trained with mixed precision: 16-bit parameters and gradients for computation, plus a 32-bit master copy of the parameters and 32-bit Adam moments. How much memory do these require (excluding activations)?

Show solution
  1. 16-bit parameters and gradients: \(7 \times 10^9 \times (2 + 2) = 28\) GB.
  2. 32-bit master parameters, m and v: \(7 \times 10^9 \times (4 + 4 + 4) = 84\) GB.
  3. Total: 112 GB, or 16 bytes per parameter.

Answer: About 112 GB, more than a single 80 GB accelerator holds, before counting activations. This is why large-model training shards optimizer state across devices (as in the ZeRO technique) and why memory-saving optimizers, such as those that factorize or quantize the second moment, exist.

Choosing an optimizer

For transformers and most new architectures, AdamW with warmup and decay is the reliable default. For convolutional networks on image classification, SGD with momentum (0.9), weight decay and a step or cosine schedule remains competitive and sometimes generalizes slightly better. Research continues: newer optimizers such as Lion (which uses only the sign of a momentum term), Shampoo (which uses larger, non-diagonal preconditioners per layer) and Muon (which orthogonalizes the updates of matrix-shaped parameters) have shown gains in some large-scale settings, but none has yet displaced AdamW as the general default. Whatever the optimizer, the learning rate and its schedule matter more than the choice between well-tuned alternatives.

Lesson 6 shows how the gradients these optimizers consume are computed, and Lesson 8 how the choice of optimizer affects which solution is found and how well it generalizes.

Common mistakes

  • MistakeKeeping the same learning rate when adding momentum.

    InsteadMomentum multiplies the effective step by about 1/(1 − β); reduce η accordingly.

  • MistakeUsing Adam with an L2 penalty and expecting proper weight decay.

    InsteadUse AdamW, which decouples decay from the adaptive scaling.

  • MistakeOmitting bias correction in a hand-written Adam.

    InsteadWithout it, early steps are badly scaled, especially because of β₂ = 0.999.

  • MistakeAssuming Adam needs no learning rate tuning.

    InsteadIt is more robust, but the learning rate, warmup and schedule still matter most.

  • MistakeIgnoring optimizer state when estimating memory.

    InsteadAdam adds two values per parameter; with mixed precision, budget about 16 bytes per parameter.

Summary and key terms

  • Momentum accumulates velocity: effective step ≈ η/(1 − β) along consistent directions; it damps zigzags.
  • Optimal heavy ball and Nesterov reduce iterations from ∝ κ to ∝ √κ; Nesterov gives O(1/k²) for smooth convex problems.
  • AdaGrad and RMSProp scale each coordinate by the inverse root of accumulated or averaged squared gradients.
  • Adam combines momentum (β₁ = 0.9) and RMSProp scaling (β₂ = 0.999) with bias correction; its steps are roughly scale-invariant.
  • AdamW decouples weight decay from adaptive scaling and is the standard optimizer for transformers.
  • Gradient clipping by global norm (often 1.0) guards against gradient spikes.
  • Adam stores two extra values per parameter; mixed-precision training needs about 16 bytes per parameter.
  • SGD with momentum remains strong for CNNs; Lion, Shampoo and Muon are active research directions.
Momentum
Adding a fraction of the previous update to the current one.
Heavy-ball method
Polyak's momentum method using the gradient at the current point.
Nesterov accelerated gradient
Momentum with the gradient evaluated at a look-ahead point.
Accelerated rate
Convergence with iteration count proportional to √κ, or O(1/k²) for convex problems.
AdaGrad
An adaptive method dividing by the root of the sum of past squared gradients.
RMSProp
An adaptive method dividing by the root of a moving average of squared gradients.
Adam
An optimizer combining momentum, RMSProp-style scaling and bias correction.
Bias correction
Dividing Adam's moving averages by 1 − βᵗ to offset their zero initialization.
Weight decay
Shrinking parameters toward zero at each step.
AdamW
Adam with weight decay decoupled from the adaptive gradient scaling.
Gradient clipping
Rescaling gradients whose norm exceeds a threshold.
Optimizer state
Per-parameter quantities, such as Adam's moments, stored between steps.

Practice problems

Work each problem on paper first, then reveal the answer to check.

  1. What is the effective step along a constant-gradient direction with η = 0.01 and β = 0.95?

    Show answer

    0.01/(1 − 0.95) = 0.2.

  2. For κ = 400, compare the contraction factors of best-step gradient descent and optimal heavy ball.

    Show answer

    GD: 399/401 = 0.995; heavy ball: (20 − 1)/(20 + 1) = 0.905.

  3. Find the optimal heavy-ball β for κ = 400.

    Show answer

    (19/21)² = 0.819.

  4. After two Adam steps with constant gradient g, what are m₂ and the bias-corrected m̂₂ (β₁ = 0.9)?

    Show answer

    m₂ = 0.9(0.1g) + 0.1g = 0.19g; m̂₂ = 0.19g/(1 − 0.81) = g.

  5. Why is Adam's step size roughly η regardless of gradient scale?

    Show answer

    It divides a moving average of the gradient by the root of a moving average of its square; scaling g by c scales both by c, which cancels.

  6. A gradient has norm 5 and the clipping threshold is 1. What happens to it?

    Show answer

    It is multiplied by 1/5, keeping its direction but reducing its norm to 1.

  7. How much memory does Adam state (m and v, 32-bit) need for a 70-billion-parameter model?

    Show answer

    70 × 10⁹ × 8 bytes = 560 GB.

  8. Under SGD, is weight decay equivalent to an L2 penalty? Under Adam?

    Show answer

    Under SGD, yes (with λ matched). Under Adam, no: the L2 gradient is divided by the adaptive scale; AdamW restores proper decay.

  9. Why might AdaGrad stall in a long training run?

    Show answer

    Its denominator accumulates all past squared gradients, so effective step sizes decrease monotonically toward zero.

  10. Name two reasons SGD with momentum is still used for some image models.

    Show answer

    It is simple and memory-light (one state per parameter), and with tuned schedules it often matches or slightly exceeds Adam's generalization on CNN image classification.

Lesson quiz · 5 questions

Score 60% or more to complete this lesson.

Take the quiz