Inference EngineeringInteractive lab
Gradient descent on a surface
Change the learning rate and watch the run diverge
Drop a starting point on a loss surface and step downhill with plain SGD, momentum, or Adam, with the trajectory drawn over the contours.
What this teaches
- Learning rate
- Momentum
- Why Adam adapts per parameter
The surface and the step
f = x^2 + 12y^2Condition number 12. The gradient points across the valley rather than along it, which is what momentum fixes and what makes a single learning rate a compromise.
This surface is a quadratic, so the stability threshold is exact rather than a rule of thumb: plain gradient descent converges while lr < 2/L, and here L = 24, so the boundary is 0.0833. You are at 0.0200, below it. SGD ended at a loss of 0.0193. Walk the slider across 0.0833 and watch the prediction and the behaviour change together.
After 60 steps
from the same starting pointAt a learning rate of 0.0200 over 60 steps on the Elliptical bowl (ill-conditioned), the best final loss is 1.21e-5 from Momentum.
All three start at the same point and see the same gradients. Where they end up differs only in how they turn a gradient into a step, which is the entire content of an optimiser.
The path each one took
darker is lower loss- SGD
- Momentum
- Adam
Why Adam adapts per parameter
its step in x and in y, separately| Step | x | y | loss | grad x | grad y | step in x | step in y |
|---|---|---|---|---|---|---|---|
| 0 | -1.6000 | 0.9000 | 12.2800 | 0 | 0 | 0 | 0 |
| 5 | -1.5004 | 0.8005 | 9.9398 | -3.0405 | 19.6873 | -0.0199 | 0.0198 |
| 10 | -1.4014 | 0.7022 | 7.8806 | -2.8422 | 17.3203 | -0.0197 | 0.0195 |
| 15 | -1.3036 | 0.6065 | 6.1132 | -2.6461 | 15.0083 | -0.0194 | 0.0189 |
| 20 | -1.2078 | 0.5147 | 4.6373 | -2.4536 | 12.7835 | -0.0190 | 0.0180 |
| 25 | -1.1144 | 0.4281 | 3.4411 | -2.2657 | 10.6784 | -0.0185 | 0.0168 |
| 30 | -1.0239 | 0.3480 | 2.5018 | -2.0834 | 8.7233 | -0.0178 | 0.0154 |
| 35 | -0.9368 | 0.2755 | 1.7884 | -1.9078 | 6.9448 | -0.0171 | 0.0139 |
| 40 | -0.8534 | 0.2114 | 1.2643 | -1.7394 | 5.3637 | -0.0164 | 0.0121 |
| 45 | -0.7740 | 0.1561 | 0.8913 | -1.5790 | 3.9934 | -0.0155 | 0.0103 |
| 50 | -0.6988 | 0.1098 | 0.6329 | -1.4270 | 2.8392 | -0.0147 | 0.0085 |
| 55 | -0.6281 | 0.0723 | 0.4571 | -1.2837 | 1.8977 | -0.0138 | 0.0068 |
| 60 | -0.5618 | 0.0430 | 0.3378 | -1.1494 | 1.1576 | -0.0129 | 0.0052 |
The last two columns are the whole point. SGD multiplies both gradients by the same learning rate, so a coordinate with a gradient twelve times larger gets a step twelve times larger. Adam divides each coordinate by the square root of its own running squared gradient, so the two steps come out close to the same size whatever the gradients are. That is what "adapts per parameter" means, and it is these two numbers being different from each other in a way SGD's never are.
What is real here, and what is standing in
Real: every gradient is the analytic derivative of the formula shown, not a finite difference. All three update rules are the textbook ones, Adam's bias correction included and visible in the table. The stability bound on the quadratic is exact, and the divergence step beside it is measured by running until the loss stops being finite.
Standing in, and this is the big one: there is no data here. This is full-batch descent on a closed-form function, so the gradient is exact every time and there is no noise at all - the "S" in SGD is missing, and half of what momentum is for in practice is smoothing exactly that noise.
Also standing in: two dimensions. A real network has millions of parameters and a surface nobody can draw, and the mechanics generalise while the geometry does not - in high dimensions saddle points vastly outnumber local minima, which is the most important fact about a real loss landscape and the one a picture like this cannot show you. Momentum here is heavy ball rather than Nesterov, and there is no weight decay, no learning-rate schedule and no gradient clipping.
Everything on this page runs in your browser. Nothing you type is sent anywhere, there is no account, and it keeps working offline.