Scaling Laws and Optimization

You will be able to take a compute budget and turn it into a model size, a token count, and a predicted loss; and you will know how to set the optimizer, the learning-rate schedule and the batch size so that the run you can only afford once actually converges.

You have $10^{24}$ FLOPs and one attempt. Should you train a 30B model on 5T tokens, or a 100B model on 1.5T? Both cost the same. One of them will be noticeably better, and you will not find out which until the money is spent. Then, having chosen, what learning rate do you set? You cannot sweep it; a single run takes a month.

Ten years ago these questions were answered by folklore. Today they are answered by two bodies of work. Scaling laws say that loss is a smooth, predictable function of model size, data and compute, so you can extrapolate from cheap runs to the expensive one. Optimization practice is the accumulated knowledge of which optimizer settings survive at scale, and why runs blow up when they do. This chapter covers both, because in practice they are used together: scaling laws pick $N$ and $D$; optimization makes the run that uses them succeed.

Part A: Scaling laws

The observation: loss is a power law

The problem in 2019 was that nobody knew whether bigger models would keep getting better, or whether the returns would flatten. Kaplan et al. (2020) at OpenAI trained hundreds of transformers spanning seven orders of magnitude of compute and plotted the test loss against three quantities: non-embedding parameters $N$, dataset tokens $D$, and compute $C$. Every plot was a straight line on log-log axes. That is the signature of a power law.

$$L(N) \approx \left(\frac{N_c}{N}\right)^{\alpha_N}, \qquad L(D) \approx \left(\frac{D_c}{D}\right)^{\alpha_D}$$

Read $L(N)$ as "the loss you get from a model of size $N$ when data is not the bottleneck". Kaplan's fits gave $\alpha_N \approx 0.076$ and $\alpha_D \approx 0.095$. The exponents are small, which means the lines are shallow: to halve the loss you need to increase $N$ by a factor of $2^{1/0.076} \approx 9{,}000$. But they are straight over seven orders of magnitude, with no sign of bending. That was the headline: scaling works, and it works predictably.

Intuition

Why a power law? One picture: natural text has structure at every scale, from spelling to syntax to facts to long-range narrative, and each kind of structure is rarer and harder than the last. A model with more capacity, or more data, keeps picking off the next-rarest pattern. Because the patterns are distributed like a long tail, each doubling of resources buys a constant fraction of the remaining loss.

Kaplan also asked how to split a compute budget between $N$ and $D$. Their answer, from fitting $L$ as a function of both, was that model size should grow much faster than data: $N \propto C^{0.73}$ and $D \propto C^{0.27}$. Between 2020 and 2022 the field followed this advice. GPT-3 (175B on 300B tokens), Gopher (280B on 300B), and Megatron-Turing NLG (530B on 270B) all spent their compute on parameters.

The Chinchilla result

Hoffmann et al. (2022) at DeepMind re-ran the experiment with one change that turned out to matter enormously: they tuned the learning-rate schedule to the length of each run, instead of using a fixed schedule for all of them (which Kaplan had done, leaving short runs under-decayed and so under-performing). With that fixed, the picture changed. Using three separate methods, they found that for compute-optimal training:

$$N_{\text{opt}} \propto C^{0.5}, \qquad D_{\text{opt}} \propto C^{0.5}$$

Model size and tokens should scale together. Doubling the budget means a model $\sqrt{2}$ times bigger trained on $\sqrt{2}$ times more data. The practical rule that fell out of their isoFLOP curves: about 20 tokens per parameter. By that rule, Gopher's 280B parameters wanted 5.6T tokens, not 300B; Gopher was drastically under-trained. To prove it they trained Chinchilla, a 70B model on 1.4T tokens with exactly Gopher's compute, and it beat Gopher on essentially every benchmark.

Fixed budget C = 6·N·D. Which way along the curve? big Nfew D small Nmany D Gopher 280B / 300Bloss 1.99 (fit) Chinchilla 70B / 1.4Tsame C, lower loss Llama-style: 8B / 15Tover-trained on purpose the isoFLOP curve: every point costs the same to train; inference cost falls to the right
Figure 1. One compute budget, many ways to spend it. Gopher sat at the top-left (big model, little data). Chinchilla moved along the same isoFLOP curve to the loss minimum. Llama-style models deliberately go further right than optimal, because a smaller model is cheaper to serve.
Where it came from

