Learning-Rate Schedules

Imagine training a deep network with a single fixed learning rate for a hundred epochs. If the rate is too large, the loss oscillates wildly or diverges. This happens once the network reaches a narrow ravine in the loss surface. If it is too small, training crawls. This wastes compute and GPU-hours before ever reaching a good minimum. The uncomfortable truth is that no single constant learning rate is optimal across the whole training run. The ideal step size early in training is very different from the ideal step size late in training. Early on, weights are far from any minimum. Late in training, the model is fine-tuning inside a narrow basin. Learning-rate schedules resolve this tension. They treat the learning rate not as a fixed hyperparameter but as a function of time. This is a plan that changes the step size as training proceeds. This idea is one of the most consequential and cheap tricks in deep learning. Changing a single scalar's trajectory over training routinely improves final accuracy. It also shortens training time and stabilizes optimization. All this happens without touching the model architecture or the loss function. Nearly every state-of-the-art result in vision, language modeling, and speech uses some nontrivial schedule. This is often combined with a warmup phase and momentum. The big picture is that a learning-rate schedule sits at the interface between optimization theory and practical engineering. Optimization theory tells us that for convex problems, decaying learning rates are necessary for provable convergence. This applies to a stationary point when using noisy stochastic gradients. An example is a rate proportional to 1/t1/t. Practice tells us that deep, non-convex loss landscapes have extra quirks. These include sharp regions early in training, plateaus, and sensitivity to the initial few iterations. These quirks motivate warmup and cyclical decay patterns. Theory alone would not predict such patterns. This article builds the schedule toolbox from first principles. It covers step decay, exponential decay, cosine annealing, and warmup. It explains precisely how each is computed, why it helps, and where it can go wrong. It assumes familiarity with Gradient Descent for Deep Learning and its use of momentum. It also sets up later material on Hyperparameter Tuning and Debugging the Training Process. In that material, schedule choice becomes one of the first things to inspect when a model underperforms.

Key takeaways
  • A learning-rate schedule is a function η(t)\eta(t) that changes the step size over training instead of holding it constant.
  • Step decay drops η\eta by a fixed factor at pre-set milestones; simple, but introduces sudden loss jumps.
  • Exponential decay shrinks η\eta smoothly and continuously, giving predictable but sometimes overly aggressive decay.
  • Cosine annealing follows a smooth cosine curve to zero (or a floor), widely used in modern vision/NLP training.
  • Warmup linearly ramps η\eta up from near zero at the start, preventing early instability from large gradients.
  • Schedules interact with momentum and batch size, and picking one well is a core skill covered further in Hyperparameter Tuning.
The core insight

The learning rate should be large when the model is far from a good solution and small when it is close, and a schedule is simply an explicit, pre-planned function that implements this idea over training time.

The idea

A learning-rate schedule is a deterministic function η:N→R>0\eta: \mathbb{N} \to \mathbb{R}_{>0} mapping the current training step (or epoch) tt to a learning rate η(t)\eta(t), used in the update rule

θt+1=θt−η(t) gt,\theta_{t+1} = \theta_t - \eta(t)\, g_t,

where gtg_t is the (possibly momentum-adjusted) gradient estimate at step tt. The schedule is fixed before training starts — it does not adapt to the observed loss (that would be an adaptive method like ReduceLROnPlateau, a related but distinct idea) — although some schedules are parameterized by quantities like total number of steps TT, which must be known or estimated in advance. The reason a schedule helps is rooted in the shape of the loss landscape and the statistics of stochastic gradients. Early in training, the model is typically far from any minimum, gradients tend to be large and informative, and a larger step size lets the model make rapid progress across broad, low-curvature regions. Late in training, the model is near a minimum (or a flat basin containing one), the loss surface is locally more like a bowl with possibly high curvature in some directions, and stochastic gradient noise (from mini-batching) has variance that does not shrink as training proceeds. A large learning rate at this stage causes the parameters to bounce around the bottom of the bowl instead of settling into it — the update variance, roughly η2 Var(gt)\eta^2 \,\mathrm{Var}(g_t), must shrink for the iterate to converge rather than oscillate around a noise floor. Formally, in stochastic approximation theory (Robbins–Monro conditions), a decaying schedule satisfying

