← All posts

Foundations

Post 3 of 15

Optimisers: SGD, momentum, Adam and learning-rate schedules

Posts in this series · 15

In the last post we built gradient descent: measure the slope, step against it, repeat. It works, but it has habits that make real training slow and fragile. It zigzags across narrow valleys. It crawls on flat ground. And it uses one step size for every weight, even when some weights sit on steep slopes and others on gentle ones.

The methods that fix this are called optimisers. An optimiser is just a rule for turning the gradient into a step. In this post we build the four you will meet everywhere (stochastic gradient descent, momentum, RMSProp and Adam), then add learning-rate schedules, which change the step size as training goes on.

We will keep using the same landscape as post 2, so you can see the same terrain walked better and better:

WhatValue
The bowlL=w12+4w22L = w_1^2 + 4 w_2^2
Its slopes (the gradient)(2w1,  8w2)\left(2 w_1, \; 8 w_2\right)
Starting point(4,1)(4, 1), where the loss is 20
The bottom(0,0)(0, 0), where the loss is 0

Later we will also use a long valley, L=0.1w12+4w22L = 0.1 w_1^2 + 4 w_2^2: the same narrow direction, but the gentle direction made ten times flatter.

Plain gradient descent and its three problems

Recall the rule from post 2. In one sentence: move every weight a step against its own slope, with one shared step size.

w←w−η gw \leftarrow w - \eta \, g

When gg is computed on a random mini-batch rather than all the data, this is stochastic gradient descent (SGD), and in practice people call the whole family SGD. On our toy bowls the gradient is exact, but every idea below works the same with noisy gradients.

On the bowl, with η=0.2\eta = 0.2, post 2 found the zigzag: (4,1)→(2.4,−0.6)→(1.44,0.36)→(0.864,−0.216)(4, 1) \to (2.4, -0.6) \to (1.44, 0.36) \to (0.864, -0.216). Each step multiplies w1w_1 by 1−2η=0.61 - 2\eta = 0.6 and w2w_2 by 1−8η=−0.61 - 8\eta = -0.6.

That small example already shows the three problems.

  1. Zigzag in narrow valleys. The steep direction (w2w_2) overshoots and flips sign every step, while the gentle direction (w1w_1) creeps. Raise η\eta to speed up w1w_1, and w2w_2 explodes once η\eta passes 0.25.
  2. Slow on flat ground. On the long valley the slope in w1w_1 is 0.2w10.2 w_1, tiny. With η=0.2\eta = 0.2, w1w_1 is multiplied by 1−0.04=0.961 - 0.04 = 0.96 per step: after 10 steps it has only gone from 4 to 2.66.
  3. One step size for every weight. The best η\eta for w1w_1 and the best η\eta for w2w_2 are different numbers, but plain descent must pick one, and the steepest direction always wins that argument.

Each optimiser below fixes one or more of these. Here is the race we are building towards.

Four optimisers walking the same landscape, with their loss over time
Show the arithmetic of
Landscape
Schedule
Figure 1. Four optimisers, one landscape. Press Step to move all four at once. Pick an optimiser to see its full arithmetic for that step; the chart on the right tracks all four losses. Switch to the long valley to see where the newer methods earn their keep.

Momentum: a heavy ball with a memory

The idea

Plain descent is a walker with no memory: every step looks only at the slope underfoot. Imagine instead a heavy ball rolling downhill. It builds up speed along directions where the slope keeps pointing the same way, and when the slope flips back and forth (as in the zigzag), the pushes cancel and the ball calms down.

In one sentence: keep a running velocity that adds up recent gradients, fading old ones, and step along the velocity instead of the raw gradient.

v←β v+gv \leftarrow \beta \, v + g w←w−η vw \leftarrow w - \eta \, v

Everyday picture: pushing a child on a swing, or a shopping trolley. Each push adds to the motion you already have. Pushes in the same direction pile up; pushes that alternate mostly cancel.

This is the heavy ball method of Boris Polyak (1964).

Why it adds up to “ten times”