Hestness et al. (2017) at Baidu had shown power-law learning curves across several domains. Kaplan et al. (2020) made it a planning tool for language models. Hoffmann et al. (2022) corrected the recipe, and "Chinchilla-optimal" became the standard reference point for every training run since.

The fitted loss form

The most useful output of the Chinchilla paper is a formula. Their third approach fits the final loss as the sum of three pieces: an irreducible floor, a term that shrinks with model size, and a term that shrinks with data.

$$L(N, D) = E + \frac{A}{N^{\alpha}} + \frac{B}{D^{\beta}}$$

with fitted constants $E \approx 1.69$, $A \approx 406.4$, $B \approx 410.7$, $\alpha \approx 0.34$, $\beta \approx 0.28$ (loss in nats per token on their held-out data). Read it as: $E$ is the entropy of text itself, which no model can beat; $A/N^\alpha$ is the penalty for having finitely many parameters; $B/D^\beta$ is the penalty for having seen finitely many tokens. Both penalties fall as power laws and both go to zero in the limit.

Worked evaluation: Gopher vs Chinchilla

Gopher, $N = 2.8\times 10^{11}$, $D = 3\times 10^{11}$. Parameter term: $406.4 / (2.8\times 10^{11})^{0.34} = 406.4 / 7800 = 0.052$. Data term: $410.7 / (3\times 10^{11})^{0.28} = 410.7 / 1636 = 0.251$. Loss: $1.69 + 0.052 + 0.251 = 1.993$.

Chinchilla, $N = 7\times 10^{10}$, $D = 1.4\times 10^{12}$. Parameter term: $406.4 / 4866 = 0.084$. Data term: $410.7 / 2516 = 0.163$. Loss: $1.69 + 0.084 + 0.163 = 1.937$.

Same compute; the fit predicts Chinchilla is 0.056 nats better. Look at where the loss comes from: Gopher's data term is five times its parameter term. It was starved of tokens. Chinchilla balanced them (0.084 vs 0.163 is closer, though still not equal).

Deriving the compute-optimal split

Given this formula and the constraint $C = 6ND$, where is the minimum? Set up the trade: spend a little compute moving from $D$ to $N$, and the loss changes by the difference of the two marginal terms. At the optimum they balance. Working through the algebra (a Lagrange multiplier on $\log N + \log D = \text{const}$) gives:

$$N_{\text{opt}} = G\left(\frac{C}{6}\right)^{a}, \quad D_{\text{opt}} = G^{-1}\left(\frac{C}{6}\right)^{b}, \qquad a = \frac{\beta}{\alpha+\beta},\ b = \frac{\alpha}{\alpha+\beta},\ G = \left(\frac{\alpha A}{\beta B}\right)^{\frac{1}{\alpha+\beta}}$$

With the published constants, $a = 0.45$, $b = 0.55$, $G = 1.34$. Both exponents are near one half, which is the "scale them together" result. Note that $b$ is slightly larger than $a$: as budgets grow, the fit wants tokens to grow a little faster than parameters.

Common confusion: the published constants do not give 20 tokens per parameter

Plug Gopher's budget ($C = 5.76\times 10^{23}$) into the formulas above and you get $N_{\text{opt}} \approx 32$B and $D_{\text{opt}} \approx 3.0$T, a ratio of about 90 tokens per parameter, not 20. The 20:1 rule comes from the paper's first two approaches (isoFLOP curves), and the parametric fit as published is known to disagree with them; Besiroglu et al. (2024) replicated the fit from the paper's own data and found constants (roughly $E = 1.82$, $A = 482$, $B = 2085$, $\alpha = 0.35$, $\beta = 0.37$) that do reproduce ~20:1. The practical lesson is twofold: the 20:1 rule is the robust finding, and the loss surface is very flat near the optimum, so under the published fit a 32B/3T model and a 69B/1.4T model land within 0.007 nats of each other. Getting the ratio wrong by 4x costs almost nothing; getting it wrong by 20x, as Gopher did, costs a lot.

InteractiveChinchilla explorerdrag C, then over-train

