AI / ML Theory
Chapter 3 · 15 min

3.2 — Exponential moving averages and bias correction

Goal: Define the EMA, derive its bias when initialised at zero, and recover the v_t/(1−β^t) correction used by Adam.

1. Why this session exists

Every adaptive optimiser we'll meet — momentum, RMSProp, Adam, AdamW, Lion — runs an exponential moving average (EMA) over some quantity that changes from step to step (the gradient itself, or the squared gradient). The EMA gives a smooth, low-variance running estimate without storing the entire history.

This session does the EMA in isolation: definition, recurrence, what it converges to, and why the standard initialisation v0=0v_0 = 0 creates a bias that must be corrected. The correction vt/(1−βt)v_t / (1 - \beta^t) from the Adam paper is not a heuristic — it falls out of one line of algebra.


2. Definition

Given a sequence of vectors g1,g2,g3,…g_1, g_2, g_3, \dots (the "raw" signal) and a decay rate β∈[0,1)\beta \in [0, 1), define the EMA vtv_t by the recurrence

 vt=βvt−1+(1−β)gt,v0=0. \boxed{\ v_t = \beta v_{t-1} + (1 - \beta) g_t, \qquad v_0 = 0.\ }

For β=0.9\beta = 0.9, each new gradient contributes 10%10\% to vtv_t and the previous average is discounted by 90%90\%. For β=0.99\beta = 0.99 the average is much smoother — it remembers many more steps.


3. Unrolling: the EMA as a weighted sum

Iterate the recurrence:

v1=β⋅0+(1−β)g1=(1−β)g1,v2=βv1+(1−β)g2=(1−β)[βg1+g2],v3=βv2+(1−β)g3=(1−β)[β2g1+βg2+g3],  ⋮vt=(1−β)∑k=1tβt−kgk.\begin{aligned} v_1 &= \beta \cdot 0 + (1 - \beta) g_1 = (1 - \beta) g_1, \\ v_2 &= \beta v_1 + (1 - \beta) g_2 = (1 - \beta)\bigl[\beta g_1 + g_2\bigr], \\ v_3 &= \beta v_2 + (1 - \beta) g_3 = (1 - \beta)\bigl[\beta^2 g_1 + \beta g_2 + g_3\bigr], \\ &\;\vdots \\ v_t &= (1 - \beta) \sum_{k=1}^t \beta^{t-k} g_k. \end{aligned}

So vtv_t is a weighted sum of past gradients with weights wk=(1−β)βt−kw_k = (1 - \beta) \beta^{t-k}. Most recent: weight (1−β)(1 - \beta). One step back: β(1−β)\beta (1 - \beta). Geometric decay.

The total weight is

∑k=1t(1−β)βt−k=(1−β)⋅1−βt1−β=1−βt.\sum_{k=1}^t (1 - \beta) \beta^{t-k} = (1 - \beta) \cdot \frac{1 - \beta^t}{1 - \beta} = 1 - \beta^t.

Two regimes:

  • For large tt (βt≈0\beta^t \approx 0), the total weight tends to 11: vtv_t is a proper convex combination of past gkg_k's.
  • For small tt (early in training), the total weight 1−βt1 - \beta^t is less than 11, and vtv_t is biased toward zero.

This second observation is the entire reason for the correction in §5.[1]


4. Effective window size

A useful sanity check: what is the "effective" number of past gradients an EMA with decay β\beta averages over? Heuristic argument — define the effective window as the number of recent samples that carry, say, half the total weight.

The weights are wt−k=(1−β)βkw_{t-k} = (1 - \beta) \beta^k for k=0,1,2,…k = 0, 1, 2, \dots. The cumulative weight after KK most recent samples is

∑k=0K−1(1−β)βk=1−βK.\sum_{k=0}^{K-1} (1 - \beta) \beta^k = 1 - \beta^K.

Set this equal to 1/21/2: βK=1/2  ⟹  K=log⁡(1/2)/log⁡(β)\beta^K = 1/2 \implies K = \log(1/2) / \log(\beta). For β=0.9\beta = 0.9, K≈6.6K \approx 6.6. For β=0.99\beta = 0.99, K≈69K \approx 69. For β=0.999\beta = 0.999, K≈693K \approx 693.

The convenient rule of thumb is

effective window  ≈  11−β.\text{effective window} \;\approx\; \frac{1}{1 - \beta}.

(Same order as the half-life, off by a small constant.) Adam's defaults β1=0.9\beta_1 = 0.9 and β2=0.999\beta_2 = 0.999 mean: average gradients over the last ∼10\sim 10 steps; average squared gradients over the last ∼1000\sim 1000 steps.


5. The bias and its correction

