Mathematical Foundations

VI.8 · Optimization

How do signed and squared histories set an adaptive update?

Inspect Adam's two moment vectors, correct their zero-start weight deficit, then scale each coordinate using its own squared-gradient history. Keep the time index and epsilon placement explicit at every step.

Inspect moments, bias correction and each adaptive update

Parameter space: θ₁ and θ₂

Iteration 0: at θ ≈ (2, 1), L ≈ 4 and gradient ≈ (2, 4). Rate η ≈ 0.25 gives update ≈ (−0.25, −0.25). Adding that update gives θ next ≈ (1.75, 0.75) and L next ≈ 2.65625. Adam time t = 1: first moment ≈ (0.2, 0.4), second moment ≈ (0.004, 0.016), corrected moments ≈ (2, 4) and ≈ (4, 16). Epsilon is added outside the square root. Adaptive scaling gives no global-optimality guarantee. Iteration 0: at θ ≈ (2, 1), L ≈ 4 and gradient ≈ (2, 4). Rate η ≈ 0.25 gives update ≈ (−0.25, −0.25). Adding that update gives θ next ≈ (1.75, 0.75) and L next ≈ 2.65625. Adam time t = 1: first moment ≈ (0.2, 0.4), second moment ≈ (0.004, 0.016), corrected moments ≈ (2, 4) and ≈ (4, 16). Epsilon is added outside the square root. Adaptive scaling gives no global-optimality guarantee. Stop: iteration budget. Parameters outside the displayed window are retained in the table; the view never changes the path.

Loss slice: θ₂ = 0

This is a slice of the objective in parameter space, with θ₂ fixed at zero.

Current parameter vector
(2, 1)
Current objective value
4
Actual gradient components
(2, 4)
Learning rate
0.250000
Update vector
(−0.25, −0.25)
Next parameter vector
(1.75, 0.75)
New objective value
2.656250
Adam update time (k + 1)
1
Previous first moment
(0, 0)
Previous second moment
(0, 0)
Updated first moment
(0.2, 0.4)
Updated second moment
(0.004, 0.016)
Bias-corrected first moment
(2, 4)
Bias-corrected second moment
(4, 16)
First moment decay
0.900000
Second moment decay
0.999000
Epsilon outside square root
1×10⁻⁸

≈ binary64 calculation · = analytic classification. Replay selects the same evaluated step in every view.

Iteration 0: at θ ≈ (2, 1), L ≈ 4 and gradient ≈ (2, 4). Rate η ≈ 0.25 gives update ≈ (−0.25, −0.25). Adding that update gives θ next ≈ (1.75, 0.75) and L next ≈ 2.65625. Adam time t = 1: first moment ≈ (0.2, 0.4), second moment ≈ (0.004, 0.016), corrected moments ≈ (2, 4) and ≈ (4, 16). Epsilon is added outside the square root. Adaptive scaling gives no global-optimality guarantee. Stop: iteration budget. Parameters outside the displayed window are retained in the table; the view never changes the path.

L=a2(θ1−c)2+2θ22L=\tfrac a2(\theta_1-c)^2+2\theta_2^2
θt=θt−1−ηm^tv^t+ϵ\theta_{t}=\theta_{t-1}-\eta\frac{\widehat m_t}{\sqrt{\widehat v_t}+\epsilon}
θ1≈[21]+[−0.25−0.25]≈[1.750.75]\theta_{1}\approx \begin{bmatrix}2\\1\end{bmatrix}+\begin{bmatrix}-0.25\\-0.25\end{bmatrix}\approx \begin{bmatrix}1.75\\0.75\end{bmatrix}
mt=β1mt−1+(1−β1)gt,vt=β2vt−1+(1−β2)gt2m_t=\beta_1m_{t-1}+(1-\beta_1)g_t,\quad v_t=\beta_2v_{t-1}+(1-\beta_2)g_t^2
m^t=mt1−β1t,v^t=vt1−β2t\widehat m_t=\frac{m_t}{1-\beta_1^t},\quad\widehat v_t=\frac{v_t}{1-\beta_2^t}
Evaluated binary64 history. Replay changes the selected row, never the stored mathematics.
kθ(k)L(k)gradientηupdateθ(k+1)L(k+1)tm previousv previousmvm correctedv corrected
0(2, 1)4(2, 4)0.25(−0.25, −0.25)(1.75, 0.75)2.656251(0, 0)(0, 0)(0.2, 0.4)(0.004, 0.016)(2, 4)(4, 16)
1(1.75, 0.75)2.65625(1.75, 3)0.25(−0.248579, −0.245644)(1.501421, 0.504356)1.6358822(0.2, 0.4)(0.004, 0.016)(0.355, 0.66)(0.007059, 0.024984)(1.868421, 3.473684)(3.531016, 12.498249)
2(1.501421, 0.504356)1.635882(1.501421, 2.017425)0.25(−0.245871, −0.235869)(1.25555, 0.268487)0.9323743(0.355, 0.66)(0.007059, 0.024984)(0.469642, 0.795742)(0.009306, 0.029029)(1.732997, 2.936319)(3.105006, 9.686023)
3(1.25555, 0.268487)0.932374(1.25555, 1.07395)0.25(−0.24155, −0.217892)(1.014001, 0.050595)0.5192184(0.469642, 0.795742)(0.009306, 0.029029)(0.548233, 0.823563)(0.010873, 0.030153)(1.594164, 2.394775)(2.722282, 7.549656)
4(1.014001, 0.050595)0.519218(1.014001, 0.202382)0.25(−0.23524, −0.189068)(0.778761, −0.138473)0.3415845(0.548233, 0.823563)(0.010873, 0.030153)(0.59481, 0.761445)(0.01189, 0.030164)(1.452491, 1.859405)(2.382787, 6.04491)
5(0.778761, −0.138473)0.341584(0.778761, −0.553892)0.25(−0.22653, −0.149025)(0.552231, −0.287498)0.317796(0.59481, 0.761445)(0.01189, 0.030164)(0.613205, 0.629911)(0.012485, 0.030441)(1.308703, 1.344359)(2.085993, 5.086164)
6(0.552231, −0.287498)0.31779(0.552231, −1.149993)0.25(−0.215012, −0.10156)(0.337219, −0.389058)0.3595917(0.613205, 0.629911)(0.012485, 0.030441)(0.607107, 0.451921)(0.012777, 0.031733)(1.163703, 0.866242)(1.830795, 4.546881)
7(0.337219, −0.389058)0.359591(0.337219, −1.556233)0.25(−0.200354, −0.053277)(0.136866, −0.442335)0.4006878(0.607107, 0.451921)(0.012777, 0.031733)(0.580119, 0.251106)(0.012878, 0.034123)(1.018587, 0.440897)(1.615408, 4.280322)
8(0.136866, −0.442335)0.400687(0.136866, −1.769341)0.25(−0.182391, −0.009826)(−0.045525, −0.452161)0.4099369(0.580119, 0.251106)(0.012878, 0.034123)(0.535793, 0.049061)(0.012884, 0.037219)(0.874651, 0.080089)(1.437289, 4.15206)
9(−0.045525, −0.452161)0.409936(−0.045525, −1.808645)0.25(−0.16123, 0.026031)(−0.206755, −0.42613)0.38454810(0.535793, 0.049061)(0.012884, 0.037219)(0.477662, −0.13671)(0.012873, 0.040453)(0.733373, −0.209896)(1.29312, 4.063576)
10(−0.206755, −0.42613)0.384548(−0.206755, −1.704521)0.25(−0.137315, 0.053748)(−0.34407, −0.372382)0.33652911(0.477662, −0.13671)(0.012873, 0.040453)(0.40922, −0.293491)(0.012903, 0.043318)(0.596366, −0.427711)(1.17888, 3.957759)
11(−0.34407, −0.372382)0.336529(−0.34407, −1.489528)0.25(−0.11142, 0.073713)(−0.45549, −0.298669)0.28214112(0.40922, −0.293491)(0.012903, 0.043318)(0.333891, −0.413095)(0.013009, 0.045494)(0.465308, −0.575685)(1.090019, 3.812038)

