Quant Memo
Core

Stochastic Weight Averaging and EMA Weights

The last set of weights SGD produces is often a noisy, lucky snapshot; averaging the weights from several points along training instead tends to land in a flatter, more reliable region of the loss surface.

Prerequisites: Stochastic Gradient Descent, The Loss Landscape: Flat vs Sharp Minima

Training a neural network with stochastic gradient descent doesn't settle onto one clean minimum — it bounces around near the bottom of the loss surface for the rest of training, buffeted by the noise of different random mini-batches every step. Whichever point it happens to be at when you stop becomes "the model," even though that point is essentially a single noisy sample from a cloud of similarly-good weight settings the optimizer visited. A different random seed, or stopping one epoch earlier, would hand you a noticeably different final model. SWA and EMA both address this the same way: instead of trusting the last snapshot, average several snapshots together.

The analogy: averaging noisy GPS readings

A phone's GPS reading jitters around your true location moment to moment due to signal noise. Trust only the very last reading before your phone died, and you'd have a noisy estimate. But log readings for a minute and average them, and the jitter mostly cancels, leaving an estimate closer to your true position than any single reading. SWA and EMA do this to a network's weights: average several points visited near the end of training instead of trusting the one, individually-noisy point SGD happened to land on.

Two ways to average, same underlying idea

Stochastic Weight Averaging runs training normally for most of the schedule, then — typically once the learning rate has been lowered and the optimizer is circling a good region rather than making large jumps — starts a separate running average of the weights, updated at fixed intervals (say, once per epoch):

wˉwˉn+wcurrentn+1\bar{w} \leftarrow \frac{\bar{w} \cdot n + w_{\text{current}}}{n + 1}

In words: the new average is the old average, weighted by how many snapshots contributed to it so far, blended with the current weights, giving every collected snapshot equal say.

EMA weights instead keep a running average updated at every step with a decay factor β\beta close to 1 (e.g., 0.9990.999):

wˉβwˉ+(1β)wcurrent\bar{w} \leftarrow \beta\, \bar{w} + (1-\beta)\, w_{\text{current}}

In words: the average leans heavily on its own past value and only slightly toward the freshest weights, changing slowly and smoothly, giving recent snapshots more weight than distant ones (unlike SWA's flat average). Both produce a weight vector no single SGD step ever visited, but which tends to sit in a flatter region of the loss surface — and flatter regions are empirically associated with better generalization, because small mismatches between training and live data move you less far up the loss surface than a sharp, narrow minimum would.

Gradient descent
parameter →
position -0.623loss -0.141gradient -0.930converging

Drag the settings above and watch SGD-style steps overshoot and oscillate near a minimum rather than settling exactly on it — that oscillation is exactly the noise SWA and EMA are built to average away.

sharp flat averaged weight
Individual noisy SGD snapshots can land in a sharp minimum; averaging several tends to land in the wider, flatter basin nearby.

Worked example 1: EMA by hand over four steps

Suppose a single weight takes the noisy values 2.0,2.4,1.8,2.22.0, 2.4, 1.8, 2.2 over four steps, tracked with β=0.5\beta = 0.5 (exaggerated for a hand-computable example), starting the average at the first value:

wˉ1=2.0,wˉ2=0.5(2.0)+0.5(2.4)=2.2,wˉ3=0.5(2.2)+0.5(1.8)=2.0,wˉ4=0.5(2.0)+0.5(2.2)=2.1\bar w_1 = 2.0,\quad \bar w_2 = 0.5(2.0)+0.5(2.4)=2.2,\quad \bar w_3 = 0.5(2.2)+0.5(1.8)=2.0,\quad \bar w_4 = 0.5(2.0)+0.5(2.2)=2.1

The raw values swing from 1.8 to 2.4 (a range of 0.6); the EMA only swings from 2.0 to 2.2 (a range of 0.2) — visibly smoother, and closer to the values' true center of roughly 2.1.

Worked example 2: SWA's flat average versus the last snapshot

Suppose the last five epochs produced weight snapshots (simplified to one number) of 3.1,2.9,3.3,2.8,3.03.1, 2.9, 3.3, 2.8, 3.0. The final snapshot alone is 3.03.0. The SWA average is (3.1+2.9+3.3+2.8+3.0)/5=3.02(3.1+2.9+3.3+2.8+3.0)/5 = 3.02 — close in this case. But if the final snapshot had instead been an unlucky outlier, say 2.52.5, from a mini-batch that pushed weights the wrong way right before stopping, trusting it alone would give a noticeably worse model than the 3.023.02 average, since the average dilutes any one unlucky step across all five.

SWA and EMA both trade a single, individually noisy snapshot of the weights for an average of several snapshots visited during training, landing in a flatter region of the loss surface that tends to generalize better than any one point along the way.

What this means in practice

SWA is typically combined with a cyclical or constant learning rate near the end of training, so the averaged snapshots are meaningfully different points circling one basin, not points still descending; EMA needs no separate phase — it runs alongside normal training the whole time, and the EMA copy is what gets deployed. Both add negligible compute cost: an extra weight buffer and a cheap update, no extra forward or backward passes.

Practice

  1. With EMA decay β=0.9\beta = 0.9 and raw values 10,12,810, 12, 8 (starting the average at 1010), compute wˉ\bar w after each step.
  2. Why does SWA typically wait until late in training, after the learning rate has been lowered, to start averaging?
  3. In your own words, explain why a flatter region of the loss surface should be more robust to the mismatch between training data and live data than a sharp, narrow minimum.

The common confusion is assuming averaged weights can just be swapped in with no further changes. For architectures with batch normalization, the averaged weights are a different point in weight space than any single snapshot, so the batch-norm running statistics must be recomputed with a forward pass over some training data using the new weights — skipping this is a frequent, quietly-damaging bug that leaves the averaged model performing worse than either the naive last snapshot or a properly recalibrated SWA model.

Related concepts

Practice in interviews

Further reading

  • Izmailov, Podoprikhin, Garipov, Vetrov & Wilson, Averaging Weights Leads to Wider Optima and Better Generalization (2018)
ShareTwitterLinkedIn