Assume gtg_t is i.i.d. from some distribution with mean E[gt]=g⋆\mathbb{E}[g_t] = g^\star (a "true" gradient we're trying to estimate). Take the expectation of the unrolled vtv_t:

E[vt]=(1−β)∑k=1tβt−kE[gk]=g⋆⋅(1−β)∑k=1tβt−k=g⋆⋅(1−βt).\mathbb{E}[v_t] = (1 - \beta) \sum_{k=1}^t \beta^{t-k} \mathbb{E}[g_k] = g^\star \cdot (1 - \beta) \sum_{k=1}^t \beta^{t-k} = g^\star \cdot (1 - \beta^t).

So vtv_t underestimates g⋆g^\star by exactly the factor 1−βt1 - \beta^t. The estimator is biased — toward zero, the value v0v_0 was initialised to.

The fix is the obvious one. Define the bias-corrected EMA

 v^t  :=  vt1−βt. \boxed{\ \hat v_t \;:=\; \frac{v_t}{1 - \beta^t}.\ }

Then E[v^t]=g⋆\mathbb{E}[\hat v_t] = g^\star. v^t\hat v_t is the unbiased moving average; vtv_t is the raw one.

The correction matters most in the early steps. At t=1t = 1 with β=0.9\beta = 0.9, 1−βt=0.11 - \beta^t = 0.1, so v^1=10⋅v1=g1\hat v_1 = 10 \cdot v_1 = g_1 — the first gradient, as it should be. At t=1t = 1 with β=0.999\beta = 0.999, v^1=1000⋅v1=g1\hat v_1 = 1000 \cdot v_1 = g_1 again. After many steps (βt→0\beta^t \to 0), v^t≈vt\hat v_t \approx v_t and the correction is irrelevant.


6. Why not just initialise v0≠0v_0 \ne 0?

You could. Setting v0=g1v_0 = g_1 would make vtv_t a valid weighted average from step 1 onward. The reason every implementation initialises to zero anyway:

  1. You don't know g1g_1 at t=0t = 0. Code is cleaner if v0v_0 is set before the first gradient is computed.
  2. The correction is one line of arithmetic. v^t=vt/(1−βt)\hat v_t = v_t / (1 - \beta^t). Cheap.
  3. For t→∞t \to \infty they coincide. Long training runs barely see the bias; we pay for the correction only when it matters (warmup / short runs).

Zero-init is the convention. Bias correction lives in the optimiser's update.


7. Two EMAs we will use

In the next three sessions, two specific EMAs appear:

First moment (momentum, Adam's mtm_t):

mt=β1mt−1+(1−β1)gt,m^t=mt1−β1t.m_t = \beta_1 m_{t-1} + (1 - \beta_1) g_t, \qquad \hat m_t = \frac{m_t}{1 - \beta_1^t}.

This estimates E[gt]\mathbb{E}[g_t] — the mean gradient. Used as a velocity in momentum and Adam.

Second moment (RMSProp, Adam's vtv_t):

vt=β2vt−1+(1−β2)gt2,v^t=vt1−β2t,v_t = \beta_2 v_{t-1} + (1 - \beta_2) g_t^2, \qquad \hat v_t = \frac{v_t}{1 - \beta_2^t},

with gt2g_t^2 understood element-wise. This estimates E[gt2]\mathbb{E}[g_t^2] — the second moment of the gradient (variance + mean2^2). Used as a per-parameter scale to divide the update by v^t\sqrt{\hat v_t}.

Both follow the same EMA pattern. The bias correction is the same line of algebra in both cases.


8. Takeaways

  • An EMA vt=βvt−1+(1−β)gtv_t = \beta v_{t-1} + (1 - \beta) g_t is a weighted sum of past inputs with geometric weights (1−β)βt−k(1-\beta)\beta^{t-k}.
  • The total weight after tt steps is 1−βt1 - \beta^t. For tt small, this is well below 11 — hence the bias toward v0=0v_0 = 0.
  • The bias-corrected EMA v^t=vt/(1−βt)\hat v_t = v_t / (1 - \beta^t) is unbiased for E[g]\mathbb{E}[g] when the gtg_t's are i.i.d.
  • Effective averaging window: ≈1/(1−β)\approx 1/(1 - \beta).
  • Adam's β1=0.9\beta_1 = 0.9 averages gradients over ∼10\sim 10 steps; β2=0.999\beta_2 = 0.999 averages squared gradients over ∼1000\sim 1000 steps.

Self-test

(a) Starting from v0=0v_0 = 0 and the recurrence vt=βvt−1+(1−β)gtv_t = \beta v_{t-1} + (1 - \beta) g_t, prove the closed form vt=(1−β)∑k=1tβt−kgkv_t = (1 - \beta) \sum_{k=1}^t \beta^{t-k} g_k by induction.

(b) Show that the bias-corrected EMA v^t=vt/(1−βt)\hat v_t = v_t / (1 - \beta^t) is also expressible as a weighted average v^t=∑kw~kgk\hat v_t = \sum_k \tilde w_k g_k with w~k≥0\tilde w_k \ge 0 and ∑kw~k=1\sum_k \tilde w_k = 1.

(c) With β=0.9\beta = 0.9 and the constant sequence gt=1g_t = 1 for all tt, compute vtv_t and v^t\hat v_t for t=1,2,5,10,50t = 1, 2, 5, 10, 50. Confirm v^t=1\hat v_t = 1 for all tt (no bias) while vtv_t approaches 11 only as tt grows.

(d) A practitioner uses β=0.99\beta = 0.99 and trains for only T=50T = 50 steps. Without bias correction, by what factor is the EMA at the final step smaller than the true mean of the gradients (assuming stationary gg)?


References

  1. [1]

    Patarasuk, P., & Yuan, X. (2009). "Bandwidth optimal all-reduce algorithms for clusters of workstations". J. Parallel and Distributed Computing. sciencedirect.com — Ring all-reduce algorithm (7.8 §3.2).

    ↩