Evaluated iteration 0

Iteration 0: at θ ≈ (2, 1), L ≈ 4 and gradient ≈ (2, 4). Rate η ≈ 0.25 gives update ≈ (−0.25, −0.25). Adding that update gives θ next ≈ (1.75, 0.75) and L next ≈ 2.65625. Adam time t = 1: first moment ≈ (0.2, 0.4), second moment ≈ (0.004, 0.016), corrected moments ≈ (2, 4) and ≈ (4, 16). Epsilon is added outside the square root. Adaptive scaling gives no global-optimality guarantee.

θ1≈[21]+[−0.25−0.25]≈[1.750.75]\theta_{1}\approx \begin{bmatrix}2\\1\end{bmatrix}+\begin{bmatrix}-0.25\\-0.25\end{bmatrix}\approx \begin{bmatrix}1.75\\0.75\end{bmatrix}

from −3 to 3, up to 2 decimal places

from −3 to 3, up to 2 decimal places

from 0.25 to 4, up to 2 decimal places

from −2 to 2, up to 2 decimal places

from 0.01 to 2, up to 2 decimal places

from 1 to 40, whole numbers only

from 0 to 0.99, up to 2 decimal places

from 0 to 0.999, up to 3 decimal places

Inspect both raw moments, their bias corrections, the positive coordinate denominators, and the actual update. The first optimizer iteration k=0 is Adam time t=1.

At the canonical start (2,1)(2,1), the gradient is (2,4)(2,4). Ordinary descent with rate 1/41/4 would move by (−1/2,−1)(-1/2,-1). Adam’s first update instead moves both coordinates by nearly −1/4-1/4. Predict how dividing by the square root of a squared-gradient history produces that change, then inspect the moments rather than treating the arrow as a magic rescaling.

Intuition: direction history and magnitude history

A signed average remembers which way gradients have tended to point. An average of their squares remembers their typical magnitudes while discarding their signs. Adam uses the first history in the numerator and the square root of the second in the denominator, separately for each coordinate.

This can make coordinates with very different gradient magnitudes receive similarly sized first updates. Later updates also depend on the entire retained history, so a new sign change need not reverse the signed average immediately. Adam is not a Hessian method, a unit-gradient method, or a promise that every update lowers the objective.

Both moment vectors start at zero. Their initial geometric weights sum to less than one, which shrinks their early raw values. Bias correction removes this zero-initialization weight deficit. It does not replace a sampled gradient with the exact full gradient or make old gradients describe the current point perfectly.

Definition: Algorithm 1 with an explicit first time index

These elementwise equations follow Kingma and Ba’s Adam: A Method for Stochastic Optimization (2014), arXiv:1412.6980, Algorithm 1. Start with m0=v0=0m_0=v_0=0. At time t≥1t\geq1, evaluate gt=∇L(θt−1)g_t=\nabla L(\theta_{t-1}) and use

mt=β1mt−1+(1−β1)gt,vt=β2vt−1+(1−β2)gt⊙2,m_t=\beta_1m_{t-1}+(1-\beta_1)g_t,\qquad v_t=\beta_2v_{t-1}+(1-\beta_2)g_t^{\odot2}, m^t=mt1−β1t,v^t=vt1−β2t,θt=θt−1−ηm^tv^t+ϵ.\widehat m_t=\frac{m_t}{1-\beta_1^t},\qquad \widehat v_t=\frac{v_t}{1-\beta_2^t},\qquad \theta_t=\theta_{t-1}-\eta\frac{\widehat m_t}{\sqrt{\widehat v_t}+\epsilon}.

Squares, square roots, and division are componentwise. Require 0≤β1,β2<10\leq\beta_1,\beta_2<1, η>0\eta>0, and ϵ>0\epsilon>0. Epsilon is outside the square root. The first update uses t=1t=1, corresponding to the stage’s first iteration k=0k=0.