Pick a compute budget. See the compute-optimal $N$ and $D$ and the predicted loss. Then drag "tokens per parameter" away from optimal and watch loss rise slowly while inference cost falls fast.

Why later models over-train past Chinchilla-optimal

Chinchilla answered "what is the best model for a fixed training budget". But that is the wrong question if you are going to serve the model to millions of users. Every generated token costs about $2N$ FLOPs at inference. A model half the size is half the price to run, forever. If inference compute will dwarf training compute, and for a popular model it does, then you should accept a slightly worse loss for a much smaller model, and pay for it with more training tokens.

This is the Llama philosophy, stated explicitly in the Llama 1 paper (Touvron et al., 2023): "the objective of the scaling laws from Hoffmann et al. is to determine how to best scale the dataset and model sizes for a particular training compute budget. However, this objective disregards the inference budget." Llama 3 8B was trained on about 15T tokens, roughly 1,900 tokens per parameter, nearly a hundred times past the 20:1 rule. Under the fitted law its loss ($1.949$) is only slightly worse than Chinchilla 70B's ($1.937$) at a fraction of the serving cost. Sardana and Frankle (2023) formalize this by adding expected inference tokens to the objective; the more you plan to serve, the smaller and longer-trained the optimal model becomes.

The loss surface being flat near the optimum is what makes this a good trade rather than a heroic sacrifice: the $B/D^\beta$ term keeps shrinking as you add tokens, and it partly compensates for the larger $A/N^\alpha$ term of the smaller model.

The power-law plot

Here is the fitted law drawn as a family of curves. Each line is loss against model size for a fixed token count. The curves flatten on the right where $N$ is large enough that the data term dominates: adding parameters to a data-starved model does nothing. Adjust the exponents to see how sensitive the whole picture is to them.

InteractiveLoss vs N for several Ddrag the exponents

Log-log axes. Watch where each curve flattens: that is the point where more parameters stop helping because the model has run out of data.

Emergent abilities and the debate

Loss scales smoothly. Do capabilities? Wei et al. (2022) collected examples of tasks (multi-step arithmetic, word unscrambling, some BIG-Bench tasks) where performance sat at chance for small models and then jumped sharply at some scale, and called these emergent abilities: abilities that are absent in smaller models and present in larger ones, not predictable from the small-model trend. If real, this would mean that scaling laws on loss tell you little about what a bigger model will be able to do.

Schaeffer et al. (2023) offered a deflationary reading. Most of the "emergent" tasks were scored with discontinuous metrics: exact match on a five-digit answer, where being off by one digit scores zero. If the model's per-token accuracy improves smoothly, the probability of getting all five digits right goes as accuracy to the fifth power, which looks like a sudden jump when the per-token accuracy crosses a threshold. Replace exact match with a continuous metric like token edit distance, and the curves become smooth. They showed this on the arithmetic tasks and argued that emergence is often a property of the metric, not the model.

Where the debate stands, as best it can be summarized: loss and continuous proxies scale predictably, and that is what you plan a run on. Some downstream capabilities do look sharp in the metrics people care about, and whether you call that "emergent" depends on whether you insist on the metric that users see (exact answers) or the one that is smooth. Both camps agree that per-token loss improves smoothly, and that smooth improvement is what scaling laws promise.

Symbols
$N$ = parameters
$D$ = tokens
$C = 6ND$ = FLOPs
$E$ = irreducible loss
$\alpha, \beta$ = exponents
STEP 1
Sweep small
Train a grid of small models over several sizes and token counts. Record final loss.
STEP 2
Fit
Fit $L = E + A/N^\alpha + B/D^\beta$ (or isoFLOP parabolas) to the grid.
STEP 3
Extrapolate
For the real budget $C$, solve for the $N, D$ that minimize predicted loss, then adjust for inference cost.
STEP 4
Verify
Compare the big run's loss to the prediction. If it misses, something else (data, instability) is wrong.

Part B: Optimization

Scaling laws told you what to train. Now you have to train it, and the constraint is brutal: you get one shot, at a scale where you cannot tune anything. Every setting below is a default that was learned the hard way.

AdamW: the optimizer everyone uses