∑t=1∞η(t)=∞and∑t=1∞η(t)2<∞\sum_{t=1}^{\infty} \eta(t) = \infty \qquad \text{and} \qquad \sum_{t=1}^{\infty} \eta(t)^2 < \infty

is sufficient (together with standard smoothness and noise assumptions) for SGD iterates to converge almost surely to a stationary point of the objective. The first condition ensures the schedule does not decay so fast that the algorithm cannot travel arbitrarily far (it must be able to escape a bad starting point and reach any region of the space). The second ensures the accumulated noise injected by stochastic gradients is summable, so the random fluctuations eventually die out and the sequence stabilizes. A constant learning rate satisfies neither condition properly: it can travel infinitely far (∑η=∞\sum \eta = \infty, fine) but the noise term ∑η2\sum \eta^2 diverges too, meaning the iterate never truly settles — it converges only to a noise ball around the minimum whose radius is proportional to η\eta. Schedules like 1/t1/t decay or step decay satisfy both conditions and hence give a much stronger convergence guarantee, at the cost of needing to travel less late in training. Deep learning practice departs from this classical picture in three important ways, motivating the specific schedules covered here. First, training runs for a finite, known horizon TT, so schedules can be shaped to hit a target minimum learning rate exactly at TT (as cosine annealing does) rather than decaying forever. Second, the very first few hundred to thousand iterations are often the most fragile part of training — activations and gradient scales have not yet equilibrated, and a full-sized learning rate can cause instability or even divergence — motivating warmup, a short initial phase where η(t)\eta(t) ramps up rather than down. Third, non-convexity means the "right" trajectory of η(t)\eta(t) is partly empirical: cosine schedules, for instance, were popularized less by a convergence proof and more by consistently strong empirical results across architectures.

How it works

We now specify each schedule precisely as a function of the training step tt (or epoch ee), assuming a base learning rate η0\eta_0 and, where relevant, a total training horizon TT.

Step decay multiplies η\eta by a fixed factor γ∈(0,1)\gamma \in (0,1) (commonly 0.10.1 or 0.50.5) every time training crosses one of a fixed set of milestone epochs {m1,m2,… }\{m_1, m_2, \dots\}:

η(e)=η0⋅γ k(e),k(e)=#{ i:mi≤e }.\eta(e) = \eta_0 \cdot \gamma^{\,k(e)}, \qquad k(e) = \#\{\, i : m_i \le e \,\}.

So η\eta is a piecewise-constant staircase: full rate until m1m_1, then η0γ\eta_0\gamma until m2m_2, then η0γ2\eta_0\gamma^2, and so on.

Exponential decay shrinks the learning rate smoothly and continuously at every step, governed by a decay rate k>0k>0:

η(t)=η0⋅e−kt,or equivalently η(t)=η0⋅γt/s\eta(t) = \eta_0 \cdot e^{-k t}, \qquad \text{or equivalently } \eta(t) = \eta_0 \cdot \gamma^{t/s}

for a decay factor γ\gamma applied every ss steps. Unlike step decay, there are no discontinuities — the rate glides down monotonically at every single update.

Cosine annealing follows one half-period of a cosine curve from η0\eta_0 down to a floor ηmin⁡\eta_{\min} (often 00) over the horizon TT:

η(t)=ηmin⁡+12(η0−ηmin⁡)(1+cos⁡(tTπ)),t∈[0,T].\eta(t) = \eta_{\min} + \tfrac{1}{2}(\eta_0 - \eta_{\min})\Big(1 + \cos\big(\tfrac{t}{T}\pi\big)\Big), \qquad t \in [0, T].

At t=0t=0 this gives η(0)=η0\eta(0)=\eta_0; at t=Tt=T it gives η(T)=ηmin⁡\eta(T)=\eta_{\min}. The curve decays slowly at first, drops fastest through the middle of training, and flattens out again as it approaches ηmin⁡\eta_{\min} — an S-shaped decay that spends more time near both the top and the bottom than a linear ramp would. A common variant, cosine with warm restarts (SGDR), resets tt to 00 periodically, creating a sawtooth of cosine cycles used to encourage the optimizer to explore multiple basins and produce ensembles of snapshots.