The lesson uses β1=0.9\beta_1=0.9, β2=0.999\beta_2=0.999, ϵ=10−8\epsilon=10^{-8}, rate η=0.25\eta=0.25, and the default quadratic start (2,1)(2,1). The rate is this toy lesson’s setting for visible movement. The notation vv now names a raw squared-gradient moment, distinct from the unnormalized velocity in the preceding momentum chapter.

Mechanics: account for every state component

Read the current parameters and gradient, previous moments, updated moments, corrected moments, time, decay factors, epsilon, and displacement together. The denominator for coordinate j is v^t,j+ϵ\sqrt{\widehat v_{t,j}}+\epsilon; it must use the same corrected second moment shown in the inspector.

The first time is 1 even though the history table begins at iteration 0. Increasing the replay cursor chooses an evaluated moment-and-parameter state; it does not change the time denominator independently or recompute a different gradient. Reset restores zero moments, zero initial time, the canonical point, and the canonical settings.

Change the rate or decay factors in the opening explorer to produce another run. The worked stage retains the canonical run. Epsilon remains the displayed configured positive constant; the deliberately enlarged epsilon in one exercise is a separate hand probe, not a claim about the explorer’s default.

Derivation: correct the missing weight, not the current gradient

Unrolling the first moment gives

mt=(1−β1)∑j=1tβ1t−jgj.m_t=(1-\beta_1)\sum_{j=1}^{t}\beta_1^{t-j}g_j.

Its weights sum to

(1−β1)∑j=1tβ1t−j=1−β1t.(1-\beta_1)\sum_{j=1}^{t}\beta_1^{t-j}=1-\beta_1^t.

Dividing by that sum produces a normalized weighted history. For a constant gradient g, mt=(1−β1t)gm_t=(1-\beta_1^t)g and m^t=g\widehat m_t=g exactly. If gradient distributions have a constant mean over time, the same calculation explains the initialization bias in expectation. When gradients change, the corrected vector remains a history average rather than necessarily the newest gradient.

Likewise,

vt=(1−β2)∑j=1tβ2t−jgj⊙2,v^t=vt1−β2t.v_t=(1-\beta_2)\sum_{j=1}^{t}\beta_2^{t-j}g_j^{\odot2}, \qquad \widehat v_t=\frac{v_t}{1-\beta_2^t}.

This is a raw second moment: it averages squares without centering around a mean. It is not a variance, a covariance matrix, or a Hessian. Squaring removes each gradient sign; the first moment determines the update sign because the denominator is positive.

At the first step from zero history, m^1=g1\widehat m_1=g_1 and v^1=g1⊙2\widehat v_1=g_1^{\odot2}, so coordinate j has

Δθj=−ηg1,j∣g1,j∣+ϵ.\Delta\theta_j=-\eta\frac{g_{1,j}}{\abs{g_{1,j}}+\epsilon}.

For a nonzero component much larger than epsilon, this is close to −ηsign⁡(g1,j)-\eta\operatorname{sign}(g_{1,j}). For a zero component it is exactly zero. This first-step cancellation does not hold in the same form once historical gradients differ.

Worked example: two different magnitudes, nearly equal steps

On L=x2/2+2y2L=x^2/2+2y^2 at θ0=(2,1)\theta_0=(2,1), g1=(2,4)g_1=(2,4). At t=1t=1 the raw moments are

m1=(0.2,0.4),v1=(0.004,0.016).m_1=(0.2,0.4),\qquad v_1=(0.004,0.016).

Their denominators are 1−0.9=0.11-0.9=0.1 and 1−0.999=0.0011-0.999=0.001, giving exact hand values

m^1=(2,4),v^1=(4,16).\widehat m_1=(2,4),\qquad \widehat v_1=(4,16).

With the lesson’s epsilon and rate, the update is

Δθ0=(−(1/4)22+10−8,−(1/4)44+10−8)≈(−0.24999999875,−0.249999999375).\Delta\theta_0= \left(-\frac{(1/4)2}{2+10^{-8}}, -\frac{(1/4)4}{4+10^{-8}}\right) \approx(-0.24999999875,-0.249999999375).

Therefore

θ1≈(1.75000000125,0.750000000625).\theta_1\approx(1.75000000125,0.750000000625).

The raw gradient’s y component was twice its x component, but its corrected squared magnitude produces twice the square-root denominator. This first update is different from plain descent’s (3/2,0)(3/2,0) at the same nominal rate. One step does not decide which algorithm is preferable for a complete problem.

Worked example: Inspect moments, bias correction and each adaptive update

Parameter space: θ₁ and θ₂

Iteration 0: at θ ≈ (2, 1), L ≈ 4 and gradient ≈ (2, 4). Rate η ≈ 0.25 gives update ≈ (−0.25, −0.25). Adding that update gives θ next ≈ (1.75, 0.75) and L next ≈ 2.65625. Adam time t = 1: first moment ≈ (0.2, 0.4), second moment ≈ (0.004, 0.016), corrected moments ≈ (2, 4) and ≈ (4, 16). Epsilon is added outside the square root. Adaptive scaling gives no global-optimality guarantee. Iteration 0: at θ ≈ (2, 1), L ≈ 4 and gradient ≈ (2, 4). Rate η ≈ 0.25 gives update ≈ (−0.25, −0.25). Adding that update gives θ next ≈ (1.75, 0.75) and L next ≈ 2.65625. Adam time t = 1: first moment ≈ (0.2, 0.4), second moment ≈ (0.004, 0.016), corrected moments ≈ (2, 4) and ≈ (4, 16). Epsilon is added outside the square root. Adaptive scaling gives no global-optimality guarantee. Stop: iteration budget. Parameters outside the displayed window are retained in the table; the view never changes the path.

Loss slice: θ₂ = 0

This is a slice of the objective in parameter space, with θ₂ fixed at zero.