If the gradient stays the same, say g=1g = 1, the velocity goes 11, then 0.9+1=1.90.9 + 1 = 1.9, then 1.71+1=2.711.71 + 1 = 2.71, and settles towards 1/(1−β)=1/0.1=1 / (1 - \beta) = 1 / 0.1 = 10. So on a steady slope, momentum with learning rate η\eta moves like plain descent with learning rate 10η10 \eta. That is why momentum is usually paired with a smaller learning rate. Below we use η=0.05\eta = 0.05.

(Some libraries write the velocity as an average, v←βv+(1−β)gv \leftarrow \beta v + (1 - \beta) g, which settles at gg instead of 10g10 g. Same idea, with the factor of 10 moved into η\eta. We will meet this averaging form properly in the moving average.)

Three steps by hand

Bowl L=w12+4w22L = w_1^2 + 4 w_2^2, start (4,1)(4, 1), η=0.05\eta = 0.05, β=0.9\beta = 0.9, velocity starts at (0,0)(0, 0).

Step 1.

Step 2.

Step 3.

Look at the two directions.

What would change with a smaller β\beta? At β=0\beta = 0 the velocity is just the gradient, and we are back to plain descent. At β=0.5\beta = 0.5 old pushes fade twice as fast, so the ball overshoots less but speeds up less.

Honest result: on this small, fairly round bowl, momentum at these settings is not faster than plain descent at η=0.2\eta = 0.2. After 10 steps momentum’s loss is 6.61 (it is swinging past the bottom) against plain descent’s 0.0007. Momentum’s real wins are on long, flat valleys (on the long valley it reaches 0.0020 after 60 steps against 0.0119) and, as the next figure shows, on bumpy ground.

Rolling through a small dip

The heavy ball has a second gift. Here is a 1-D loss with a small dent on the way down:

L(w)=0.1 w2−0.5 e−2(w−3)2L(w) = 0.1 \, w^2 - 0.5 \, e^{-2 (w - 3)^2}

Start at w=5w = 5 with η=0.2\eta = 0.2. The slope there is 0.2×5+2×2×e−8≈1+0.0013=0.2 \times 5 + 2 \times 2 \times e^{-8} \approx 1 + 0.0013 = 1.0013.

What would change with a smaller β\beta? At β=0.5\beta = 0.5 the ball does not build enough speed and is caught in the dip; at β=0.6\beta = 0.6 it just escapes. Momentum is not a guarantee, just a better chance, the same way the noise from mini-batches helped escape the saddle in post 2.

A curve with a small dip; a plain walker stops in the dip while a ball with momentum rolls through
Figure 2. A heavy ball rolls through a dip that traps a careful walker. Step to watch plain descent settle at 2.667 while momentum swings past the hump. Lower beta to 0.5 and the ball is caught too.

Nesterov momentum: look before you leap

A small improvement, due to Yurii Nesterov (1983) and brought into deep learning by Sutskever and colleagues (2013). In one sentence: measure the gradient not where you stand, but where the velocity is about to carry you.

v←β v+∇L ⁣(w−η β v)v \leftarrow \beta \, v + \nabla L\!\left(w - \eta \, \beta \, v\right) w←w−η vw \leftarrow w - \eta \, v

The only change is inside the gradient: w−ηβvw - \eta \beta v is a look-ahead point, roughly where the ball will be next. Everyday picture: a cyclist who looks at the road ahead rather than at the front wheel, and starts braking before the bend.

Step 1 is the same as plain momentum (velocity is 0, so the look-ahead point is where we stand): (3.6,0.6)(3.6, 0.6). Step 2:

Compare with plain momentum’s (2.88,0)(2.88, 0) and then (1.944,−0.54)(1.944, -0.54): Nesterov’s third point is (2.0704,−0.1598)(2.0704, -0.1598), overshooting w2w_2 by much less. It brakes earlier.

Moving averages and their early bias

Before the next optimisers we need one tool, used three times in Adam. It deserves its own section.

In one sentence: an exponential moving average (EMA) keeps a running summary that is mostly the old summary plus a little of the new value.

mt=β mt−1+(1−β) gtm_t = \beta \, m_{t-1} + (1 - \beta) \, g_t