The problem plain gradient descent has with transformers: different parameters see gradients of wildly different scale. Embedding rows for rare tokens get tiny, infrequent gradients; attention output projections get large, dense ones. One learning rate cannot serve both. Adam (Kingma and Ba, 2015) fixes this by keeping, for every parameter, a running average of the gradient and a running average of its square, and dividing one by the root of the other. The result is that each parameter moves by roughly the learning rate per step, regardless of gradient scale.

$$m_t = \beta_1 m_{t-1} + (1-\beta_1) g_t, \qquad v_t = \beta_2 v_{t-1} + (1-\beta_2) g_t^2$$ $$\hat m_t = \frac{m_t}{1-\beta_1^t}, \qquad \hat v_t = \frac{v_t}{1-\beta_2^t}, \qquad \theta_t = \theta_{t-1} - \eta\left(\frac{\hat m_t}{\sqrt{\hat v_t} + \epsilon} + \lambda\,\theta_{t-1}\right)$$

What just happened, line by line. $m_t$ is momentum: an exponential moving average of gradients, which smooths noise. $v_t$ tracks the typical squared gradient size. The hats divide out the bias from starting both averages at zero (without them the first steps would be tiny). The update divides momentum by the root of the second moment, so a parameter with consistently large gradients and one with consistently small gradients both move by about $\eta$ per step. The last term, $\lambda\theta$, is decoupled weight decay (Loshchilov and Hutter, 2019): the "W" in AdamW. It pulls every weight toward zero by a fixed fraction each step, applied directly rather than through the adaptive scaling.

Worked example, one parameter

$\beta_1 = 0.9$, $\beta_2 = 0.95$, and the gradient is $g = 1$ for three steps.

Step 1: $m = 0.1$, $v = 0.05$. Bias correction: $\hat m = 0.1/0.1 = 1$, $\hat v = 0.05/0.05 = 1$. Update $= 1/\sqrt{1} = 1$. The parameter moves by exactly $\eta$.

Step 2: $m = 0.19$, $v = 0.0975$; $\hat m = 0.19/0.19 = 1$, $\hat v = 0.0975/0.0975 = 1$. Update $= 1$ again.

Now change the gradient to $g = 0.001$ for all three steps instead. Every $m$ is 1000 times smaller, every $v$ is a million times smaller, and the ratio $\hat m / \sqrt{\hat v}$ is again exactly 1. The step size does not depend on the gradient's scale. That is the whole point of Adam, and why one learning rate works for a billion heterogeneous parameters.

The hyperparameters for LLMs

The defaults you inherit from PyTorch ($\beta_2 = 0.999$, no weight decay) are wrong for LLM pre-training. The settings that have converged across GPT-3, Llama, and most open reports:

SettingTypical valueWhy
$\beta_1$0.9Standard momentum. Rarely changed.
$\beta_2$0.95The default 0.999 averages $v$ over ~1000 steps, so when gradient magnitudes suddenly grow (a spike), $v$ is stale and the step is too large. 0.95 averages over ~20 steps and reacts in time. This single change removes many instabilities.
$\epsilon$$10^{-8}$Prevents division by zero. Some runs use $10^{-6}$ or larger for stability with bf16; too large and it becomes plain momentum SGD for small-gradient parameters.
weight decay $\lambda$0.1Larger than the 0.01 common in vision. Keeps weight norms, and thereby attention logits, from growing without bound over a long run. Usually not applied to norms and sometimes not to embeddings.
peak learning rate$3\times 10^{-4}$ (7B) to $6\times 10^{-5}$ (175B)Falls with model size; see below.
gradient clippingglobal norm 1.0See below.
InteractiveSGD vs momentum vs Adam on an ill-conditioned bowldrag lr and conditioning

The loss is $f(x, y) = \tfrac{1}{2}(x^2 + \kappa y^2)$: a valley that is $\kappa$ times steeper in $y$ than in $x$. All three optimizers start from the same point and take 60 steps.

Learning-rate schedules

The problem: the right learning rate is not one number. Early in training, the weights are random and the gradient direction is unreliable; a big step can push the model into a bad region it never recovers from. In the middle, you want big steps to cover ground. At the end, you want small steps so the model settles into a minimum rather than bouncing around it. A schedule encodes all three.