Current parameter vector
(2, 1)
Current objective value
4
Actual gradient components
(2, 4)
Learning rate
0.250000
Update vector
(−0.25, −0.25)
Next parameter vector
(1.75, 0.75)
New objective value
2.656250
Adam update time (k + 1)
1
Previous first moment
(0, 0)
Previous second moment
(0, 0)
Updated first moment
(0.2, 0.4)
Updated second moment
(0.004, 0.016)
Bias-corrected first moment
(2, 4)
Bias-corrected second moment
(4, 16)
First moment decay
0.900000
Second moment decay
0.999000
Epsilon outside square root
1×10⁻⁸

≈ binary64 calculation · = analytic classification. Replay selects the same evaluated step in every view.

Iteration 0: at θ ≈ (2, 1), L ≈ 4 and gradient ≈ (2, 4). Rate η ≈ 0.25 gives update ≈ (−0.25, −0.25). Adding that update gives θ next ≈ (1.75, 0.75) and L next ≈ 2.65625. Adam time t = 1: first moment ≈ (0.2, 0.4), second moment ≈ (0.004, 0.016), corrected moments ≈ (2, 4) and ≈ (4, 16). Epsilon is added outside the square root. Adaptive scaling gives no global-optimality guarantee. Stop: iteration budget. Parameters outside the displayed window are retained in the table; the view never changes the path.

L=a2(θ1−c)2+2θ22L=\tfrac a2(\theta_1-c)^2+2\theta_2^2
θt=θt−1−ηm^tv^t+ϵ\theta_{t}=\theta_{t-1}-\eta\frac{\widehat m_t}{\sqrt{\widehat v_t}+\epsilon}
θ1≈[21]+[−0.25−0.25]≈[1.750.75]\theta_{1}\approx \begin{bmatrix}2\\1\end{bmatrix}+\begin{bmatrix}-0.25\\-0.25\end{bmatrix}\approx \begin{bmatrix}1.75\\0.75\end{bmatrix}
mt=β1mt−1+(1−β1)gt,vt=β2vt−1+(1−β2)gt2m_t=\beta_1m_{t-1}+(1-\beta_1)g_t,\quad v_t=\beta_2v_{t-1}+(1-\beta_2)g_t^2
m^t=mt1−β1t,v^t=vt1−β2t\widehat m_t=\frac{m_t}{1-\beta_1^t},\quad\widehat v_t=\frac{v_t}{1-\beta_2^t}
Evaluated binary64 history. Replay changes the selected row, never the stored mathematics.
kθ(k)L(k)gradientηupdateθ(k+1)L(k+1)tm previousv previousmvm correctedv corrected
0(2, 1)4(2, 4)0.25(−0.25, −0.25)(1.75, 0.75)2.656251(0, 0)(0, 0)(0.2, 0.4)(0.004, 0.016)(2, 4)(4, 16)
1(1.75, 0.75)2.65625(1.75, 3)0.25(−0.248579, −0.245644)(1.501421, 0.504356)1.6358822(0.2, 0.4)(0.004, 0.016)(0.355, 0.66)(0.007059, 0.024984)(1.868421, 3.473684)(3.531016, 12.498249)
2(1.501421, 0.504356)1.635882(1.501421, 2.017425)0.25(−0.245871, −0.235869)(1.25555, 0.268487)0.9323743(0.355, 0.66)(0.007059, 0.024984)(0.469642, 0.795742)(0.009306, 0.029029)(1.732997, 2.936319)(3.105006, 9.686023)
3(1.25555, 0.268487)0.932374(1.25555, 1.07395)0.25(−0.24155, −0.217892)(1.014001, 0.050595)0.5192184(0.469642, 0.795742)(0.009306, 0.029029)(0.548233, 0.823563)(0.010873, 0.030153)(1.594164, 2.394775)(2.722282, 7.549656)
4(1.014001, 0.050595)0.519218(1.014001, 0.202382)0.25(−0.23524, −0.189068)(0.778761, −0.138473)0.3415845(0.548233, 0.823563)(0.010873, 0.030153)(0.59481, 0.761445)(0.01189, 0.030164)(1.452491, 1.859405)(2.382787, 6.04491)
5(0.778761, −0.138473)0.341584(0.778761, −0.553892)0.25(−0.22653, −0.149025)(0.552231, −0.287498)0.317796(0.59481, 0.761445)(0.01189, 0.030164)(0.613205, 0.629911)(0.012485, 0.030441)(1.308703, 1.344359)(2.085993, 5.086164)
6(0.552231, −0.287498)0.31779(0.552231, −1.149993)0.25(−0.215012, −0.10156)(0.337219, −0.389058)0.3595917(0.613205, 0.629911)(0.012485, 0.030441)(0.607107, 0.451921)(0.012777, 0.031733)(1.163703, 0.866242)(1.830795, 4.546881)
7(0.337219, −0.389058)0.359591(0.337219, −1.556233)0.25(−0.200354, −0.053277)(0.136866, −0.442335)0.4006878(0.607107, 0.451921)(0.012777, 0.031733)(0.580119, 0.251106)(0.012878, 0.034123)(1.018587, 0.440897)(1.615408, 4.280322)
8(0.136866, −0.442335)0.400687(0.136866, −1.769341)0.25(−0.182391, −0.009826)(−0.045525, −0.452161)0.4099369(0.580119, 0.251106)(0.012878, 0.034123)(0.535793, 0.049061)(0.012884, 0.037219)(0.874651, 0.080089)(1.437289, 4.15206)
9(−0.045525, −0.452161)0.409936(−0.045525, −1.808645)0.25(−0.16123, 0.026031)(−0.206755, −0.42613)0.38454810(0.535793, 0.049061)(0.012884, 0.037219)(0.477662, −0.13671)(0.012873, 0.040453)(0.733373, −0.209896)(1.29312, 4.063576)
10(−0.206755, −0.42613)0.384548(−0.206755, −1.704521)0.25(−0.137315, 0.053748)(−0.34407, −0.372382)0.33652911(0.477662, −0.13671)(0.012873, 0.040453)(0.40922, −0.293491)(0.012903, 0.043318)(0.596366, −0.427711)(1.17888, 3.957759)
11(−0.34407, −0.372382)0.336529(−0.34407, −1.489528)0.25(−0.11142, 0.073713)(−0.45549, −0.298669)0.28214112(0.40922, −0.293491)(0.012903, 0.043318)(0.333891, −0.413095)(0.013009, 0.045494)(0.465308, −0.575685)(1.090019, 3.812038)