Everyday picture: the “feels like” temperature of a room. Open a window for a second and the room barely changes; leave it open and it slowly follows the outside. With β=0.9\beta = 0.9, each new value gets a 10% say, and a value from 10 steps ago still has about 0.910≈35%0.9^{10} \approx 35\% of its original weight. Roughly, the average remembers the last 1/(1−β)=101 / (1 - \beta) = 10 values.

Worked example: smoothing a noisy gradient

Suppose a weight’s gradients over eight mini-batches are 4,2,6,3,5,1,4,34, 2, 6, 3, 5, 1, 4, 3. Their true average is 3.5; the jumps are mini-batch noise. With β=0.9\beta = 0.9:

Something is wrong. The gradients are around 3.5, but the average says 0.4, then 0.56, then 1.104. After 8 steps it has only reached 1.954. The average is badly biased towards zero at the start.

Where the bias comes from

The reason is the starting value m0=0m_0 = 0. Unroll the formula when every gradient equals the same number gg:

mt=(1−β)(1+β+β2+⋯+βt−1)g=(1−βt)gm_t = (1 - \beta)\left(1 + \beta + \beta^2 + \cdots + \beta^{t-1}\right) g = \left(1 - \beta^t\right) g

(The middle bracket is a geometric sum, and (1−β)(1 - \beta) times it is exactly 1−βt1 - \beta^t.) So after tt steps, the average holds only a fraction 1−βt1 - \beta^t of the true value. The rest of the weight is still sitting on the made-up 0 we started with.

With β=0.9\beta = 0.9 and a steady gradient of 8, as at the first step on our bowl: m1=0.1×8=m_1 = 0.1 \times 8 = 0.8, m2=0.19×8=m_2 = 0.19 \times 8 = 1.52, m3=0.271×8=m_3 = 0.271 \times 8 = 2.168, and even m10=0.651×8≈m_{10} = 0.651 \times 8 \approx 5.21. Ten steps in, still a third short.

The fix: divide by what is missing

In one sentence: since the average holds only 1−βt1 - \beta^t of the truth, divide by 1−βt1 - \beta^t.

m^t=mt1−βt\hat{m}_t = \frac{m_t}{1 - \beta^t}

Back to the noisy gradients:

Stepgtg_tmtm_t1−0.9t1 - 0.9^tm^t\hat{m}_tTrue mean so far
140.40.14.04.0
220.560.192.9473.0
361.1040.2714.0744.0
431.29360.34393.7623.75
831.95420.56953.4313.5

The corrected average tracks the real values from the very first step. What would change with a smaller β\beta? At β=0.5\beta = 0.5 the bias disappears faster (1−0.53=0.8751 - 0.5^3 = 0.875 by step 3) but the average jumps around more: it goes 4,2.667,4.571,3.733,4.387,2.667,…4, 2.667, 4.571, 3.733, 4.387, 2.667, \ldots, following each noisy value closely.

Noisy gradients as bars with the raw moving average, the corrected average and the true running mean
Gradients
Figure 3. A moving average, its bias, and the fix. Step through the eight gradients. The raw average (grey) starts far too low; dividing by 1 − β^t (gold) fixes it. Move β and watch the trade-off between smoothness and lag, or switch to a steady gradient of 8 to see the bias on its own.

Per-weight step sizes: AdaGrad and RMSProp

Now the third problem: one step size for every weight. The idea is to give each weight its own step size, based on how big its gradients usually are. Big gradients get a smaller step size; small gradients get a larger one.

AdaGrad

AdaGrad (adaptive gradient) by Duchi, Hazan and Singer (2011). In one sentence: keep a running total of each weight’s squared gradients, and divide the step by its square root.

G←G+g2G \leftarrow G + g^2 w←w−η gG+ϵw \leftarrow w - \eta \, \frac{g}{\sqrt{G} + \epsilon}

Everyday picture: a thermostat that has learned which radiators run hot. A weight that always gets big pushes has its pushes turned down; a weight that rarely gets pushed is turned up. This made AdaGrad popular for rare features, such as uncommon words, whose weights get few updates.

By hand on the bowl with η=0.5\eta = 0.5:

Notice step 1: both weights moved by exactly 0.5=η0.5 = \eta, whatever the size of the gradient. No zigzag at all. But notice also that GG only ever grows, so the steps shrink for ever, even on flat ground where we would like to keep going. After 50 steps, AdaGrad’s loss is still 0.062.

RMSProp

RMSProp (root mean square propagation) was proposed by Tieleman and Hinton in a 2012 online lecture, never in a paper. In one sentence: like AdaGrad, but replace the growing total with a moving average of squared gradients, so old gradients are forgotten.

s←β s+(1−β) g2s \leftarrow \beta \, s + (1 - \beta) \, g^2 w←w−η gs+ϵw \leftarrow w - \eta \, \frac{g}{\sqrt{s} + \epsilon}

Dividing gg by a typical ∣g∣\lvert g \rvert makes the step roughly η\eta in size for every weight, steep or gentle. The step’s direction still comes from the gradient’s sign and recent history.

By hand on the bowl with η=0.3\eta = 0.3, β=0.9\beta = 0.9:

Step 1. Gradient (8,8)(8, 8).

Step 2. Gradient (6.103,0.411)(6.103, 0.411).

Step 3. Gradient (4.914,0.0006)(4.914, 0.0006). s1=10.950s_1 = 10.950, s1=3.309\sqrt{s_1} = 3.309, step 0.4450.445. New point (2.011,0.0000)(2.011, 0.0000), loss 4.046.

Two things to notice.

Same path on both bowls

Here is the striking part. Run RMSProp on the long valley, L=0.1w12+4w22L = 0.1 w_1^2 + 4 w_2^2. The w1w_1 gradient is now ten times smaller: 0.80.8 instead of 88. But s1s_1 is 100100 times smaller (0.0640.064 instead of 6.46.4), so s1\sqrt{s_1} is also ten times smaller, and the ratio is unchanged: 0.3×0.8/0.253=0.9490.3 \times 0.8 / 0.253 = 0.949, the same step. RMSProp follows exactly the same path on both bowls: (3.051,0.051)(3.051, 0.051), (2.457,0.0001)(2.457, 0.0001), (2.011,0.0000)(2.011, 0.0000).

Plain descent at η=0.2\eta = 0.2 on the long valley does much worse: (3.84,−0.6)(3.84, -0.6), (3.686,0.36)(3.686, 0.36), (3.539,−0.216)(3.539, -0.216), loss 1.439 after three steps against RMSProp’s 0.405. Its w1w_1 barely moves because the slope is flat, and it cannot raise η\eta because w2w_2 would explode.

Dividing each weight’s step by its own typical gradient size cancels out how steep or flat that direction is. That is the whole point of per-weight step sizes.

Plain descent and RMSProp on a round bowl and a long valley, with each weight's effective step size
Figure 4. One step size per weight. Plain descent’s path changes completely when the valley is stretched; RMSProp’s does not. The bars show why: each weight’s effective step size grows exactly as much as its slope shrinks. The slider stretches the right-hand valley further.

The weakness shows later. Near the bottom, gradients become tiny, ss shrinks to match, and the step stays roughly η\eta in size. So RMSProp with a fixed learning rate never settles: on the bowl its loss reaches 0.0003 at step 20, then jitters back up to 0.19 at step 40. Keep that in mind for schedules.

Adam: momentum plus RMSProp, with bias correction

Adam (adaptive moment estimation), by Diederik Kingma and Jimmy Ba (2015), is the default optimiser for most of deep learning today, including the Transformers behind speech models like Pocket TTS. It is three ideas you now know, stacked:

  1. A moving average of the gradient, mm: momentum (direction, with memory).
  2. A moving average of the squared gradient, vv: RMSProp (typical size, per weight).
  3. Bias correction for both, because both start at 0.

The formulas

In one sentence: step along the remembered direction, divided by the remembered size, after correcting both for their zero start.