Linear warmup, cosine decay

The standard recipe from GPT-3 onward: ramp the learning rate linearly from zero to its peak $\eta_{\max}$ over the first $W$ steps (GPT-3: 375M tokens; Llama: 2,000 steps), then decay it along a cosine curve to a floor $\eta_{\min}$ (typically 10% of peak) at the final step $S$.

$$\eta(t) = \begin{cases} \eta_{\max}\, t / W & t \le W \\[4pt] \eta_{\min} + \tfrac{1}{2}(\eta_{\max} - \eta_{\min})\left(1 + \cos\!\left(\pi \dfrac{t - W}{S - W}\right)\right) & t > W \end{cases}$$

The cosine is nothing magic; it is a smooth curve that spends a long time near the peak and a long time near the floor, with a fast transition between. Its weakness is that it needs to know $S$ in advance. Decide to train longer, and the schedule you already ran was wrong (it decayed too early). This is also exactly what tripped up the Kaplan scaling-law fits.

Warmup-stable-decay (WSD)

The alternative that has spread since 2024 (Hu et al., 2024 in MiniCPM; analyzed by Hägele et al., 2024): warm up, then hold the learning rate constant for most of training, then decay it quickly (linearly, or along a square-root-shaped curve) over the last 10 to 20 percent of steps. The constant phase is agnostic to total length: you can branch off a decay at any point and get a good model, or keep going. It also makes scaling-law experiments cheap, because one long stable run yields models at many token counts, each finished by a short decay. Loss during the stable phase sits above the cosine run's, and then drops sharply during decay to match or beat it.

Why warmup matters

Three reasons, all early-training. First, Adam's $v_t$ estimate is built from a handful of samples in the first steps, and dividing by an unreliable $\sqrt{\hat v}$ produces erratic step sizes; warmup keeps those steps small until the estimate settles. Second, at random initialization the loss surface is sharp in some directions (large gradient norms), and a full-size step overshoots; warmup lets the model move into a flatter region first. Third, attention logits and layer norms are unconstrained at initialization and can be driven into saturation by a few large updates. Skipping warmup on a large model reliably produces a spike in the first few hundred steps.

InteractiveLearning-rate schedule designerchoose a shape, drag

Warmup, then cosine, linear or WSD. The area under the curve is a rough proxy for "how far the weights can travel".

Batch size in tokens and the critical batch size

The problem: with thousands of GPUs you want a huge batch, because each GPU needs enough work to stay busy and because fewer, bigger steps means less communication per token. But does a bigger batch actually learn more per token? Not without limit. LLM batch sizes are quoted in tokens: GPT-3 used 3.2M tokens per batch; Llama 3 405B ramped from 4M to 16M tokens over the run.

McCandlish et al. (2018) gave the tool for thinking about this: the gradient noise scale. A mini-batch gradient is the true gradient plus noise whose variance shrinks as $1/B$. Averaging over more examples helps until the noise is small compared to the signal, and then it stops helping. The noise scale, approximately

$$B_{\text{noise}} \approx \frac{\operatorname{tr}(\Sigma)}{|G|^2}$$

where $G$ is the true gradient and $\Sigma$ the per-example covariance, estimates the batch size where that transition happens: the critical batch size. Below it, doubling the batch nearly halves the number of steps needed (perfect scaling). Above it, doubling the batch buys almost nothing; you are just spending more tokens per step. Their empirical rule ties the two limits together: if $S_{\min}$ is the minimum steps (with infinite batch) and $E_{\min}$ the minimum examples (with tiny batch), any run satisfies roughly $(S/S_{\min} - 1)(E/E_{\min} - 1) = 1$.

Worked example

Suppose a run needs at least $S_{\min} = 50{,}000$ steps and at least $E_{\min} = 100$B tokens. Choosing $S = 100{,}000$ steps ($S/S_{\min} = 2$) forces $E/E_{\min} - 1 = 1/(2-1) = 1$, so $E = 200$B tokens and the batch is $200\text{B}/100\text{k} = 2$M tokens. Choosing $S = 55{,}000$ instead ($S/S_{\min} = 1.1$) forces $E/E_{\min} = 11$, so $E = 1.1$T tokens and a 20M-token batch. You bought a 45% reduction in steps at 5.5x the tokens. Batch size is a trade between wall-clock time and compute, and the critical batch is where the exchange rate turns bad.