Evaluated iteration 0

Iteration 0: at θ ≈ (2, 1), L ≈ 4 and gradient ≈ (2, 4). Rate η ≈ 0.25 gives update ≈ (−0.25, −0.25). Adding that update gives θ next ≈ (1.75, 0.75) and L next ≈ 2.65625. Adam time t = 1: first moment ≈ (0.2, 0.4), second moment ≈ (0.004, 0.016), corrected moments ≈ (2, 4) and ≈ (4, 16). Epsilon is added outside the square root. Adaptive scaling gives no global-optimality guarantee.

θ1≈[21]+[−0.25−0.25]≈[1.750.75]\theta_{1}\approx \begin{bmatrix}2\\1\end{bmatrix}+\begin{bmatrix}-0.25\\-0.25\end{bmatrix}\approx \begin{bmatrix}1.75\\0.75\end{bmatrix}

Replay canonical Adam time t=1: m=(0.2,0.4), v=(0.004,0.016), corrected moments (2,4) and (4,16), and next parameters approximately (1.75000000125,0.750000000625).

As a separate scalar sign probe, prescribe gradients 22 then −2-2 rather than taking the canonical quadratic’s next gradient. At t=2t=2,

m2=0.9(0.2)+0.1(−2)=−0.02,v2=0.999(0.004)+0.001(4)=0.007996.m_2=0.9(0.2)+0.1(-2)=-0.02,\quad v_2=0.999(0.004)+0.001(4)=0.007996.

Bias denominators 0.190.19 and 0.0019990.001999 give m^2=−2/19\widehat m_2=-2/19 and v^2=4\widehat v_2=4. The second moment retains magnitude while the signed moment reverses. This explicit gradient sequence tests the state recurrence; it is not a replacement for the actual gradients in the stage’s quadratic trajectory.

Executable reference code

The standard-library program implements Algorithm 1 with an independent 80-digit Decimal calculation. The first moments and corrected literal values are exact for the decimal inputs; later square roots and divisions are high-precision approximations. Assertions cover the canonical first update, positive epsilon, zero history, zero current input with retained history, sign reversals, and an enlarged-epsilon hand calculation.

It also evolves eight actual quadratic steps and independently checks the moment recurrences against explicit weighted gradient histories. The NumPy program evolves multiple starts with array operations and cross-checks those moments against a lower-triangular weight matrix acting on the saved gradients. Its binary64 tolerance is 10−1410^{-14} on that bounded run. Neither program imports another book reference or installs an optimizer library.

code/python/optimization_adam.py
"""Independent 80-digit Decimal Adam, Algorithm 1: https://arxiv.org/pdf/1412.6980.

The first moment step uses t=1; epsilon is outside the square root.
Decimal outputs involving square roots are high-precision approximations.
"""
from decimal import Decimal as D, localcontext


def adam_update(gradient, m=(0, 0), v=(0, 0), t=1,
                eta="0.25", beta1="0.9", beta2="0.999", epsilon="1e-8"):
    if type(t) is not int or t < 1:
        raise ValueError("The first update is t=1, not t=0")
    if any(len(vector) != 2 for vector in (gradient, m, v)):
        raise ValueError("Require two-component gradient and moment vectors")
    with localcontext() as context:
        context.prec = 80
        gradient, m, v = (tuple(D(str(x)) for x in vector) for vector in (gradient, m, v))
        eta, beta1, beta2, epsilon = map(lambda x: D(str(x)), (eta, beta1, beta2, epsilon))
        if not all(x.is_finite() for x in (*gradient, *m, *v, eta, beta1, beta2, epsilon)):
            raise ValueError("Require finite inputs")
        if eta <= 0 or epsilon <= 0 or not 0 <= beta1 < 1 or not 0 <= beta2 < 1 or any(x < 0 for x in v):
            raise ValueError("Require eta,epsilon>0, betas in [0,1), and nonnegative second moments")
        next_m = tuple(beta1*old+(1-beta1)*g for old, g in zip(m, gradient))
        next_v = tuple(beta2*old+(1-beta2)*g*g for old, g in zip(v, gradient))
        m_hat = tuple(value/(1-beta1**t) for value in next_m)
        v_hat = tuple(value/(1-beta2**t) for value in next_v)
        update = tuple(-eta*mean/(second.sqrt()+epsilon) for mean, second in zip(m_hat, v_hat))
        return {"t": t, "gradient": gradient, "m": next_m, "v": next_v,
                "m_hat": m_hat, "v_hat": v_hat, "update": update}