mt=β1 mt−1+(1−β1) gtm_t = \beta_1 \, m_{t-1} + (1 - \beta_1) \, g_t vt=β2 vt−1+(1−β2) gt2v_t = \beta_2 \, v_{t-1} + (1 - \beta_2) \, g_t^2 m^t=mt1−β1t,v^t=vt1−β2t\hat{m}_t = \frac{m_t}{1 - \beta_1^t}, \qquad \hat{v}_t = \frac{v_t}{1 - \beta_2^t} w←w−η m^tv^t+ϵw \leftarrow w - \eta \, \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon}

Everyday picture: a hiker with a compass and a stride length. The compass (m^\hat{m}) is an average of recent directions, so a single odd reading does not throw it off. The stride (η/v^\eta / \sqrt{\hat{v}}) is shortened on ground that has been rough and lengthened on ground that has been smooth.

Why bias correction matters even more here

Look at the step at t=1t = 1 without correction. With gradient g1g_1:

So the uncorrected first step is about 3.16 times bigger than η\eta. The small numerator is underestimated, but the denominator is underestimated far more, because β2\beta_2 is closer to 1. With η=0.5\eta = 0.5 and g1=8g_1 = 8: 0.5×0.8/0.064=0.5×0.8/0.253=0.5 \times 0.8 / \sqrt{0.064} = 0.5 \times 0.8 / 0.253 = 1.581 instead of 0.5. Without the correction, Adam’s first steps would be about three times bigger than the learning rate asks for, and bigger still with β2\beta_2 closer to 1. Kingma and Ba added the correction for exactly this reason.

With correction, m^1=g1\hat{m}_1 = g_1 and v^1=g12\hat{v}_1 = g_1^2, so the first step is η×g1/∣g1∣=±η\eta \times g_1 / \lvert g_1 \rvert = \pm\eta: exactly one learning rate, in the downhill direction, for every weight.

Three Adam steps by hand

Bowl L=w12+4w22L = w_1^2 + 4 w_2^2, start (4,1)(4, 1), η=0.5\eta = 0.5, β1=0.9\beta_1 = 0.9, β2=0.999\beta_2 = 0.999, m=v=(0,0)m = v = (0, 0).

Step 1 (t=1t = 1; corrections 1−0.9=0.11 - 0.9 = 0.1 and 1−0.999=0.0011 - 0.999 = 0.001).

w1w_1w2w_2
Gradient gg2×4=82 \times 4 = 88×1=88 \times 1 = 8
m=0.9×0+0.1gm = 0.9 \times 0 + 0.1 g0.80.8
v=0.999×0+0.001g2v = 0.999 \times 0 + 0.001 g^20.0640.064
m^=m/0.1\hat{m} = m / 0.188
v^=v/0.001\hat{v} = v / 0.0016464
v^\sqrt{\hat{v}}88
Step 0.5×m^/v^0.5 \times \hat{m} / \sqrt{\hat{v}}0.50.5
New weight3.50.5

Loss 12.25+1=12.25 + 1 = 13.25.

Step 2 (t=2t = 2; corrections 1−0.81=0.191 - 0.81 = 0.19 and 1−0.998001=0.0019991 - 0.998001 = 0.001999).

w1w_1w2w_2
Gradient gg2×3.5=72 \times 3.5 = 78×0.5=48 \times 0.5 = 4
m=0.9×0.8+0.1gm = 0.9 \times 0.8 + 0.1 g0.72+0.7=1.420.72 + 0.7 = 1.420.72+0.4=1.120.72 + 0.4 = 1.12
v=0.999×0.064+0.001g2v = 0.999 \times 0.064 + 0.001 g^20.063936+0.049=0.1129360.063936 + 0.049 = 0.1129360.063936+0.016=0.0799360.063936 + 0.016 = 0.079936
m^=m/0.19\hat{m} = m / 0.197.4745.895
v^=v/0.001999\hat{v} = v / 0.00199956.49639.988
v^\sqrt{\hat{v}}7.5166.324
Step 0.5×m^/v^0.5 \times \hat{m} / \sqrt{\hat{v}}0.4970.466
New weight3.0030.034

Loss 9.022.

Step 3 (t=3t = 3; corrections 0.2710.271 and 0.0029970.002997).

