Optimizer race
Race seven optimizers on six classic loss surfaces. Drag the start point, change the learning rates and the β values, and see why momentum helps in a valley, why Adam rescales the coordinates, and what goes wrong when the step is too large.
Training a model means finding parameters that make a loss small. An optimizer does this step by step: it looks at the gradient , the direction in which grows fastest, and moves the parameters a little against it. How far it moves is set by the learning rate (the step size).
Real models have millions of parameters, but the main effects are already visible with two. Here , and the loss is drawn as a contour map: each line joins points with the same loss, like the height lines of a hiking map, and darker regions are lower. Seven optimizers start at the same point and race to the minimum:
- GD: plain gradient descent;
- momentum and Nesterov: gradient descent with a memory of the previous steps;
- AdaGrad, RMSProp, Adam and AdamW: adaptive methods, which give each coordinate its own step size.
You will see where each one is fast, where it is slow, and where it fails. The update rules and the math behind the pictures are in section 3.
1. The race #
Press Play and watch the race; then drag the start point (the large dot) or tap the map. Colours: GD grey, momentum blue, Nesterov violet, AdaGrad yellow, RMSProp aqua, Adam orange and AdamW magenta (dashed). Stars mark the global minima. The table is the race board: click a name to switch that optimizer on or off, and move its slider to change its learning rate . The column finish is the first step with (the dashed line in the chart), and the numbers 1, 2, 3 are the ranks. The chart shows the loss gap on a log scale. The sliders at the bottom set the momentum , Adam's and , RMSProp's and AdamW's weight decay for all optimizers that use them.
The six surfaces:
| Surface | What it tests | |
|---|---|---|
| Rosenbrock | a long, curved, flat valley; minimum | |
| Beale | , | flat plateaus next to steep walls; minimum |
| Saddle | a saddle point at ; minima | |
| Ill-conditioned | , valley turned by the angle | the condition number ; axis-aligned or tilted valley |
| Noisy | , with gradient noise of size | stochastic gradients, as with minibatches |
| Himmelblau | four global minima; which one do you reach? |
2. Try this #
- Momentum in a curved valley. Use Rosenbrock with the default settings. GD, momentum and Nesterov all have the same learning rate . Question: which of them reach the finish line in 1500 steps? What to see: GD does not; after 1500 steps it is still in the valley near with . Momentum finishes at and Nesterov at . Now set : momentum does not finish either. With it finishes at . Along the valley the gradient keeps its direction, so momentum makes the step about times longer. Finally set AdamW's weight decay to : AdamW now stops near , because the decay pulls it toward .
- Too large a step. Choose Ill-conditioned (, ). The side panel shows the largest stable learning rate of GD, momentum and Nesterov. Question: move GD's to , , . What happens? What to see: at GD zigzags across the valley but still finishes (). At exactly it jumps between two points forever. At the board shows diverged after 8 steps, and the curve in the chart goes up. Momentum diverges above and Nesterov above (with ). Adam does not blow up even with (it finishes at ): its steps are normalized. On Rosenbrock, the curvature near the start is about , so GD with diverges after 4 steps.
- Adam rescales the coordinates. Stay on Ill-conditioned and set , . Question: compare GD and Adam, then turn the valley to . Who suffers from the turn? What to see: with the axis-aligned valley Adam finishes at and AdaGrad at , while GD needs steps. Adam's number does not change when you raise . At Adam and AdaGrad no longer finish in 400 steps. GD and momentum do not slow down: they even finish earlier ( and ), only because the start point now has a smaller part along the flat direction. Their speed does not depend on the angle. Adam scales each coordinate; that fixes a valley along an axis, not a tilted one.
- Escaping a saddle point. Choose Saddle. The start is , very close to the line that leads into the saddle. Question: which optimizers leave the saddle first? What to see: the adaptive methods turn toward a minimum at once ( after 3 steps for AdaGrad and 11 steps for RMSProp and Adam). Momentum and Nesterov need about 40 steps. GD needs 83 steps and spends 33 of them near the saddle, where the gradient is tiny. Now drag the start point onto the axis (it snaps to steps of ). All optimizers run into the saddle and stop there with : the gradient has no part, so nothing pushes them off the line.
- Noise and the step size. Choose Noisy. Each optimizer sees the true gradient plus random noise. Question: set GD's to , then to . How do the cloud of points at the end and the mean column change? What to see: with the mean loss of the last 100 steps is about ; with it is about ; with it drops to about , but GD needs more steps to arrive. With a constant learning rate, the optimizer does not converge; it moves around in a noise ball whose size grows with . AdaGrad's steps shrink over time, so it usually ends lowest. Press New noise to see another random run, and set to remove the noise.
- Many minima. Choose Himmelblau. Question: from the default start , which minimum does each optimizer reach? What to see: GD, momentum and Nesterov go down-left to star 3; AdaGrad, RMSProp, Adam and AdamW go up to star 2. The first steps of the adaptive methods follow the sign of the gradient, not the gradient itself, so they take another route. Move the start to : GD still ends at star 3, but momentum and Nesterov now reach star 2. In a nonconvex problem the solution you get depends on the start and on the optimizer.
3. The math behind the race #
All seven optimizers use the gradient at step (on the noisy
surface, is the noisy gradient). The playground uses exactly the update rules of PyTorch's
torch.optim. Squares, square roots and divisions of vectors act per coordinate.
Gradient descent and the step size #
Gradient descent (GD) moves against the gradient:
The clearest case is a quadratic with a symmetric positive definite . Its gradient is . Write in the eigenvectors of , the Hessian of (the matrix of second derivatives). Then each coordinate follows its own rule:
where is the eigenvalue, the curvature in that direction. Call the largest eigenvalue and the smallest . Every factor must be below 1, so GD converges only if
For a larger the steep direction overshoots more at every step and the iterates grow: this is divergence (experiment 2). But the flat direction shrinks only by the factor , which is close to 1. With the best fixed step the error shrinks by per step, where is the condition number. So the number of steps grows in proportion to . A long, narrow valley is a valley with a large . In the Ill-conditioned surface and .
Momentum and Nesterov: memory along the valley #
Momentum (Polyak's heavy-ball method) adds up the past gradients in a buffer :
This is PyTorch's SGD(momentum=β). If the gradient stays the same, grows to :
the effective step is , ten times larger for . In a valley the gradient
across the valley changes sign at every step, so these parts cancel in . The gradient along
the valley keeps its sign, so it adds up. The method speeds up exactly where GD crawls (experiment 1).
With the best and on a quadratic, the error shrinks by about
per step: about steps per digit of accuracy instead
of .
Nesterov's method takes the gradient at a look-ahead point, where momentum is about to carry
the iterate: , . PyTorch
(nesterov=True) writes the same method in the variables of the look-ahead point:
On a quadratic with largest eigenvalue , the three methods are stable for
For this gives and about : the limits in experiment 2.
On the Ill-conditioned surface (), GD uses and momentum uses with . For a constant gradient, which one takes the larger effective step?
With a constant gradient the momentum buffer grows to , so the step becomes . The raw of different methods cannot be compared directly. Momentum is still stable here, because on a quadratic its limit is , and across the valley the gradient changes sign, so the buffer does not grow there.
Adaptive methods: one step size per coordinate #
The adaptive methods divide each coordinate of the step by a running size of its own gradients.
AdaGrad sums all squared gradients:
RMSProp uses an exponential moving average instead, so old gradients are forgotten:
Adam also keeps a moving average of the gradients (momentum) and corrects both averages for their start at zero (bias correction):
AdamW adds decoupled weight decay: . The term pulls every coordinate toward 0. In a neural network this is a regularizer; on a 2D loss it moves the end point away from the minimum of (experiment 1). The playground uses , and all states start at zero.
Why Adam rescales the coordinates. At the first step and , so the step is : every coordinate moves by about , whether its gradient is or . Later, as long as a coordinate's gradient keeps a similar size, stays of order one. So Adam acts like gradient descent with a diagonal preconditioner: a different step size for each coordinate. If the valley lies along an axis, this removes the bad scaling, and no longer matters. If the valley is tilted, a steep and a flat direction share each coordinate, and no per-coordinate scaling can separate them (experiment 3).
At the first step, Adam (with ) sees the gradient . How far does each coordinate move?
With bias correction and , so each coordinate moves by . Only the sign of the gradient matters at the first step. GD would move the first coordinate by and the second by .
What goes wrong with a too-large step #
- GD and momentum diverge. On a quadratic the steep direction is multiplied by at every step, so the error grows exponentially. On a non-quadratic surface the limit uses the local curvature: on Rosenbrock the largest Hessian eigenvalue at the start is about , so GD needs below about there.
- Adam and RMSProp do not blow up, but they do not settle. Their step in each coordinate is at most a few times (with the default and ), however large the gradient is. With a large they jump over the minimum and wander. With a constant , RMSProp ends up stepping back and forth within about of the minimum (look at its f − f* column).
- Noise needs a small or a decaying step. With stochastic gradients and a constant , the iterates never stop moving. For GD on a quadratic in dimensions, the average loss gap settles at
which grows in proportion to (experiment 5). This is why training uses learning-rate schedules that lower at the end, and why AdaGrad, whose step shrinks like , ends low.
Where the noise-ball formula comes from
In the eigenvector coordinates of , one GD step with noise is with , independent at every step. If the variance of has settled, it is the same before and after the step: . So , and this direction adds to the mean loss gap. In the playground ( and , , ) the formula gives ; long simulations give as well.
On the Noisy surface, GD with ends with a mean loss gap of about . What do you expect with , once the run has settled?
The settled loss gap is about , so doubling doubles it (the exact formula gives ). A larger step arrives sooner but then moves around in a larger noise ball. This is the trade-off that learning-rate schedules solve.
4. Learn more #
These lessons explain the ideas of this page in depth, with proofs, worked examples and notebooks:
- Optimization: loss surfaces and gradient descent, convexity, smoothness and the condition number, convergence rates of gradient descent, momentum and Nesterov acceleration, stochastic gradient descent and the noise ball, AdaGrad, RMSProp, Adam and AdamW and learning-rate schedules, warmup and clipping.
- Calculus: the gradient and the Hessian and Taylor's theorem.
- Linear algebra: eigenvalues and the spectral theorem, which give the eigen-directions of a quadratic.
- Deep learning: the training loop and mini-batches, weight decay as a regularizer and training dynamics: warmup, clipping and loss spikes.