def main():
    with localcontext() as context:
        context.prec = 80
        first = adam_update((2, 4))
        assert first["m"] == (D("0.2"), D("0.4"))
        assert first["v"] == (D("0.004"), D("0.016"))
        assert first["m_hat"] == (2, 4) and first["v_hat"] == (4, 16)
        assert first["update"] == (-D("0.25")*2/(2+D("1e-8")), -D("0.25")*4/(4+D("1e-8")))
        zero = adam_update((0, 0))
        assert zero["m_hat"] == zero["v_hat"] == zero["update"] == (0, 0)
        retained = adam_update((0, 0), first["m"], first["v"], t=2)
        assert retained["m"] == (D("0.18"), D("0.36"))
        assert all(x < 0 for x in retained["update"])
        reversed_gradient = adam_update((-2, -4), first["m"], first["v"], t=2)
        assert reversed_gradient["m"] == (D("-0.02"), D("-0.04"))
        assert reversed_gradient["v"] == (D("0.007996"), D("0.031984"))
        assert reversed_gradient["m_hat"] == (-D(2)/19, -D(4)/19)
        assert reversed_gradient["v_hat"] == (4, 16)
        small_reversal = adam_update(("-0.1", 0), first["m"], first["v"], t=2)
        assert small_reversal["m"] == (D("0.17"), D("0.36"))
        assert small_reversal["update"][0] < 0  # Memory still points against the new negative gradient.
        large_epsilon = adam_update((2, 4), epsilon=1)
        assert large_epsilon["update"] == (-D(1)/6, -D(1)/5)
        theta, m, v, gradients, path = (D(2), D(1)), (D(0), D(0)), (D(0), D(0)), [], []
        for t in range(1, 9):
            gradient = (theta[0], 4*theta[1])
            gradients.append(gradient)
            item = adam_update(gradient, m, v, t)
            weighted_m = tuple(D("0.1")*sum(D("0.9")**(t-i)*g[j] for i, g in enumerate(gradients, 1)) for j in (0, 1))
            weighted_v = tuple(D("0.001")*sum(D("0.999")**(t-i)*g[j]*g[j] for i, g in enumerate(gradients, 1)) for j in (0, 1))
            assert all(abs(actual-expected) < D("1e-70") for actual, expected in zip(item["m"], weighted_m))
            assert all(abs(actual-expected) < D("1e-70") for actual, expected in zip(item["v"], weighted_v))
            theta = tuple(theta[j]+item["update"][j] for j in (0, 1))
            m, v = item["m"], item["v"]
            path.append(theta)
        for kwargs in ({"t": 0}, {"beta1": 1}, {"beta2": -1}, {"epsilon": 0}, {"eta": 0}):
            try:
                adam_update((2, 4), **kwargs)
            except ValueError:
                pass
            else:
                raise AssertionError("Invalid Adam configuration accepted")
        print("First-step high-precision moments and update:", first)
        print("First next theta, 80-digit approximations:", path[0])
        print("Zero current gradient can retain a nonzero update from moment history.")
        print("A finite Adam run does not certify convergence or global optimality.")


if __name__ == "__main__":
    main()
code/python/optimization_adam_numpy.py
"""Vectorized binary64 Adam paths, checked against explicit weighted gradient histories."""
import numpy as np


def trajectories(starts, iterations=8, eta=0.25, beta1=0.9, beta2=0.999, epsilon=1e-8):
    starts = np.asarray(starts, dtype=np.float64)
    if starts.ndim != 2 or starts.shape[1] != 2 or not np.all(np.isfinite(starts)):
        raise ValueError("Require finite starts of shape (n,2)")
    if not np.all(np.isfinite([eta, beta1, beta2, epsilon])) or eta <= 0 or epsilon <= 0 or not 0 <= beta1 < 1 or not 0 <= beta2 < 1:
        raise ValueError("Require finite parameters, eta,epsilon>0, and betas in [0,1)")
    if type(iterations) is not int or not 1 <= iterations <= 1000:
        raise ValueError("Require an integer iteration count in [1,1000]")
    path = np.empty((iterations+1, len(starts), 2), dtype=np.float64)
    gradients = np.empty((iterations, len(starts), 2), dtype=np.float64)
    moments, seconds, updates = np.empty_like(gradients), np.empty_like(gradients), np.empty_like(gradients)
    m, v = np.zeros_like(starts), np.zeros_like(starts)
    path[0] = starts
    for k in range(iterations):
        t = k+1
        gradients[k] = path[k]*np.array([1.0, 4.0])
        m = beta1*m+(1-beta1)*gradients[k]
        v = beta2*v+(1-beta2)*gradients[k]**2
        moments[k], seconds[k] = m, v
        m_hat, v_hat = m/(1-beta1**t), v/(1-beta2**t)
        updates[k] = -eta*m_hat/(np.sqrt(v_hat)+epsilon)
        path[k+1] = path[k]+updates[k]
        if not np.all(np.isfinite(path[k+1])) or not np.all(np.isfinite(m)) or not np.all(np.isfinite(v)):
            raise OverflowError(f"Non-finite binary64 Adam state at t={t}")
    return path, gradients, moments, seconds, updates


def weighted_moments(gradients, beta):
    count = len(gradients)
    lag = np.arange(count)[:, None]-np.arange(count)[None, :]
    weights = np.where(lag >= 0, (1-beta)*beta**np.maximum(lag, 0), 0.0)
    return np.einsum("ti,inj->tnj", weights, gradients)


def main():
    path, gradients, moments, seconds, updates = trajectories([[2, 1], [-2, -1], [0, 0]])
    np.testing.assert_allclose(moments, weighted_moments(gradients, 0.9), rtol=0, atol=1e-14)
    np.testing.assert_allclose(seconds, weighted_moments(gradients**2, 0.999), rtol=0, atol=1e-14)
    np.testing.assert_allclose(moments[0, 0], [0.2, 0.4], rtol=0, atol=1e-14)
    np.testing.assert_allclose(seconds[0, 0], [0.004, 0.016], rtol=0, atol=1e-14)
    expected_first = -0.25*np.array([2.0, 4.0])/(np.array([2.0, 4.0])+1e-8)
    np.testing.assert_allclose(updates[0, 0], expected_first, rtol=0, atol=1e-14)
    np.testing.assert_allclose(path[1, 0], [1.75000000125, 0.750000000625], rtol=0, atol=1e-14)
    assert np.all(path[:, 2] == 0) and np.all(updates[:, 2] == 0)
    probes = np.array([[[2.0, 4.0]], [[0.0, 0.0]], [[-2.0, -4.0]]])
    probe_m, probe_v = weighted_moments(probes, 0.9), weighted_moments(probes**2, 0.999)
    t = np.arange(1, 4)[:, None, None]
    probe_updates = -0.25*(probe_m/(1-0.9**t))/(np.sqrt(probe_v/(1-0.999**t))+1e-8)
    assert np.all(probe_updates[1] < 0) and np.all(probe_updates[2] > 0)
    np.testing.assert_allclose(probe_m[1, 0], [0.18, 0.36], rtol=0, atol=1e-14)
    reversal = weighted_moments(np.array([[[2.0, 4.0]], [[-2.0, -4.0]]]), 0.9)
    np.testing.assert_allclose(reversal[1, 0]/(1-0.9**2), [-2/19, -4/19], rtol=0, atol=1e-14)
    large_epsilon = trajectories([[2, 1]], iterations=1, epsilon=1)[4]
    np.testing.assert_allclose(large_epsilon[0, 0], [-1/6, -1/5], rtol=0, atol=1e-14)
    for kwargs in ({"epsilon": 0}, {"beta1": 1}, {"beta2": np.nan}, {"eta": 0}):
        try:
            trajectories([[2, 1]], **kwargs)
        except ValueError:
            pass
        else:
            raise AssertionError("Invalid Adam configuration accepted")
    print("Binary64 Adam path for the first start ≈", path[:, 0])
    print("Binary64 first moments ≈", moments[:, 0])
    print("Weighted-history cross-check: absolute tolerance 1e-14 on this bounded run.")
    print("The raw second moment is not a Hessian or a centered variance.")