w1w_1w2w_2
Gradient gg6.0060.271
mm1.8791.035
vv0.148890.07993
m^\hat{m}6.9323.820
v^\hat{v}49.68026.670
v^\sqrt{\hat{v}}7.0485.164
Step0.4920.370
New weight2.511−0.336

Loss 6.757.

What to notice:

Like RMSProp, Adam’s path is the same on both bowls, since stretching a direction scales m^\hat{m} and v^\sqrt{\hat{v}} alike. On the long valley after 10 steps, Adam’s loss is 0.147 against plain descent’s 0.707. And like RMSProp, with a fixed learning rate it never quite settles: on the bowl its loss is 0.30 at step 10 but 1.17 at step 20, as it circles the bottom.

A table filling one Adam update at a time for a single weight
Bias correction
Figure 5. Adam, one weight, one operation at a time. The default follows w1 on the bowl. Turn bias correction off and the first step jumps from 0.5 to 1.581.

The race, honestly

Here are the losses in Figure 1, with the defaults (plain descent η=0.2\eta = 0.2; momentum η=0.05\eta = 0.05, β=0.9\beta = 0.9; RMSProp η=0.3\eta = 0.3, β=0.9\beta = 0.9; Adam η=0.5\eta = 0.5, β1=0.9\beta_1 = 0.9, β2=0.999\beta_2 = 0.999).

Loss after step10204060
Bowl w12+4w22w_1^2 + 4 w_2^2
Plain descent0.00070.00000.00000.0000
Momentum6.612.120.2160.025
RMSProp0.2150.00030.1880.038
Adam0.3011.1680.0380.006
Long valley 0.1w12+4w220.1 w_1^2 + 4 w_2^2
Plain descent0.7070.3130.0610.012
Momentum1.6850.2390.0310.002
RMSProp0.0220.00000.1880.038
Adam0.1470.3220.0040.001

Three honest lessons.

  1. On a small, round-ish bowl, well-tuned plain descent wins. Fancier is not always faster.
  2. Stretch the valley and the per-weight methods win easily early on, because their behaviour does not depend on how flat a direction is. In real networks, directions differ in steepness by factors far bigger than 40, and you do not know them in advance. That robustness is why Adam is the default.
  3. With a fixed learning rate, RMSProp and Adam wander near the bottom. They need the learning rate to come down. That is the job of a schedule.

AdamW and decoupled weight decay

A common trick against overfitting, covered fully in the regularisation post, is weight decay: pull every weight a little towards zero each step. With plain descent, the usual way to do it is to add a penalty λ2w2\frac{\lambda}{2} w^2 to the loss, which adds λw\lambda w to the gradient. (λ\lambda, lambda, sets the strength.)

With Adam, that goes wrong. The extra λw\lambda w is mixed into gg, so it is averaged into m^\hat{m} and then divided by v^\sqrt{\hat{v}} like everything else. Weights with big gradients get their decay shrunk; weights with small gradients get it blown up.

A tiny example. One weight, w=4w = 4, true gradient 00, λ=0.01\lambda = 0.01, η=0.5\eta = 0.5, first step.

w←w−η(m^tv^t+ϵ+λ w)w \leftarrow w - \eta \left( \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon} + \lambda \, w \right)

Here the Adam part is 00 and the decay is 0.5×0.01×4=0.5 \times 0.01 \times 4 = 0.02, exactly what the strength asked for.

This fix is AdamW, by Ilya Loshchilov and Frank Hutter (2019). The “W” stands for weight decay. AdamW is what most large models, including language and speech Transformers, are trained with today.

Learning-rate schedules

So far η\eta has been fixed. But the best step size changes during training. Early on, the weights are far from good and big steps help. Late in training, the weights are close, mini-batch noise and the wandering we saw above dominate, and small steps help. A schedule is a rule for η\eta as a function of the step number tt.

For all three examples: training lasts T=100T = 100 steps, and the peak learning rate is ηmax⁡=0.1\eta_{\max} = 0.1.

Step decay

In one sentence: hold η\eta fixed, then cut it by a factor at chosen milestones.