Warmup is not a full schedule on its own but a short prefix, typically the first TwT_w steps, during which η\eta ramps linearly (or sometimes with a low-order polynomial) from a small value (often 00) up to η0\eta_0:

η(t)=η0⋅tTw,t≤Tw.\eta(t) = \eta_0 \cdot \frac{t}{T_w}, \qquad t \le T_w.

After t=Twt = T_w, control passes to a main schedule (step, exponential, or cosine) that takes over with η0\eta_0 as its own starting value. Warmup is essential for very deep networks, large batch sizes, and Transformer architectures, where the raw gradient signal at initialization can be poorly scaled and a full-size step causes the loss to spike or the optimizer's momentum/adaptive-moment estimates (as in Adam) to lock onto a bad early direction. ```

# Generic training loop with a pluggable learning-rate schedule.

# schedule(t) returns eta_t given the current global step t. function TRAIN(model, data, T, schedule, momentum_beta): velocity = zeros_like(model.parameters) t = 0 for epoch in 1..num_epochs: for batch in data: g = compute_gradient(model, batch) # stochastic gradient estimate eta_t = schedule(t) # <-- the only thing that changes velocity = momentum_beta velocity + g model.parameters -= eta_t velocity t = t + 1 return model.parameters

# --- Schedule implementations --- function STEP_DECAY(t, eta0, gamma, milestones): k = count(m in milestones such that m <= t) return eta0 gamma^k function EXPONENTIAL_DECAY(t, eta0, gamma, step_size): return eta0 gamma^(t / step_size) function COSINE_ANNEALING(t, eta0, eta_min, T): t_clamped = min(t, T) # hold at eta_min after t = T cos_term = cos(pi t_clamped / T) return eta_min + 0.5 (eta0 - eta_min) (1 + cos_term) function WARMUP_THEN(t, T_warmup, eta0, main_schedule): if t < T_warmup: return eta0 (t + 1) / T_warmup # linear ramp, avoids eta=0 at t=0 else: return main_schedule(t - T_warmup) # main schedule restarts its clock at 0 ``` Each `schedule(t)` function is a pure function of the step counter, queried once per update; it adds negligible overhead (O(1)O(1) time, no extra memory) compared to the gradient computation itself.

Figure
Four learning-rate schedules over a training run of length T, with an optional warmup prefix
training step t learning rate η(t) step decay exponential decay cosine annealing warmup η₀ η_min T_warmup T

Complexity & correctness

Time and space complexity. Every schedule discussed is O(1)O(1) time and O(1)O(1) extra space per step: computing η(t)\eta(t) requires a handful of arithmetic operations (a power, an exponential, or a cosine evaluation) independent of model size, dwarfed by the O(number of parameters)O(\text{number of parameters}) cost of the gradient step itself. Storing the schedule requires only a few scalars (η0\eta_0, γ\gamma, milestones, or TT), not per-parameter state — this is in contrast to adaptive optimizers like Adam, which maintain O(parameters)O(\text{parameters}) auxiliary state. Consequently, a schedule is essentially "free": it changes what number multiplies the gradient, not the cost of computing that gradient. The only indirect cost is that a poorly chosen schedule can lengthen the number of steps needed to converge, which is a statistical/optimization cost, not a computational one per step.

Correctness argument for decaying schedules. Consider SGD on a smooth, possibly non-convex objective ff with LL-Lipschitz-continuous gradient, using unbiased stochastic gradients gtg_t with bounded variance Var(gt)≤σ2\mathrm{Var}(g_t) \le \sigma^2. A standard descent-lemma argument gives, for one step with learning rate ηt\eta_t,

E[f(θt+1)]≤f(θt)−ηt(1−Lηt2)∥∇f(θt)∥2+Lηt22σ2.\mathbb{E}[f(\theta_{t+1})] \le f(\theta_t) - \eta_t\big(1 - \tfrac{L\eta_t}{2}\big)\|\nabla f(\theta_t)\|^2 + \tfrac{L\eta_t^2}{2}\sigma^2.