if __name__ == "__main__":
    main()

Explore: zero coordinates and changing direction

Choose zero gradients. With zero moment history and a zero initial gradient, both raw and corrected moments remain zero. The denominator is epsilon, so the displacement is the defined zero vector. Choose one zero component instead: the corresponding history stays zero while the other coordinate evolves.

Use the sign-change preset and compare current gradient signs with corrected first-moment signs before reading the displacement. The squared moment remains nonnegative; it cannot reverse a denominator’s sign. A small opposing gradient can leave the signed average pointing its old way.

For a hand example of that lag, prescribe scalar gradients 22 then −1/10-1/10 with β1=9/10\beta_1=9/10. The second first moment is 0.9(0.2)+0.1(−0.1)=0.17>00.9(0.2)+0.1(-0.1)=0.17>0. The update is therefore still negative despite a negative current gradient. With retained nonzero moments, a zero current gradient can likewise leave a nonzero update after decay. A fresh zero-history preset and a zero gradient inside an ongoing run are different states.

Common mistakes and counterexamples

Starting the correction at t=0t=0 divides by zero. Using 1−β1-\beta at every time treats all updates like the first one. Bias correction normalizes a whole weighted history, so its denominator depends on the actual count of parameter updates, not the number of examples in a mini-batch.

Moving epsilon inside the root changes the algorithm. To see the difference exactly, keep the first corrected moments but use ϵ=1\epsilon=1 for a hand probe. The denominators are 4+1=3\sqrt4+1=3 and 16+1=5\sqrt{16}+1=5, so the update is (−1/6,−1/5)(-1/6,-1/5) and next point (11/6,4/5)(11/6,4/5). Replacing the denominators by 5\sqrt5 and 17\sqrt{17} would produce different values.

Numerical considerations

The stage records binary64 approximations, including powers, corrections, square roots, and parameter additions. The Decimal reference is a high-precision cross-check rather than a symbolic guarantee that every returned decimal expansion is exact. Keep hand-exact moments separate from rounded numerical trajectory values.

When a decay is close to 1, calculating 1−βt1-\beta^t subtracts nearby numbers and can lose relative accuracy. Squaring a very small gradient can underflow; squaring a large finite gradient can overflow before a parameter update is computed. Check raw and corrected moments for finite values instead of accepting a misleading zero update from an infinite denominator.

Positive epsilon prevents division by zero at zero corrected second moment and controls behavior when gradient scale is tiny. It also means rescaling all gradients does not give exact scale invariance in general: the constant epsilon does not scale with them. Epsilon placement and magnitude are therefore mathematical parts of the chosen update, not display details.

Engineering and ML connections

Momentum retains an unnormalized accumulated gradient, while Adam retains a normalized signed average plus a normalized squared-gradient history and corrects their initial weights. Stochastic mini-batches can supply the gradients, but Adam’s moments do not turn biased sampling into unbiased sampling.

A restart must preserve parameters, both moment vectors, the time count, and the configured decay and epsilon values to continue the same run. Keeping only the parameters and resetting the moments changes later displacements. Automatic differentiation computes gradients; Adam’s state transition is the separate mechanism using them. Convexity describes an objective’s global structure, which no optimizer name can supply automatically.

Exercises

Use exact rational answers for moment arithmetic and the enlarged-epsilon probe. State when a gradient sequence is prescribed rather than generated by the canonical objective.

calculation

Correct the first moments at t=1

Start Adam from zero moments with g=(2,4), β₁=9/10, β₂=999/1000 and t=1. Give m_x, v_x, corrected m_x, corrected v_x, corrected m_y, and corrected v_y.

construction

Make epsilon placement visible

For the first canonical Adam step, corrected m=(2,4), corrected v=(4,16), η=1/4 and θ=(2,1). For this hand calculation only set ε=1, instead of 10⁻⁸. With update=−ηm̂/(sqrt(v̂)+ε), give both update components and next coordinates.

prediction

Reverse the signed gradient

In a scalar probe, use gradients g₁=2 then g₂=−2, zero initial moments, β₁=9/10 and β₂=999/1000. At t=2 give m₂, v₂, corrected m₂, and corrected v₂.

explanation

Separate zero input from zero history

With ε>0, what does Adam do with a zero current gradient?

Choose one answer

prediction

Read the direction from the first moment

A scalar probe starts from zero moments, sees g₁=2 then g₂=−1/10, and uses β₁=9/10 with positive η,ε and valid β₂. Which statement is correct?

Choose one answer

Summary and checkpoints

Adam updates signed and squared-gradient histories, divides by their accumulated weight sums, and scales each coordinate by a square-root denominator with epsilon outside. Check that you can recover the canonical first moments and update, identify the first time as 1, preserve sign information in the correct vector, and distinguish zero input from zero history. Adaptive state explains movement; it does not by itself prove convergence or optimality.