Steps vs tokens: (S/S_min − 1)(E/E_min − 1) = 1 steps Stokens E S_min: infinite batch E_min: tiny batch small batch: few tokens, many steps critical batch: the knee huge batch: barely fewer steps,many more tokens Every point on the curve reaches the same loss. Batch size picks the point; the knee is the critical batch size.
Figure 3. The trade-off curve from McCandlish et al. (2018). Moving right (bigger batch) buys fewer steps, but past the knee each step saved costs an enormous number of extra tokens. The knee moves right as training progresses, which is why batch sizes are ramped.

The noise scale grows as the loss falls: as the model gets better, the "signal" gradient gets smaller while the per-example noise stays, so larger batches become useful later in training. That is why Llama 3 and others ramp the batch size up in stages rather than fixing it.

Gradient clipping

The problem: occasionally a batch produces a gradient far larger than usual (a rare token pattern, a numerical hiccup). One such step with Adam is partly buffered by the $\sqrt{\hat v}$ division, but with $\beta_2 = 0.95$ the second moment adapts within a few steps and a burst of large gradients gets through. Clipping rescales the entire gradient vector if its global $L_2$ norm exceeds a threshold, almost always 1.0:

$$g \leftarrow g \cdot \min\!\left(1, \frac{1.0}{\|g\|_2}\right)$$

The direction is kept; only the magnitude is capped. Logging how often the clip fires is one of the most useful health signals in a run. If it fires on most steps, the learning rate is too high or something is wrong; if it never fires, it is not doing anything.

Loss spikes and their remedies

Every team that has trained a large model has stared at a loss curve that suddenly leapt upward, sometimes recovering, sometimes not. Spikes are the dominant failure mode of long runs, and by now the causes and fixes are reasonably well catalogued (Wortsman et al., 2023 is a good survey with small-scale reproductions).

losssteps spike: recovers spike: recovers,but loss is higher after or divergence: never recovers causes: attention logit growth, output logit drift, a bad batch, stale Adam v, lr too high. fixes below.
Figure 2. The anatomy of a spike. Loss climbs sharply within a few steps. Sometimes it returns to trend; sometimes it settles at a permanently worse level; sometimes the run diverges. The response to a spike that does not recover is to roll back to a checkpoint and change something.
RemedyWhat it doesWho uses it
Lower the learning rateThe blunt instrument. Spikes are strongly lr-dependent; the maximum stable lr shrinks with model size.Everyone, as a last resort
Longer warmupKeeps early steps small while Adam's statistics and the weights settle.Everyone
$\beta_2 = 0.95$Lets $v_t$ track sudden gradient growth so the update shrinks in time.GPT-3, Llama, most open runs
z-lossAdds $10^{-4} \cdot (\log Z)^2$ to the loss, where $Z$ is the softmax normalizer, keeping output logits from drifting to huge magnitudes.PaLM, OLMo 2
QK-normNormalizes queries and keys so attention logits cannot blow up (see pre-02).OLMo 2, Gemma 3, many since 2024
Weight decay 0.1Slows the growth of weight norms over the whole run.Everyone
Skip bad batchesRoll back to a checkpoint before the spike and skip the next few hundred batches. PaLM did this and found it worked, suggesting the data-plus-state combination, not the data alone, caused the spike.PaLM, Llama 3 (reported)
Embedding norm / tied lrApplies a norm after the embedding layer, or a separate lr for embeddings, which see the sparsest gradients.OLMo 2, Gemma
Common confusion

A spike is not a "bad batch" in the sense of one poisoned document. The same batch at a different point in training is usually harmless. What happens is that the model's state (large logits, saturated softmaxes, stale $v_t$) is fragile, and a batch that would be fine elsewhere tips it over. That is why architectural fixes like QK-norm work: they make the state robust rather than trying to sanitize the data.

μP and hyperparameter transfer