Summing over t=1,…,Tt=1,\dots,T and rearranging, the average squared gradient norm is bounded by a telescoping term (which is finite because ff is bounded below) plus a noise term proportional to ∑tηt2\sum_t \eta_t^2. For the right-hand side to vanish as T→∞T \to \infty, we need ∑tηt→∞\sum_t \eta_t \to \infty (so the useful first term's denominator grows, letting us divide it out and still get a shrinking bound) while ∑tηt2<∞\sum_t \eta_t^2 < \infty (so the accumulated noise stays bounded). This is exactly the Robbins–Monro condition stated earlier. Step decay, exponential decay (over a finite horizon, effectively), and cosine annealing (whose learning rate integrates to a finite but large value and whose squared values are summable since it is bounded and eventually near zero) all satisfy versions of this condition in the finite-horizon setting used in practice, giving a principled reason they outperform a constant rate on the same total noise budget.

Why warmup does not break this. Warmup only affects a short prefix of O(Tw)O(T_w) steps out of a much longer horizon TT; since Tw≪TT_w \ll T in practice, its contribution to ∑ηt\sum \eta_t and ∑ηt2\sum \eta_t^2 is negligible, and it does not change the asymptotic convergence argument. Its benefit is a separate, more practical one: at initialization, the loss landscape's local curvature and gradient scale are poorly conditioned (weights have not adapted to the data distribution), and using the full η0\eta_0 immediately can cause an update large enough to move parameters into a region where gradients blow up (particularly acute for deep networks, large batch sizes, or Transformer layer-normalization interactions). Ramping η\eta up avoids taking a large step until the local geometry has stabilized somewhat, after which the full learning rate is safe.

Honest tradeoffs.

  • Step decay is simple and interpretable but the milestone epochs are extra hyperparameters that must be tuned per dataset/architecture; a badly placed milestone wastes epochs at a rate that is already too small, or drops too late and never lets the model settle.
  • Exponential decay has just one decay-rate hyperparameter but can decay the rate to near-zero well before training ends if kk is even slightly too aggressive, effectively freezing learning early.
  • Cosine annealing needs the total horizon TT known in advance; extending training (e.g., resuming with more epochs later) requires recomputing the schedule, unlike step or exponential decay which naturally continue.
  • Warmup adds one more hyperparameter (TwT_w) and, for very short training runs, can consume a nontrivial fraction of the whole budget in what is initially near-zero learning rate.

Worked example

Consider training a network with base learning rate η0=0.1\eta_0 = 0.1, total horizon T=100T = 100 epochs, warmup length Tw=5T_w = 5 epochs, and each schedule's own decay parameters, tracked epoch by epoch.

Epoch eeStep decay (γ=0.1\gamma{=}0.1, milestones {30,60,90}\{30,60,90\})Exponential (γ=0.96\gamma{=}0.96/epoch)Cosine (ηmin⁡=0\eta_{\min}{=}0)Warmup + Cosine
00.10000.10000.10000.0200
10.10000.09600.09980.0400
50.10000.07830.9755·0.1 = 0.09510.1000 (warmup ends)
290.10000.02940.57140.5626 (cosine restarts clock at e=5)
300.01000.02830.55560.5460
590.01000.00880.02450.0206
600.00100.00850.02190.0182
890.00100.00260.00010.00005
990.00010.0018≈0.0000≈0.0000

Reading this table: step decay stays completely flat at 0.10.1 until epoch 3030, then instantaneously drops to 0.010.01 — a 10×10\times shock that typically causes a visible bump in training loss curves (the model was still making large steps and suddenly its exploration radius shrinks). Exponential decay is already down to about 0.0780.078 by epoch 55 and continues shrinking every single epoch without any jump, reaching 0.00180.0018 (below step decay's final value) by epoch 9999 — for this γ\gamma, it decays faster in the long run than the 33-stage step schedule with γ=0.1\gamma=0.1. Cosine annealing starts identically to the others at η0\eta_0, decays slowly for the first fifth of training, drops through its steepest region in the middle third, and flattens smoothly to nearly zero by epoch 9999, with no discontinuities anywhere. The warmup+cosine column shows the ramp from 0.020.02 at epoch 00 to the full 0.10.1 at epoch 55 (note η(0)\eta(0) is not exactly zero — using (t+1)/Tw(t{+}1)/T_w avoids a literal zero-rate first step which would produce no update at all — a common off-by-one detail), after which cosine annealing takes over with its clock reset to zero at that point, following the same S-shape but over the remaining 9595 epochs. A second, smaller trace makes the discontinuity of step decay concrete on a per-batch loss curve. Suppose at epoch 2929, just before the first milestone, the running loss is 0.420.42 and decreasing steadily by about 0.0010.001 per epoch. At epoch 3030, the learning rate drops 10×10\times; empirically the loss often increases slightly for one or two epochs (say to 0.440.44) because the optimizer's momentum buffer, built for the old step size, briefly overshoots relative to the new tiny step size before re-equilibrating, then resumes a steeper, more stable decrease than before the drop (because a smaller step size lets it settle into finer local structure). This transient bump-then-improve pattern is the classic visual signature of a step-decay milestone in a training log, and recognizing it is a key diagnostic skill developed further in Debugging the Training Process.

Common pitfalls & traps

PitfallWhy it happensFix
Setting cosine's TT to the wrong total step countConfusing epochs with mini-batch steps, or forgetting gradient accumulation multiplies effective stepsCompute TT as `steps_per_epoch × num_epochs`, verified against the actual training loop's step counter
No warmup with a large batch size or Transformer architectureAssuming any schedule works the same regardless of batch size or model depthAdd a short linear warmup (hundreds to a few thousand steps) whenever batch size or depth is large
Step-decay milestones tuned once and reused on a new datasetMilestones are dataset/architecture-specific; blindly copying them mis-times the dropsRe-tune milestones (or switch to cosine, which needs only the horizon TT) per new setup
Forgetting the schedule resumes from step 00 on checkpoint restartRestarting training re-initializes the step counter instead of continuing itPersist and restore the global step counter alongside model weights
Exponential decay rate too aggressiveA γ\gamma tuned per-step accidentally applied per-epoch (or vice versa), causing η\eta to vanish almost immediatelyAlways state and check the unit of decay (per-step vs per-epoch) explicitly
Combining warmup with cosine but double-counting the warmup steps in TTOff-by-one: including or excluding TwT_w inconsistently when computing the cosine phase lengthExplicitly define the cosine phase as T−TwT - T_w steps, with its own clock starting at 00 right after warmup

Pioneers & history

The theoretical foundation for decaying step sizes predates deep learning by decades, rooted in stochastic approximation theory developed for sequential statistical estimation.

Origins · 1 minHerbert Robbins and how this was discovered
HR
Herbert Robbins
1915–2001 · American mathematician and statistician who, with Sutton Monro, established in 1951 the stochastic approximation framework and the step-size conditions still cited today whenever a learning-rate schedule is justified theoretically

History
1951
— Robbins and Monro publish the stochastic approximation method, introducing decaying step-size conditions for convergence.
1986
— Backpropagation popularized, with practitioners already hand-tuning learning rates and simple decay heuristics during training.
2012
— AlexNet-era ImageNet training popularizes step-decay schedules with manually chosen epoch milestones.
2016
— SGDR (cosine annealing with warm restarts) is introduced, popularizing smooth cosine decay and periodic restarts.
2017
— Transformer training recipes formalize learning-rate warmup combined with subsequent decay, now standard for large-scale models.

Where this matters

Learning-rate schedules are embedded in essentially every major deep learning framework and training recipe used in industry and research. Computer vision training pipelines (ResNet, EfficientNet, and successors) historically relied on step decay with milestones tied to a fixed epoch budget, while more recent vision and self-supervised recipes default to cosine annealing, often with a linear warmup of a few epochs. Large language model training — GPT-style and encoder-only Transformer pretraining alike — universally uses a warmup phase (typically thousands of steps) followed by either linear or cosine decay to a small floor value, a recipe now considered essential rather than optional for stable large-batch, large-model training. Reinforcement learning and speech recognition pipelines frequently borrow the same cosine-with-warmup recipe, and hyperparameter-search tools (as covered in Hyperparameter Tuning) often treat the schedule family and its parameters — not just a single learning rate — as part of the search space. Cloud training frameworks (e.g., learning-rate scheduler modules in major deep learning libraries) implement all four schedules described here as first-class, composable objects, reflecting how central this simple idea has become to reliably training deep networks at scale.

Ask the tutor: How would you design a learning-rate schedule for a training run whose total number of steps isn't known in advance?

Why not just tune a single constant learning rate really carefully instead of using a schedule?

A carefully tuned constant learning rate can only be a compromise between the needs of early and late training. If it is small enough to avoid oscillation once near a minimum, it will be too small to make fast progress early on, wasting compute. If it is large enough for fast early progress, it will keep injecting noise-proportional-to-η2\eta^2 near the minimum, forcing the iterate to hover in a "noise ball" rather than settling, which the Robbins–Monro analysis makes precise. A schedule decouples these two needs by allowing large steps early and small steps late, typically reaching a better final loss in the same or fewer total steps than any single constant rate could achieve.

How do I choose between step decay, exponential decay, and cosine annealing in practice?

Step decay is a reasonable default when you have strong prior knowledge of the right epochs to decay at, from prior experiments on a similar model/dataset, and want interpretable, easily-explained schedules for a report or comparison. Exponential decay is convenient when you want smoothness with a single hyperparameter and do not know the total training horizon in advance. Cosine annealing is the most common modern default because it needs only the total horizon TT, decays smoothly with no jumps, and has been empirically validated across many architectures and tasks; when in doubt, cosine with a short warmup is a strong starting point.

Does warmup need to be linear, or can it use other shapes?

Linear warmup, ramping from near zero to η0\eta_0 over TwT_w steps, is the most common choice because it is simple and works well in practice. Some recipes use other monotonically increasing shapes, such as a low-order polynomial or an exponential ramp, but the empirical difference from linear warmup is usually small as long as the warmup duration TwT_w is chosen well. What matters most is that the ramp is smooth and gradual (avoiding a large immediate jump) and that TwT_w is long enough for the model's activation and gradient statistics to stabilize before the full learning rate is applied.

How does a learning-rate schedule interact with momentum or Nesterov acceleration?

Momentum accumulates a running velocity from past gradients, effectively amplifying the influence of the current learning rate over several subsequent steps rather than just one. When η\eta changes abruptly (as in step decay), the velocity buffer, calibrated to the old step size, briefly produces update magnitudes inconsistent with the new learning rate, which is why step-decay milestones sometimes show a small transient bump in the loss curve before improvement resumes. Smooth schedules like cosine or exponential decay avoid this mismatch because the learning rate at each step is close to the learning rate at the previous step, keeping the momentum buffer roughly consistent with the current step size throughout training.

Can a schedule ever hurt training compared to a well-chosen constant rate?

Yes. If the schedule decays too fast relative to the amount of progress the model still needs to make, it effectively freezes learning prematurely, leaving the model undertrained even though the loss curve looks "converged" simply because the steps became too small to move the parameters meaningfully. This is common with an overly aggressive exponential decay rate or step-decay milestones placed too early. Conversely, a schedule that decays too slowly behaves almost like a constant rate and forfeits the fine-tuning benefit near the minimum. Schedule hyperparameters therefore still require tuning, which is why schedule choice is itself a subject of Hyperparameter Tuning.

Is a learning-rate schedule the same thing as an adaptive optimizer like Adam?

No, though they are complementary. A schedule is a pre-planned function η(t)\eta(t) fixed before training begins and applied uniformly to all parameters. An adaptive optimizer like Adam or RMSProp instead adjusts an effective per-parameter step size on the fly, based on running statistics of each parameter's own gradient history, without knowing the future training horizon. In practice, Adam is very commonly combined with an external schedule (often warmup plus cosine or linear decay) applied on top of its base learning rate, so the two mechanisms operate at once rather than being alternatives to each other.

Why does cosine annealing need to know the total number of training steps in advance, and what happens if I train longer than planned?

Cosine annealing is defined as one half-period of a cosine curve stretched exactly across [0,T][0, T], so it is constructed to hit ηmin⁡\eta_{\min} precisely at the last planned step; this requires TT as an input parameter. If you decide to train longer than the originally planned TT, the naive schedule will have already reached ηmin⁡\eta_{\min} (often near zero) and stay there, effectively halting learning for any extra steps. The usual fixes are to either recompute the schedule with a new, larger TT from the start of a fresh run, or use warm restarts (SGDR), which periodically resets the cosine cycle so training can be extended in discrete chunks without redefining a single fixed horizon.

Before this

Where this leads