“Training Compute-Optimal Large Language Models” (Hoffmann et al., DeepMind, 2022) — the
Chinchilla paper. One of the most consequential results in LLM training strategy.
A common conflation worth keeping straight — these are two separate things:
The identity (bookkeeping): C ≈ 6ND says what any run costs. It holds for every (N, D)
combination — good and terrible ones alike.
The optimality result (Chinchilla’s contribution): among all (N, D) pairs costing the
same C (a hyperbola: N·D = C/6), which achieves the lowest loss?
(huge N, tiny D) → under-trained → bad loss (Gopher’s corner)
(tiny N, huge D) → model too small to absorb the data → bad loss
in between → minimum loss ← N ∝ C^0.5, D ∝ C^0.5, ~20 tokens/param
At budget C, your loss is the best achievable only if you allocate Chinchilla-optimally.
C determines the floor; the (N, D) split determines whether you reach it.
Formally: minimize the fitted L(N, D) subject to 6ND = C → the solution traces the
compute-optimal frontier L(C) (lower envelope of what each budget can buy). Gopher and
Chinchilla sat at the same C — Gopher above the frontier, Chinchilla on it. Same budget,
different split, better model: proof the split (not the budget) was being wasted.
Only two axes: x = N, y = D. There is no third axis — C/6 is just a constant (the value
the product must equal). Fixing C imposes N·D = C/6 = k, same shape as x·y = k → a
hyperbola in the N–D plane:
D (tokens)
│ ● (tiny N, huge D — model too small)
│ \
│ \
│ ● ← Chinchilla-optimal point (D/N ≈ 20)
│ `--.
│ `---.
│ `----● (huge N, tiny D — Gopher's corner)
└──────────────────────── N (params)
every point on the curve: N·D = C/6 (cost exactly C)
Slide right → bigger model, fewer tokens (the zero-sum trade). Slide left → smaller
model, more tokens.
Bigger budget → a hyperbola further out; budgets form a family of nested hyperbolas.
Loss is a third quantity — picture L(N, D) as contour lines drawn over this plane. The
Chinchilla question: walk along your budget’s hyperbola; where is the loss lowest? That
tangency point is (N_opt, D_opt), at D/N ≈ 20.
Gopher and Chinchilla are on the same hyperbola (same C); Gopher sits far down-right where
loss is worse.
Same compute → a 51B model on ~1T tokens: 3.4× smaller, 3.4× more data, lower loss, and 3.4×
cheaper at inference. (Both factors equal because moving from ratio 1.7 to 20 shifts each axis by
√(20/1.7) ≈ 3.4.)
Method + sanity checks: substitute the ratio into the budget constraint → quadratic in N →
don’t forget the square root. Then verify the candidate (N, D) against BOTH original equations
(product = budget, ratio = 20) — catches algebra slips instantly.
Ratio arithmetic (interview check): double N at fixed C → D halves → the tokens-per-parameter
ratio D/N drops 4× (numerator halves AND denominator doubles):
2ND/2=41⋅ND
e.g. 20 tokens/param → 5 tokens/param → under-trained model.
From a careful sweep (400+ models, three analysis methods): the loss-optimal split scales
N and D equally:
Nopt∝C0.5Dopt∝C0.5
Rule of thumb: D ≈ 20·N — about 20 tokens per parameter (that’s just the ratio D/N ≈ 20;
tokens per parameter is D/N).
Validation: Chinchilla (70B params × 1.4T tokens = 20:1
) trained with the same compute as
Gopher (280B × 300B) beat Gopher across the board — and is 4× cheaper at inference.
Chinchilla optimizes training compute only. Every serving request costs ∝ N (forward pass),
and a deployed model serves billions of requests — so total cost of ownership favors training
a smaller model far longer than the 20:1
optimum (“overtraining”):
\text{time} \approx \frac{6\,N\,D}{\text{throughput} \times \text{utilization (MFU)}}$$
- Time per step is ~constant (fixed model + hardware) → **at fixed N, wall-clock time is linear
in D**. Double the tokens = double the GPU-hours.
- "Train longer" in the Chinchilla discussion = "increase D" = more steps = more wall-clock.
- C isn't abstract: at fixed hardware, **C ∝ wall-clock × cluster size**. Overtraining a small
model (LLaMA-3 style) means literally paying a much longer training run once, to serve cheaper
forever.
## D Counts Tokens SEEN, Not Unique Tokens
$$D = \text{dataset size} \times \text{epochs}$$
Two ways to raise D: **more unique data** (grow corpus) or **more passes** (repeat data). Same
compute per token — but not equal value:
- **Fresh tokens** — full signal; the regime Chinchilla was fit in (~1 epoch).
- **Repeated tokens** — **diminishing returns**; heavy repetition → memorization, can hurt.
- Muennighoff et al. 2023 ("Scaling Data-Constrained LMs"): **up to ~4 epochs, repeats are almost
as good as fresh**; value decays fast beyond, ~nothing after dozens of epochs.
At frontier scale (15T+ tokens), **unique high-quality data — not compute — becomes the binding
constraint** (the "data wall") → hence data filtering, controlled repetition, synthetic data.
---
## Scaling-Law Extrapolation for Capability / Safety Evals
Same move as compute-optimal planning, pointed at a different question: **forecast what a model
will be capable of before/while training → plan evals and safeguards ahead of the capability
arriving.**
**Four uses:**
1. **Forecasting → proactive eval scheduling.** Extrapolate where the next run lands; commit *in
advance* to dangerous-capability evals at that scale. Backbone of **responsible scaling
policies** (Anthropic RSP, OpenAI Preparedness): capability thresholds + eval obligations
triggered at forecasted scales.
2. **Checkpoint evals mid-run.** Capabilities improve predictably with tokens seen → eval
intermediate checkpoints. If a dangerous-capability eval moves at 30% of training, pause and
assess *before* the run finishes.
3. **Anomaly detection.** The fit predicts expected loss for your (N, D). A model coming in
substantially *better* than predicted (data/algo improvement) flags that capability forecasts
and eval plans may be stale.
4. **Compute governance.** Compute is measurable and tracks capability → FLOP thresholds as
regulatory tripwires (e.g. EU AI Act 10²⁵ FLOP). Only coherent *because* scaling laws make
compute a capability proxy.
**Critical caveat: loss extrapolates smoothly; capabilities may not.**
- Cross-entropy loss extrapolation is reliable; **downstream task performance can jump**
("emergent abilities") — exactly the capabilities safety cares about.
- Counterpoint: emergence is partly a **metric artifact** — smooth metrics (log-likelihood of
correct answer vs. exact-match) often turn the jump into a smooth curve.
- Practical consequence: **design evals with continuous/graded metrics** to see capabilities
*approaching* rather than *appearing*; treat extrapolation as a planning tool with error bars.
**Why graded metrics fix it:** capability evals are usually **pass/fail** — flat at 0% until a
sudden jump, no warning. Loss forecasts smoothly *because loss is already a continuous, graded
metric*. Design safety evals the same way (log-likelihood, partial credit, calibrated
probability) and they become extrapolable **just like loss** — a rising trend you can forecast
toward a threshold, instead of a cliff you discover after the fact.
**Not in the original paper.** Hoffmann et al. (2022) is narrowly about training-compute-optimal
(N, D) — it does not discuss capability evals, RSPs, or compute governance. This application is
later field work (Anthropic RSP, OpenAI Preparedness, Wei et al. 2022 on emergent abilities,
Schaeffer et al. 2023 on emergence as a metric artifact) that *uses* Chinchilla-style scaling laws
as one input.
---
## Finding the Optimal Operating Point by Fitting a Local Quadratic
A practical scaling-law move: you have a handful of `(size, loss)` measurements and want the
**loss-minimizing size**. Loss vs **log-compute (or log-size)** is locally U-shaped, so fit a
parabola in `log10(size)` and read off its vertex.
**Recipe:**
1. Transform: `x = log10(size)` (the parabola is U-shaped in log-space, not raw size).
2. Fit `L(x) = a·x² + b·x + c` by OLS — design matrix `[x², x, 1]`, solve the normal equations
(see [[regression-metrics]] for the polynomial-OLS setup).
3. Vertex (the minimum, valid **because `a > 0`**):
$$x^* = -\frac{b}{2a} \qquad L_{\min} = c - \frac{b^2}{4a}$$
(`L_min` = substitute `x*` back in; or just `np.polyval([a,b,c], x_opt)`.)
4. Undo the transform: `optimal_size = 10**x*`.
**Robustness caveats (the interview follow-ups):**
- **`a > 0` is load-bearing.** With noise or few points the fit can return `a ≤ 0` → `x*` is a
*maximum* or explodes (`a ≈ 0` → divide-by-~0). Guard it; the vertex is only a minimum when
`a > 0` (see [[linear-algebra-basics]] for why the fit can also be unstable).
- **Misconception:** fitting a degree-2 polynomial does *not* force `a > 0`, and neither does
having all-positive sizes/losses. The sign of `a` is **curvature** — how the *slope* changes —
determined entirely by the data's shape, not by the model choice or coordinate signs. Collinear
points → `a = 0`; concave (slope decreasing) → `a < 0`. `a > 0` holds **only if the sampled
sizes straddle the loss minimum** (loss goes down *and back up*). If every sample is still on
the descending branch (common — you haven't trained a big enough model to bottom out), the fit
gives `a ≈ 0` or `< 0` and `x*` is meaningless. The guard is really checking "did my data
capture the bottom of the curve?"
- **Extrapolation.** Nothing forces `x*` inside the observed size range — a vertex beyond your
sampled points is an extrapolated guess. Consider clipping to `[min, max]` of observed log-sizes.
- **Need ≥ 3 distinct x-values** or `XᵀX` is singular (3 coefficients). Fewer → `LinAlgError`.
- `np.linalg.lstsq` (SVD) degrades more gracefully than `solve` if `X` is ill-conditioned;
log-transforming the sizes usually keeps conditioning fine.
Related: [[optimization]], [[learning-rate]], [[perplexity]], [[tokenization]], [[regression-metrics]], [[linear-algebra-basics]]