★ FOUR BRAND-NEW COURSES ANNOUNCED! ★ Machine Learning End To End  •  Hands-On Deep Learning with Python  •  Generative AI & LLMs with Python  •  AI Agents and Agentic AI with Python  ★  Open the “Educational” menu above to explore them ★  ★  NEW! 5. JOB ASSISTANCE: JD Report • Resume customization • AI Mock Interviews — FREE with course bundles, or just ₹499 / US$5. Single Payment. No Subscription. ★★ FOUR BRAND-NEW COURSES ANNOUNCED! ★ Machine Learning End To End  •  Hands-On Deep Learning with Python  •  Generative AI & LLMs with Python  •  AI Agents and Agentic AI with Python  ★  Open the “Educational” menu above to explore them ★  ★  NEW! 5. JOB ASSISTANCE: JD Report • Resume customization • AI Mock Interviews — FREE with course bundles, or just ₹499 / US$5. Single Payment. No Subscription. ★★ FOUR BRAND-NEW COURSES ANNOUNCED! ★ Machine Learning End To End  •  Hands-On Deep Learning with Python  •  Generative AI & LLMs with Python  •  AI Agents and Agentic AI with Python  ★  Open the “Educational” menu above to explore them ★  ★  NEW! 5. JOB ASSISTANCE: JD Report • Resume customization • AI Mock Interviews — FREE with course bundles, or just ₹499 / US$5. Single Payment. No Subscription. ★★ FOUR BRAND-NEW COURSES ANNOUNCED! ★ Machine Learning End To End  •  Hands-On Deep Learning with Python  •  Generative AI & LLMs with Python  •  AI Agents and Agentic AI with Python  ★  Open the “Educational” menu above to explore them ★  ★  NEW! 5. JOB ASSISTANCE: JD Report • Resume customization • AI Mock Interviews — FREE with course bundles, or just ₹499 / US$5. Single Payment. No Subscription. ★

Warmup then cosine: the learning-rate shape of big training runs

Warmup then cosine: the learning-rate shape of big training runs
23-10-2026  |  By Tejas Desai, Ecube Analytics  |  Generative AI: Build a Small GPT From Scratch (Chapter 3)  |  3 min read
READ 3RD OF 8 IN THIS SERIES

Warmup then cosine: the learning-rate shape of big training runs

Build a Small GPT From Scratch · Part 3 of 8

Almost every large training run starts the learning rate near zero, climbs to a peak, then slowly brings it back down. Here is what that shape looks like with real numbers, and why it exists.

Warmup

At the very start the weights are random and the optimizer has no reliable estimate of the typical size of a gradient. Adam, the usual optimizer, keeps running averages of gradients and of their squares; early on those averages are based on very little data. A full-size step taken on such estimates can throw a deep transformer into a bad region from which it never recovers. So the learning rate warms up: it rises linearly from zero to the peak over a short stretch, often one to two per cent of the run.

Cosine decay

After the peak, the rate follows half a cosine wave down to a small floor. Large steps early move quickly through the loss landscape; small steps late let the weights settle instead of bouncing around the bottom. The formula is

lr = final + (peak − final) × (1 + cos(π × progress)) / 2

where progress goes from 0 to 1 between the end of warmup and the end of the schedule.

Warmup then cosine scheduleA learning rate that climbs linearly for 5 steps to 0.3, then follows a cosine down to 0.01 at step 20 and stays there.Learning rate by update step: warmup, cosine decay, floor052025update step0.3000.01warmupcosine decayfloorPeak 0.3, 5 warmup steps, decay to 0.01 by step 20 (the toy numbers used in the course; real runs use thousands of steps).
A schedule computed from the formula: peak 0.3, warmup over 5 steps, decay to 0.01 at step 20, then flat.

The schedule as code

import math

def lr_at(step, warmup=5, total=20, peak=0.3, floor=0.01):
    if step < warmup:                                   # linear warmup from 0 to the peak
        return peak * step / warmup
    if step < total:                                    # cosine decay from the peak to the floor
        progress = (step - warmup) / (total - warmup)
        return floor + (peak - floor) * (1 + math.cos(math.pi * progress)) / 2
    return floor                                        # hold at the floor afterwards

print([round(lr_at(s), 3) for s in range(0, 22)])
# [0.0, 0.06, 0.12, 0.18, 0.24, 0.3, 0.297, 0.287, 0.272, 0.252, 0.227, 0.2, 0.17,
#  0.14, 0.11, 0.083, 0.058, 0.038, 0.023, 0.013, 0.01, 0.01]

These are the toy numbers of a 20-step example. A real run has thousands of steps, and the peak is far smaller than 0.3 for a transformer, but the shape is identical.

If a run diverges early, look at the learning rate first. Too high a peak, or too short a warmup, is one of the most common reasons a loss curve shoots up instead of falling.

Takeaways

  • Warmup raises the learning rate gradually while the optimizer’s statistics are still unreliable.
  • Cosine decay brings it down smoothly to a small floor.
  • The whole schedule is a few lines of code and the shape is the same at any scale.
  • Instability early in a run often points to the peak rate or the warmup length.

Next in the series (Part 4): Gradient accumulation: a big batch on a small GPU

This blog is from chapter 3, course-2-generative-ai of 4 world-class courses on aibits.ecubeanalytics.com
← Previous Article 3 of 8 in this series Next →