Math for AILoading progress…

Adam and local geometry

Perform gradient descent updates and explain learning rate, stochastic gradients, momentum and Adam.

Adam gives every coordinate its own step size

On the valley the gradient is [−0.2, 4] at the start: one coordinate is 20 times larger. Plain descent moves 20 times farther in y than in x. Adam keeps two running averages per coordinate:

  • m ← β₁·m + (1 − β₁)·g the average gradient (the momentum-like part),
  • v ← β₂·v + (1 − β₂)·g² the average squared gradient (how big this coordinate's gradients typically are).

The update is θ ← θ − η · m̂ / (√v̂ + ε), computed for each coordinate. Dividing by √v̂ rescales every coordinate to roughly the same size, so a coordinate with huge gradients and one with tiny gradients both move about η per step. The defaults are β₁ = 0.9, β₂ = 0.999 and ε = 10⁻⁸ (a small number that prevents dividing by zero).

tg (x, y)m (x, y)v (x, y)m̂ = m / (1 − β₁ᵗ)v̂ = v / (1 − β₂ᵗ)Adam step (x, y)plain GD step
1-0.2, 4-0.02, 0.40.00004, 0.016-0.2, 40.04, 160.5, -0.50.1, -2
2-0.18, 3-0.036, 0.660.00007236, 0.02498-0.1895, 3.4740.0362, 12.50.4979, -0.49130.098, 0
3-0.1601, 2.017-0.04841, 0.79570.00009791, 0.02903-0.1786, 2.9360.03267, 9.6860.4941, -0.47170.09604, 0
4-0.1403, 1.074-0.0576, 0.82360.0001175, 0.03015-0.1675, 2.3950.02942, 7.550.4882, -0.43580.09412, 0

The valley gradient at the start is [−0.2, 4]: the y component is 20 times larger. Plain gradient descent steps are proportional to that, Adam's are not.

iteration 0
Plain gradient descent (same lr): position [-5, 2], loss 4.5. At the start. Press Step.
Adam: position [-5, 2], loss 4.5. At the start. Press Step.
loss (log scale)iteration 0 to 101e21e0

Hollow dot: start. Big dot: where the optimizer is now.

Table of the first four updates on the valley, with the plain-gradient-descent step for comparison. Move the learning rate and switch bias correction off to see the first-step size change.

Bias correction, in numbers

m and v start at zero. After one step m = 0.1·g and v = 0.001·g²: far too small, only because the averages have not had time to fill. Without a fix the first update would be lr · 0.1 / √0.001 = lr · 3.16 times the right size, and in the early steps the estimates are biased toward zero. Dividing by 1 − βᵗ removes that exactly: for a gradient that never changes, m̂ and v̂ equal g and g² at every step.

tm_t1 − β₁ᵗm̂_tv_t1 − β₂ᵗv̂_t
10.20.120.0040.0014
20.380.1920.0079960.0019994
30.5420.27120.011990.0029974
50.8190.409520.019960.004994
101.3030.651320.039820.0099554
501.990.994820.19520.048794

The gradient never changes, so the right answers are m = g = 2 and v = g² = 4. The raw m and v start near zero and creep up. Dividing by 1 − βᵗ gives exactly g and g² at every step.

A constant gradient. Raw m_t and v_t creep toward g and g². The corrected columns are g and g² from step 1.

Predict first. At the very first Adam step on the valley (lr = 0.5, bias correction on), how far does x move, given its gradient is only −0.2?

Local geometry: Adam is not a guarantee

Adam rescales steps by the history of gradients; it does not know the global shape. On a bumpy surface it still slides into whichever local minimum is near its start. Below, press Run 50 with Adam, then click a different start point and run again.

L = 0.04 (x² + y²) + 0.5 sin(2x) sin(2y). Many local minima. Where you end up depends on where you start and on the optimizer.

iteration 0
Adam: position [-3, 2.5], loss 0.476. At the start. Press Step.
loss (log scale)iteration 0 to 101e11e-1

Click the plot to choose a new starting point. Hollow dot: start. Big dot: where the optimizer is now.

Adam on the bumpy surface. Different starting points end in different valleys with different losses.
Chapter context

The gradient points toward the steepest local increase under Euclidean geometry. To lower a differentiable loss, a basic optimizer steps in the opposite direction. A local direction says little about how large a safe step can be.

Chapter reference: math, worked example & code

This section belongs to the whole chapter, so it is the same on every lesson in it and may cover a different lesson's topic. The code for the experiment you just ran is inside the experiment itself.

Math and notation

θt+1=θt−η∇L(θt).\theta_{t+1}=\theta_t-\eta\nabla L(\theta_t).

Adam uses mt=β1mt−1+(1−β1)gtm_t=\beta_1m_{t-1}+(1-\beta_1)g_t and vt=β2vt−1+(1−β2)gt2v_t=\beta_2v_{t-1}+(1-\beta_2)g_t^2, coordinatewise. Divide by 1−β1t1-\beta_1^t and 1−β2t1-\beta_2^t before using m^t/(v^t+ϵ)\hat m_t/(\sqrt{\hat v_t}+\epsilon) in the update.

For the special quadratic L(θ)=(θ−c)2L(\theta)=(\theta-c)^2, the residual follows θt+1−c=(1−2η)(θt−c)\theta_{t+1}-c=(1-2\eta)(\theta_t-c). Starting away from c, convergence requires ∣1−2η∣<1|1-2\eta|<1, or 0<η<10<\eta<1. This interval depends on this particular curvature and loss normalization.

Worked example

For L=(theta−3)^2, start at 0 and use eta=0.25. The gradients are −6, −3 and −1.5. Three updates produce theta values 1.5, 2.25 and 2.625. Their losses are 2.25, 0.5625 and 0.140625. A fixed learning rate works here because the example is a simple quadratic.

Reference code

The following example uses the Python standard library and does not call a remote service.

from math import isclose
theta = 0.0
positions = []
for _ in range(3):
    theta -= 0.25 * 2*(theta-3)
    positions.append(theta)
assert positions == [1.5, 2.25, 2.625]
assert isclose((theta-3)**2, 0.140625)

Python examples are provided for study and local execution; this page does not execute Python.

Common mistakes

Subtracting loss instead of its gradient is not gradient descent. Squared gradients in Adam are coordinatewise. A zero gradient may identify a saddle point or maximum, not just a minimum.