Example: multiply by 0.1 at steps 50 and 75. So η=0.1\eta = 0.1 for steps 0 to 49, 0.01 for steps 50 to 74, 0.001 for steps 75 to 100. Everyday picture: driving on the motorway, then the main road, then your street. Simple and still common for image models, but the sudden drops cause sudden jumps in the loss curve, and you must choose the milestones.

Cosine decay

In one sentence: glide η\eta smoothly from the peak to zero along half a cosine wave.

ηt=ηmin⁡+12(ηmax⁡−ηmin⁡)(1+cos⁡πtT)\eta_t = \eta_{\min} + \tfrac{1}{2} \left( \eta_{\max} - \eta_{\min} \right) \left( 1 + \cos \frac{\pi t}{T} \right)

Worked values with ηmax⁡=0.1\eta_{\max} = 0.1, ηmin⁡=0\eta_{\min} = 0:

It stays high for a long time, then falls steeply in the middle, then eases gently into zero. Cosine decay comes from SGDR (stochastic gradient descent with warm restarts) by Loshchilov and Hutter (2017), who also restarted the cosine several times; most people now use a single cosine.

Linear warm-up

In one sentence: start η\eta near zero and raise it in a straight line to the peak over the first few steps, then decay.

With 10 warm-up steps followed by a cosine over the remaining 90:

Why warm up? Two reasons.

  1. Large batches. Goyal and colleagues (2017) trained an image classifier with very large batches and a correspondingly large learning rate. Starting at the full rate made early training unstable; ramping up over the first 5 epochs fixed it.
  2. Adam’s early estimates are thin. In the first steps, v^\hat{v} is an average of only one or two squared gradients, so it is a shaky estimate of the typical gradient size. We saw that Adam’s first step moves every weight by a full η\eta, whatever its gradient, because m^1/v^1=±1\hat{m}_1 / \sqrt{\hat{v}_1} = \pm 1. If η\eta is already at its peak, every weight in the network takes a full-sized step on the evidence of a single mini-batch. Warm-up keeps those early steps small until the averages have seen enough data. Liu and colleagues (2020) analysed this problem in detail.

Warm-up followed by cosine decay is the most common schedule for Transformers today.

Three learning-rate schedules over 100 steps with their values at a chosen step
Figure 6. Three ways to change the step size over time. Drag the step slider; each schedule prints its learning rate and the arithmetic. Change the warm-up length and peak.

Back to the race: give RMSProp or Adam a decaying schedule in Figure 1 (turn on “Cosine decay over 60 steps”) and the wandering near the bottom fades as the step size shrinks.

Choosing a learning rate

Every optimiser above still has a learning rate, and it still matters most. How do you pick one without knowing the landscape?

Try a range

The simplest honest method: try several values spread over orders of magnitude, run each briefly, and compare. On the 1-D bowl from post 2, L=(w−3)2L = (w - 3)^2 from w=0w = 0, each step multiplies the distance by 1−2η1 - 2\eta, so after 5 steps the loss is 9×(1−2η)109 \times (1 - 2\eta)^{10}:

η\eta0.0010.010.030.10.30.50.91.01.1
Loss after 5 steps8.827.354.850.9660.000900.9669.055.7

The picture you get is always the same shape: a long flat stretch where nothing happens (too small), a dip where learning is fast, then a sharp rise (too big). The best value sits in the dip, a little below the cliff edge.

The learning-rate range test

Leslie Smith (2017) made this cheap. In one sentence: run one short training run in which the learning rate starts tiny and increases every mini-batch, and record the loss as you go. Plot loss against learning rate. Smith plotted accuracy against the learning rate: where accuracy starts rising, the rate is large enough to learn; where it stops rising or turns ragged, it is too large, and the good range lies between. Most people now read the loss curve the same way, picking a rate somewhat below the point where the loss is lowest.

It costs one short run instead of many, and it works with any optimiser.

Loss after a few steps against the learning rate, from too small through just right to too big
Figure 7. Too small, just right, too big, in one sweep. The steps visit eight learning rates; slide η yourself to try any other. The curve shows the loss after five steps and the inset shows the path. The dip is where you want to be; the cliff starts at 1.

What to remember

Try it yourself

Sources