The map of the book

97 of 97 chapters written · eight Parts

demo Foundation demo Try the live vector example Open as a page

Part I

Mathematical Language

The notation and mental objects everything else uses.

9 of 9 chapters written

  1. I.1 Scalars, quantities, units, powers and roots available
  2. I.2 Coordinates and points available
  3. I.3 Vectors: components, magnitude, and direction reference chapter available
  4. I.4 Algebraic expressions, equations and inequalities available
  5. I.5 Functions as input → transformation → output available
  6. I.6 Essential function families available
  7. I.7 Sets, intervals, and relations available
  8. I.8 Indexed quantities and summation available
  9. I.9 The notation map for ML available

Part II

Linear Algebra

Matrices as transformations: the strongest foundation in the book.

19 of 19 chapters written

  1. II.1 Vector addition and subtraction available
  2. II.2 Scalar multiplication and vector scaling available
  3. II.3 Norms, magnitude, and normalization available
  4. II.4 Dot product, angle, and orthogonality available
  5. II.5 Projection and distance to a direction available
  6. II.6 Linear combinations and span available
  7. II.7 Linear independence, basis, and coordinates available
  8. II.8 Matrices as linear transformations available
  9. II.9 Matrix × vector available
  10. II.10 Matrix × matrix as composition available
  11. II.11 Transpose and orthogonality available
  12. II.12 Determinant: orientation and area/volume scaling available
  13. II.13 Linear systems as intersecting constraints available
  14. II.14 Gaussian elimination and row operations available
  15. II.15 Rank and invertibility available
  16. II.16 Inverse matrices available
  17. II.17 Eigenvalues and eigenvectors available
  18. II.18 Orthogonal bases and least-squares geometry available
  19. II.19 Singular Value Decomposition available

Part III

Calculus

Change, local approximation, and sensitivity made visible.

15 of 15 chapters written

  1. III.1 Limits through approach available
  2. III.2 Continuity and local behavior available
  3. III.3 Derivative as secant → tangent available
  4. III.4 Derivative as rate of change and local linear model available
  5. III.5 Derivative rules available
  6. III.6 Chain rule available
  7. III.7 Multivariable functions and partial derivatives available
  8. III.8 Gradient and directional derivatives available
  9. III.9 Jacobian available
  10. III.10 Computational graphs and automatic differentiation available
  11. III.11 Hessian and curvature available
  12. III.12 Integrals as accumulation available
  13. III.13 Fundamental derivative/integral connection available
  14. III.14 Numerical differentiation available
  15. III.15 Numerical integration available

Part IV

Probability

Uncertainty through sample spaces, evidence, and repetition.

16 of 16 chapters written

  1. IV.1 Random experiments, outcomes, and sample spaces available
  2. IV.2 Events and probability mass available
  3. IV.3 Counting and finite probability where needed available
  4. IV.4 Conditional probability as restricted sample space available
  5. IV.5 Independence available
  6. IV.6 Bayes' theorem as probability-mass update available
  7. IV.7 Random variables available
  8. IV.8 PMF, PDF, and CDF available
  9. IV.9 Bernoulli and Binomial distributions available
  10. IV.10 Uniform and Gaussian distributions available
  11. IV.11 Expectation available
  12. IV.12 Variance and standard deviation available
  13. IV.13 Joint, marginal, and conditional distributions available
  14. IV.14 Covariance and correlation available
  15. IV.15 Law of Large Numbers available
  16. IV.16 Central Limit Theorem available

Part V

Statistics

From observed data to estimates, intervals, and likelihood.

10 of 10 chapters written

  1. V.1 Data summaries: mean, median, mode available
  2. V.2 Spread: variance, standard deviation, robust interpretation available
  3. V.3 Population, sample, and sampling variability available
  4. V.4 Estimators and estimation available
  5. V.5 Confidence intervals through repeated sampling available
  6. V.6 Covariance matrices and multivariate spread available
  7. V.7 Regression fundamentals available
  8. V.8 Likelihood available
  9. V.9 Maximum Likelihood Estimation available
  10. V.10 Maximum A Posteriori estimation available

Part VI

Optimization

Learning as repeated parameter updates governed by an objective.

10 of 10 chapters written

  1. VI.1 Objective functions and optimization landscapes available
  2. VI.2 Local vs global optima and stationary points available
  3. VI.3 Convexity available
  4. VI.4 Gradient descent flagship chapter available
  5. VI.5 Learning rate and convergence behavior available
  6. VI.6 Momentum available
  7. VI.7 Stochastic and mini-batch gradient descent available
  8. VI.8 Adam intuition available
  9. VI.9 Constraints and projected/penalized intuition available
  10. VI.10 Numerical stopping and optimization diagnostics available

Part VII

Information Theory

Logarithms, entropy, and the loss behind token prediction.

8 of 8 chapters written

  1. VII.1 Logarithms and log probabilities in computation available
  2. VII.2 Self-information available
  3. VII.3 Entropy available
  4. VII.4 Cross entropy and negative log-likelihood available
  5. VII.5 KL divergence available
  6. VII.6 Logits and softmax available
  7. VII.7 Numerical stability: log-sum-exp and stable softmax available
  8. VII.8 From token logits to language-model loss available

Part VIII

Numerical Computing

Why equivalent expressions behave differently on real machines.

10 of 10 chapters written

  1. VIII.1 Floating-point representation available
  2. VIII.2 Rounding and representation error available
  3. VIII.3 Error propagation and conditioning available
  4. VIII.4 Catastrophic cancellation available
  5. VIII.5 Overflow and underflow available
  6. VIII.6 Stable algorithms available
  7. VIII.7 Numerical linear algebra realities available
  8. VIII.8 Sparse matrices and sparse structure available
  9. VIII.9 Vectorized computation available
  10. VIII.10 Reproducibility, random seeds, and nondeterminism available