The problem: the optimal learning rate depends on model width, so a value tuned on a 100M-parameter proxy is wrong for the 100B target, and you cannot tune the target. Yang et al. (2022) showed that this dependence is an artifact of how we initialize and scale layers. In the standard parametrization, wider layers effectively get larger updates relative to their activations, so the safe learning rate shrinks with width. Their maximal update parametrization (μP) rescales initialization variances and per-layer learning rates with width in a specific way (for example, hidden-layer Adam learning rates scale as $1/\text{width}$) such that the optimal learning rate becomes independent of width. Tune once on a small model, transfer the values to the large one. It has been used for GPT-4-scale runs (reported), and MiniCPM and others document it in the open. The practical catch is that it must be implemented carefully in every layer, and depth transfer is less clean than width transfer.

Learning rate vs model size: rules of thumb

Without μP, you fall back on empirical fits. Kaplan et al. (2020) give one for standard-parametrization transformers: $\eta_{\text{opt}}(N) \approx 0.003239 - 0.0001395 \ln N$, which yields about $3.5\times 10^{-4}$ at 1B parameters; it was fit on models up to about a billion parameters and falls off too fast to extrapolate much beyond that. The GPT-3 table (Brown et al., 2020) is the reference most people actually copy: $6\times 10^{-4}$ for 125M, $2\times 10^{-4}$ for 1.3B, $1\times 10^{-4}$ for 13B, $6\times 10^{-5}$ for 175B. DeepSeek LLM (2024) fit both learning rate and batch size directly against compute, finding $\eta_{\text{opt}} \propto C^{-0.125}$ and $B_{\text{opt}} \propto C^{0.33}$. The direction is consistent everywhere: bigger model, smaller learning rate, bigger batch.

Companion code

code/lumen/optimizers.py implements SGD, momentum, Adam and AdamW from scratch as plain functions over parameter tensors, so you can read every line of the update. code/lumen/train.py has the warmup-cosine and WSD schedules, gradient clipping, and the training loop that logs the clip rate. The core of both fits on one screen.

import math, torch

def adamw_step(params, grads, state, lr, betas=(0.9, 0.95), eps=1e-8, wd=0.1):
    b1, b2 = betas
    state["t"] = state.get("t", 0) + 1
    t = state["t"]
    for i, (p, g) in enumerate(zip(params, grads)):
        m = state.setdefault(("m", i), torch.zeros_like(p))
        v = state.setdefault(("v", i), torch.zeros_like(p))
        m.mul_(b1).add_(g, alpha=1 - b1)              # m = b1*m + (1-b1)*g
        v.mul_(b2).addcmul_(g, g, value=1 - b2)       # v = b2*v + (1-b2)*g^2
        m_hat = m / (1 - b1 ** t)
        v_hat = v / (1 - b2 ** t)
        p.mul_(1 - lr * wd)                           # decoupled weight decay
        p.addcdiv_(m_hat, v_hat.sqrt().add_(eps), value=-lr)

def cosine_lr(step, warmup, total, peak, floor):
    if step < warmup:
        return peak * step / max(1, warmup)
    frac = (step - warmup) / max(1, total - warmup)
    return floor + 0.5 * (peak - floor) * (1 + math.cos(math.pi * frac))

def clip_grad_norm(grads, max_norm=1.0):
    total = math.sqrt(sum(float((g * g).sum()) for g in grads))
    scale = min(1.0, max_norm / (total + 1e-6))
    for g in grads:
        g.mul_(scale)
    return total  # log this: how often scale < 1 is a health signal

Practice

Exercise 1: plan a run

You have $2\times 10^{23}$ FLOPs. Using the 20 tokens-per-parameter rule, compute the compute-optimal $N$ and $D$ and evaluate the fitted loss. Then plan a Llama-style alternative that is 3x smaller and compute how many tokens it gets for the same budget, and its predicted loss. Which would you ship if you expect $10^{15}$ inference tokens over the model's lifetime? (Inference FLOPs $\approx 2N$ per token.)

Solution sketch

