A single power law tells you how big to build, how long to train, and why every modern lab now over-trains a small model to win on inference.
A scaling law is an empirical power law that predicts model loss from three numbers — parameters , training tokens , and the compute that ties them together. The headline fact: for a fixed compute budget, there is one optimal pair, and Chinchilla showed that pair has and growing in lockstep — roughly 20 tokens per parameter at the optimum. Kaplan's 2020 laws got the shape right but the allocation wrong; they told labs to build huge, data-starved models (GPT-3: 175B params, 300B tokens), and Chinchilla proved a 70B model on 1.4T tokens beats them on the same compute. The twist that defines 2024-2026: labs now deliberately violate compute-optimality, training small models far past 20 tokens/param, because the budget that matters in production is inference, not training. Everything downstream — which model you pick, how long you train, whether you repeat data — falls out of this one curve.
The words first.
Step by step.
Remember this: one power law tells you the cheapest way to reach a target loss — and production bends it toward cheap inference.
Scaling laws fit a single scalar — cross-entropy loss — as a function of scale. The clean, separable form Chinchilla uses is:
Defining every symbol:
The two non-constant terms each say: doubling that resource multiplies its loss contribution by a fixed factor ( or ). Because and are close, parameters and data reduce loss at similar rates — which is the mathematical seed of the "scale them together" conclusion. The Kaplan 2020 form was a simpler single-variable law that, crucially, used non-embedding parameter counts and a different learning-rate schedule; this is the technical root of why Kaplan and Chinchilla disagree.
Compute, parameters, and data are not independent — they're chained by the cost of a forward+backward pass. For a dense transformer, one token costs about FLOPs in the forward pass (one multiply-add per weight, counted as 2 FLOPs) and roughly in the backward pass, totaling FLOPs per token. Over tokens:
This is the load-bearing equation of the whole field. It means: fix , and choosing forces . You cannot have both big and well-fed for free. Scaling laws are, at heart, a constrained optimization over this one line.
Names in plain words: C = total training FLOPs you can afford. N = model size (params). D = training tokens. The rule C ≈ 6·N·D ties them; Chinchilla says the loss-minimizing split puts about 20 tokens per parameter.
Suppose you have C = 1.2e21 FLOPs (a modest run).
N · D = C / 6 = 1.2e21 / 6 = 2.0e20.D = 20 · N.N · (20·N) = 2.0e20, so 20·N² = 2.0e20, giving N² = 1.0e19, N ≈ 3.16e9 ≈ 3.2B params.D = 20 · 3.16e9 ≈ 6.3e10 = 63B tokens.Check: 6 · 3.2e9 · 6.3e10 ≈ 1.2e21 FLOPs. ✓
What it did: from a single budget number it pinned down both the model size and the dataset size — a 3.2B model on 63B tokens. Build a 30B model on the same budget instead and you'd starve it on 6.7B tokens (≈0.2 tokens/param) and land far up the loss curve.
Kaplan et al. (2020) concluded that under a fixed compute budget you should spend most of it on parameters: their fit implied and only — model size racing ahead of data. The industry took this literally. GPT-3 (175B params, 300B tokens) is the monument: under 2 tokens/param, wildly data-starved by the standard that came later.
Hoffmann et al. (2022) re-ran the experiment with 400+ models from 70M to 16B params, three independent methods, and a corrected learning-rate schedule (Kaplan's LR decay didn't reach the end of training, biasing his loss estimates). Their finding flipped the allocation: and — parameters and tokens scale equiproportionally. The 20-tokens-per-parameter rule is the practical summary (Chinchilla itself: 70B params, 1.4T tokens). The proof was Chinchilla (70B) beating Gopher (280B) — a 4× smaller model — on the same compute, by +7% on MMLU and across the benchmark suite, while being far cheaper to fine-tune and serve. The two reconciling technical points an interviewer wants: (1) Kaplan counted non-embedding parameters, distorting small-model fits; (2) his LR schedule under-trained the tail, making more data look less useful than it is.
Here is the subtlety that the 20:1 headline hides. The loss surface near the compute-optimal point is flat. Move to a model 2-3× smaller than optimal and feed it the extra compute as more tokens, and your training loss rises only slightly. Chinchilla-optimal minimizes loss per unit training FLOP — but it completely ignores inference.
Production economics invert the objective. A model is trained once and served billions of times. Inference cost scales with (≈ FLOPs per generated token), so a smaller model is permanently cheaper and lower-latency. The rational move: pick the smallest that hits your quality bar, then pour tokens in well past 20:1 to squeeze its loss down. This is exactly why Llama 3 8B trained on 15T tokens (≈1875 tokens/param, ~90× the Chinchilla ratio) and Llama 3.1 trained ~2 epochs on diverse corpora. The training run is "compute-suboptimal" on purpose — you knowingly burn extra GPU-hours up front to amortize a smaller, faster model across a deployment lifetime. The correct frame: Chinchilla optimizes a training budget; deployment optimizes total cost of ownership = training + (inference cost × expected query volume). When query volume is large, the optimum shifts hard toward smaller, over-trained models.
The clean laws assume unique tokens are infinite. They aren't — high-quality web text is finite, and frontier runs now bump the ceiling. Muennighoff et al. (2023) studied what happens when exceeds the unique-token supply and you must repeat data. Findings that matter:
The practical rule of thumb from this work: up to about 4 epochs, repeating data is a reasonable substitute for collecting more; beyond that, you're better off adding parameters, accepting a smaller model, or spending on data acquisition/curation. This is why most 2024-2026 production runs cap at 1-2 epochs on their best data and treat data quality as the binding constraint, not token count.
Scaling laws predict loss, which falls smoothly. But Wei et al. (2022) catalogued emergent abilities — tasks (multi-step arithmetic, certain reasoning benchmarks) where accuracy is near-random until a scale threshold, then jumps sharply. If real, emergence means you cannot extrapolate capability from small models even when you can extrapolate loss. The live debate: a strong counter-argument holds that many "emergences" are artifacts of discontinuous metrics (exact-match accuracy) — swap to a smooth metric like per-token log-likelihood and the jump dissolves into a gradual curve. The synthesis emerging in 2024-2026 work frames grokking, double descent, and emergence as the same underlying phenomenon: a memorization-vs-generalization circuit competition, where a phase transition (U-shaped scaling on hard subtasks composing with inverted-U on easy ones) produces the apparent threshold. The honest interview position: loss scaling is robust and predictive; capability scaling is partly a measurement question and partly real phase-transition behavior, and you should not bet a roadmap on a single emergence threshold.
Fit a Chinchilla-style law from run data and solve for the compute-optimal split. This is the back-of-envelope every staff engineer should be able to run before approving a training budget.
import numpy as np
from scipy.optimize import curve_fit
# --- 1. Fit L(N, D) = E + A/N^alpha + B/D^beta from observed runs ---
# Each row: (params N, tokens D, measured final loss). Real runs, not toy.
runs = np.array([
[70e6, 1.4e9, 3.40],
[160e6, 3.2e9, 3.12],
[410e6, 8.2e9, 2.88],
[1.0e9, 20e9, 2.66],
[2.8e9, 55e9, 2.49],
[6.9e9, 140e9, 2.36],
])
N, D, L = runs[:, 0], runs[:, 1], runs[:, 2]
def loss_law(X, E, A, B, alpha, beta):
n, d = X
return E + A * n**(-alpha) + B * d**(-beta)
# Fit in a numerically sane range; bounds keep exponents in (0,1).
p0 = [1.7, 400.0, 400.0, 0.34, 0.28]
(E, A, B, alpha, beta), _ = curve_fit(
loss_law, (N, D), L, p0=p0,
bounds=([0, 0, 0, 0.05, 0.05], [4, 1e6, 1e6, 1.0, 1.0]),
maxfev=100000,
)
print(f"E={E:.3f} A={A:.1f} B={B:.1f} alpha={alpha:.3f} beta={beta:.3f}")
# --- 2. Given a compute budget, solve the optimal N, D split ---
def compute_optimal(C, A, B, alpha, beta):
"""Minimize L over N,D subject to C = 6*N*D. Grid search on N."""
Ns = np.logspace(8, 11, 4000) # 0.1B .. 100B params
Ds = C / (6.0 * Ns) # compute constraint
losses = E + A * Ns**(-alpha) + B * Ds**(-beta)
i = np.argmin(losses)
return Ns[i], Ds[i], losses[i]
C = 1.2e21 # FLOPs
N_opt, D_opt, L_opt = compute_optimal(C, A, B, alpha, beta)
print(f"C={C:.1e} FLOPs -> N*={N_opt/1e9:.2f}B D*={D_opt/1e9:.1f}B "
f"tokens/param={D_opt/N_opt:.1f} loss={L_opt:.3f}")What each block does. Block 1 fits the five constants of the separable law by nonlinear least squares; the bounds keep the exponents physically meaningful and the irreducible loss non-negative. Block 2 enforces the compute bridge by parameterizing the whole feasible set with a single variable (since is then determined), evaluating loss along that line, and taking the minimum — exactly the constrained optimization of §3.2. The printed tokens/param should land near 20 when your fit recovers ; if it doesn't, your fit (or your run data) is telling you the exponents diverge, which is itself a finding. The same compute_optimal function, swept over a range of , traces the compute-optimal frontier you'd put in a planning doc.
| Regime | vs optimal | Tokens/param | Training cost | Inference cost | When to choose |
|---|---|---|---|---|---|
| Kaplan-style (legacy) | much larger | ~2 | high (wasted on params) | high (huge ) | never, in hindsight |
| Chinchilla-optimal | optimal | ~20 | minimized per FLOP | moderate | research/ablation; one-shot eval |
| Over-trained (modern default) | 2-10× smaller | 100-2000 | higher up-front | low, fast | high-volume serving, edge, latency SLA |
| Data-constrained | smaller | repeats, ≤4 epochs | bounded by data | low | scarce high-quality corpus |
Cost. Training is a one-time ; inference is recurring FLOPs per output token times every query forever. The crossover math: extra training tokens to over-train cost once; the inference savings from a smaller accrue per query. Above a volume threshold (often millions of queries — easily reached for any deployed product) the over-trained small model wins on total cost of ownership.
Latency / quality. Smaller means lower per-token latency and higher throughput (more requests per GPU), the dominant serving lever. Over-training buys back the quality you'd lose from shrinking — up to a point of diminishing returns set by the term flattening.
Failure modes. (1) Extrapolating off-distribution — laws are fit on a fixed data mix; change the corpus (more code, more multilingual) and the constants move. (2) Data exhaustion — pushing tokens/param high enough that you exceed unique data and silently start repeating, paying the >4-epoch overfitting tax. (3) Confusing loss with capability — a lower loss does not guarantee an emergent skill cleared its threshold; eval on the actual task. (4) Stale — MoE and quantized training break the dense FLOP accounting; for MoE use active parameters per token, not total.
What changes at scale. At frontier compute the binding constraint stops being FLOPs and becomes unique high-quality tokens and memory bandwidth (see /inference). Allocation decisions shift from "how big a model" to "how do I get more good data" (synthetic data, curation, multi-epoch with quality filtering). MoE changes the curve: it decouples total parameters (capacity) from active parameters (per-token cost), letting you grow capacity while holding inference FLOPs roughly fixed — a different point on the cost/quality frontier than dense scaling laws describe.
Flashcard. Chinchilla picks the cheapest training point (20 tokens/param via ); production deliberately over-trains a smaller model because inference is paid per query, forever — total cost of ownership, not training FLOPs, sets the real optimum.
Next: /inference — where the -per-token serving cost that drives over-training actually gets paid, and how to make it cheaper.