$6 N \cdot 20N = 2\times 10^{23}$ gives $N = \sqrt{2\times 10^{23}/120} \approx 4.1\times 10^{10}$ (41B) and $D \approx 8.2\times 10^{11}$. Loss $\approx 1.69 + 406.4/(4.1\times 10^{10})^{0.34} + 410.7/(8.2\times 10^{11})^{0.28} \approx 1.69 + 0.100 + 0.189 = 1.98$. The 3x-smaller model, $N = 13.6$B, gets $D = 2.45$T tokens; loss $\approx 1.69 + 0.146 + 0.140 = 1.98$: essentially the same (the loss surface is flat). Inference: $2 \times 41\text{B} \times 10^{15} = 8.2\times 10^{25}$ FLOPs for the big one versus $2.7\times 10^{25}$ for the small one, both hundreds of times the training cost. Ship the small one.

Exercise 2: reproduce the bowl

Using code/lumen/optimizers.py, minimize $f(x,y) = \tfrac{1}{2}(x^2 + 50y^2)$ from $(-4.5, 1.8)$ with SGD, momentum and Adam. Find the largest SGD learning rate that does not diverge and confirm it is close to $2/50 = 0.04$. Then show that Adam converges with a learning rate of $0.3$, where SGD would explode.

Solution sketch

For SGD on a quadratic with curvature $\kappa$, the update in $y$ is $y \leftarrow (1 - \eta\kappa) y$, which oscillates with growing amplitude when $\eta\kappa > 2$. Adam's per-coordinate normalization makes its $y$-step about $\eta$ regardless of $\kappa$; the only thing that limits Adam's lr on this problem is overshooting the minimum by more than its distance, which shows up as a zig-zag rather than divergence.

Exercise 3: measure the clip rate

Train the small model from code/lumen/train.py for 1,000 steps at three peak learning rates ($10^{-4}$, $10^{-3}$, $10^{-2}$) with warmup 100 and cosine decay. Log the gradient norm before clipping at every step and the fraction of steps where clipping fired. Plot loss and clip rate for all three. Which run is on the edge of instability, and how can you tell from the clip rate alone?

Solution sketch

Expect the $10^{-2}$ run to clip on nearly every step and possibly spike; the $10^{-4}$ run to almost never clip and converge slowly; the $10^{-3}$ run to clip occasionally early and rarely later. A clip rate that rises over time, rather than falling, is the early warning of an upcoming spike: the gradient norms are growing because the weights are.

Check yourself
According to Chinchilla, if you double your compute budget, how should model size and token count change?
$N_{\text{opt}} \propto C^{0.5}$ and $D_{\text{opt}} \propto C^{0.5}$: scale them together. Kaplan's earlier fit had favored parameters ($C^{0.73}$), which produced under-trained models like Gopher.
In L(N, D) = E + A/N^α + B/D^β, what does E represent?
E is the floor: the inherent unpredictability of natural text. Both penalty terms vanish as N and D grow, leaving E.
Why do LLM runs set Adam's β₂ to 0.95 instead of the default 0.999?
With β₂ = 0.999 the denominator averages over ~1000 steps and is stale when gradients spike, so the step is too large. 0.95 tracks recent gradient scale and shrinks the step in time.
What is the main practical advantage of a warmup-stable-decay schedule over cosine?
Cosine needs S up front and is mis-shaped if you extend training. WSD holds lr constant, so a short decay can be branched from any point of the stable phase.
Your batch is already at the critical batch size. What happens if you double it?
Below the critical batch size, bigger batches trade nearly one-for-one against steps. Above it, gradient noise is already small and extra examples add little. McCandlish et al. (2018).

Key takeaways

  • Loss follows power laws in N, D and C over many orders of magnitude; that is what makes planning a single expensive run possible.
  • Chinchilla: scale parameters and tokens together, roughly 20 tokens per parameter for compute-optimal training. Gopher-era models were badly under-trained.
  • The fitted law $L = E + A/N^\alpha + B/D^\beta$ lets you predict loss for any (N, D); the surface is flat near the optimum.
  • Production models over-train small models far past 20:1 because inference cost is proportional to N and dominates over the model's lifetime.
  • AdamW with β₂ = 0.95, weight decay 0.1, global-norm clipping at 1.0, linear warmup and cosine or WSD decay is the standard recipe.
  • Spikes come from a fragile model state (large logits, stale second moments), and the durable fixes are architectural: QK-norm, z-loss, norms on embeddings.
  • Batch size in tokens is limited by the critical batch size; learning rate falls with model size unless you use μP to transfer it.

Further reading