Evaluation During Pretraining

By the end you will know how to turn a training loss into a number you can compare across tokenizers, how the standard benchmarks actually score a base model, why a two-point gain is often noise, and how to read an evaluation curve without fooling yourself.

Your training loss is going down. Great. But loss is one number, averaged over trillions of tokens of everything from recipes to Rust. It tells you the model is getting better at predicting text on average. It does not tell you whether it can do arithmetic, recall facts, follow a few-shot pattern, or write a function that passes its tests. Two models with the same loss can differ a lot on those. So what is the model actually good at, and how would you know?

This chapter is about answering that question honestly. There are three layers. The first is the loss itself and how to make it comparable. The second is benchmarks: what they measure and, more importantly, the mechanics of how a base model is scored on them. The third is statistics: how much of a benchmark difference is real.

Held-out loss and perplexity

The cheapest evaluation is the one you already have: the next-token loss on a held-out set the model never trained on. Compute it on a few million tokens, sampled from the same mix as training, and you get an unbiased estimate of how well the model predicts unseen text.

Perplexity is the same number in a different unit. If the average loss per token is $\mathcal{L}$ nats, then

$$\text{PPL} = e^{\mathcal{L}}$$

and the interpretation is "the model is as uncertain, on average, as if it were choosing uniformly among PPL options". A loss of 2.3 nats is a perplexity of about 10: at each step, the model is roughly as confused as a ten-way coin flip. Lower is better, and the scale is exponential, so a drop from 3.0 to 2.9 nats is a 10% drop in perplexity.

Pitfalls: tokenizer, context, and domain

Here is the catch that trips people up. Perplexity is per token, and tokens are whatever your tokenizer says they are. A tokenizer with a bigger vocabulary chops text into fewer, longer tokens. Each of those tokens is harder to predict, so the per-token loss is higher, even if the model is exactly as good at predicting the underlying text. Two models with different tokenizers cannot be compared on per-token perplexity at all.

Two more pitfalls. Perplexity depends on how much context each token gets: evaluating with 512-token windows gives worse numbers than evaluating with 4k windows, because early tokens in each window have little to condition on. And it depends heavily on the domain of the held-out text: perplexity on Wikipedia and perplexity on GitHub are different quantities. Always state the tokenizer, the context length, and the evaluation corpus.

Bits per byte: the tokenizer-independent measure

The fix for the tokenizer problem is to charge the model per byte of raw text rather than per token. Total information is total information; how you chunked it should not matter. Convert the loss from nats to bits (divide by $\ln 2$), then multiply by how many tokens there are per byte:

$$\text{BPB} = \frac{\mathcal{L}}{\ln 2}\times\frac{N_{\text{tokens}}}{N_{\text{bytes}}}$$

What just happened: the model's total surprise on the document is the loss per token times the number of tokens. Dividing that total by the number of bytes gives surprise per byte, which no longer cares about the tokenizer. Bits per byte was popularised for LLM evaluation by the Pile paper (Gao et al. 2020) for exactly this reason.

Worked example

Tokenizer A turns a 1,000-byte document into 250 tokens (4 bytes per token) and the model scores 2.30 nats per token. Tokenizer B, with a bigger vocabulary, turns the same document into 200 tokens (5 bytes per token) and its model scores 2.65 nats per token.

Per-token perplexity: A is $e^{2.30} = 10.0$, B is $e^{2.65} = 14.2$. Model A looks much better.

Bits per byte: A is $2.30/0.693 \times 250/1000 = 3.32 \times 0.25 = 0.83$. B is $2.65/0.693 \times 200/1000 = 3.82 \times 0.20 = 0.76$. Model B is actually the better predictor of the text; its tokens were just harder because there were fewer of them.

InteractiveBits-per-byte convertertwo tokenizers, side by side

Per-token perplexity rewards tokenizers with many small tokens. Bits per byte does not. Set the two models up so their perplexities disagree with their BPB.

The companion code/lumen/eval.py computes held-out loss with a sliding window and reports nats per token, perplexity, and bits per byte, so that you can compare runs that use different tokenizers from the very first chapter.

Benchmarks: what they measure and how a base model is scored

Loss says how well the model predicts text. Benchmarks say whether it can do particular things. Each standard benchmark is a dataset plus a scoring rule, and the scoring rule matters as much as the data. There are two families of scoring for a base model, and you need both in your head before reading any leaderboard.

Log-likelihood scoring. For multiple-choice tasks, do not ask the model to answer. Instead, for each candidate answer, compute the log-probability the model assigns to that answer text given the question, and pick the candidate with the highest score. No generation, no parsing, works for a raw base model that has never been taught to answer questions.

Generation scoring. For tasks with a free-form answer (a number, a program), sample a completion from the model and check it: exact match against the reference, or run the tests. This needs the model to stop at the right place and format its answer, which base models are bad at unless you show them examples.

That is where few-shot prompting comes in. Prepend $k$ solved examples in the same format, and the base model continues the pattern. Five-shot MMLU means five example questions with answers precede the real one. The examples are fixed and drawn from a separate development split, so they are not the test questions.

MMLU

Massive Multitask Language Understanding (Hendrycks et al. 2020): about 14,000 four-choice questions across 57 subjects, from elementary mathematics to professional law. It measures broad world knowledge and reading. The standard base-model protocol is 5-shot with log-likelihood scoring of the answer letter: the prompt ends with "Answer:" and the model's log-probabilities for " A", " B", " C", " D" are compared. Random is 25%.

HellaSwag

Zellers et al. (2019): commonsense sentence completion. Given the start of a short scenario, choose the most plausible of four endings, where the wrong endings were adversarially generated to fool models. About 10,000 validation examples. Scored by log-likelihood of each full ending, usually length-normalized (more on that below). Random is 25%; it climbs early and smoothly in training, which makes it a useful signal for small models.

ARC

The AI2 Reasoning Challenge (Clark et al. 2018): grade-school science questions, split into an Easy set and a Challenge set of questions that simple retrieval methods got wrong. Four (occasionally three or five) options, scored by log-likelihood of the answer text, typically length-normalized, often 25-shot. ARC-Challenge is the one people report; it is the benchmark Llama 3 used as the target for its downstream scaling predictions.

GSM8K

Grade School Math 8K (Cobbe et al. 2021): about 8,500 word problems requiring two to eight arithmetic steps, with 1,319 in the test split. This is generation scoring: the model writes a chain-of-thought solution and the final number is extracted and compared exactly. The standard base-model protocol is 8-shot with worked solutions in the prompt. Base models score near zero for a long time in training and then climb, which makes it a late-moving and noisy signal.

HumanEval

Chen et al. (2021): 164 hand-written Python programming problems, each a function signature plus docstring, scored by running hidden unit tests on the generated function body. The metric is pass@k: the probability that at least one of $k$ samples passes. With $n$ samples of which $c$ pass, the unbiased estimator is $1 - \binom{n-c}{k}/\binom{n}{k}$. Zero-shot, generation, and with only 164 problems, very noisy.

BBH

BIG-Bench Hard (Suzgun et al. 2022): 23 tasks from BIG-Bench on which earlier models scored below the human average, covering logic, multi-step arithmetic, and tricky language. Scored by generation with 3-shot chain-of-thought prompts and exact match of the final answer. It is a reasoning-flavoured benchmark that base models do poorly on until they are large.

Scoring mechanics: multiple choice via log-likelihoods

Let us do the log-likelihood scoring properly, because a subtle choice inside it changes results by several points.

For each option $o_i$ with tokens $o_{i,1},\dots,o_{i,n_i}$, the model gives a log-probability of the whole option given the prompt:

$$s_i = \sum_{j=1}^{n_i}\log p\!\left(o_{i,j}\mid \text{prompt},\, o_{i,<j}\right)$$

Pick $\arg\max_i s_i$. This is the "acc" metric in the lm-evaluation-harness. The problem: $s_i$ is a sum of negative numbers, so a longer option is penalised simply for having more tokens. If the correct answer is "the water evaporates into the atmosphere" and a wrong one is "it rains", the wrong one has a head start of several nats.

Length normalization divides by the length, giving an average per-token (or per-byte) log-likelihood:

$$\tilde s_i = \frac{s_i}{n_i}$$

This is "acc_norm". The harness normalizes by the option's byte length rather than token count, to keep it tokenizer-independent, but the idea is the same. Neither choice is "right": raw likelihood is correct if the options are the same length; normalized is fairer when they differ. The important thing is to know which one a reported number used, because they can differ by five points or more on HellaSwag and ARC.

Worked example

Question: "Why is the sky blue?" Four options with total log-likelihood and token count: A "Rayleigh scattering of sunlight" ($-9.0$, 6 tokens), B "Paint" ($-4.5$, 2 tokens), C "Because it is" ($-6.0$, 3 tokens), D "Ocean reflection" ($-7.5$, 3 tokens).

Raw: B wins with $-4.5$, the shortest and wrong option. Normalized per token: A is $-1.5$, B is $-2.25$, C is $-2.0$, D is $-2.5$. A wins, correctly. The model "knew" the answer; the raw scoring rule hid it.

InteractiveMultiple-choice scoring simulatoredit likelihoods and lengths, toggle normalization

Four options, each with a total log-likelihood and a token count. See which one the scoring rule picks, and find settings where the two rules disagree.

Common confusion

"MMLU 5-shot" from two papers can mean different things: log-likelihood of the letter, log-likelihood of the full answer text, or generation with answer parsing; with or without normalization; with a chat template or without. Differences of several points between reports of the "same" benchmark on the "same" model are usually protocol, not model. Never compare numbers across papers without checking the protocol.

Contamination and decontamination

Now for the uncomfortable problem. The training set is a large fraction of the internet. The benchmarks are on the internet. If the test questions, or paraphrases of them, are in the training data, the score measures memory, not ability.

The standard defence is n-gram overlap decontamination. For each benchmark example, check whether any n-gram of it (GPT-3, Brown et al. 2020, used 13-grams; Llama 3 reports an 8-gram analysis) appears in the training corpus. Either remove the matching training documents before training, or flag the contaminated test examples and report scores on the clean subset. Llama 3 reports both the contamination rate per benchmark and the estimated performance gain from contamination, which is the honest way to present it.

N-gram matching misses paraphrases, translations, and questions that appear with reformatted whitespace, so it is a floor on contamination, not a measurement of it. It also cannot catch the subtler effect of benchmark-style synthetic data (see the advanced objectives chapter) that was never a literal copy of any test item.

Benchmarks saturate, and the move to harder sets

A benchmark stops being useful when the best models reach its ceiling, either because they are genuinely that good or because the annotation errors in the test set cap the achievable score. HellaSwag and ARC-Easy are near that point for frontier models; MMLU is close. The field responds by moving to harder sets: GPQA (Rein et al. 2023), graduate-level science questions written so that experts score around 65% and skilled non-experts with web access around 34%; MATH (Hendrycks et al. 2021), 12,500 competition problems; MMLU-Pro with ten options and harder questions. The treadmill will continue. For a small model you train yourself, saturation is not your problem; the opposite one is, and we come to it next.

Evaluation as a curve during training

A single evaluation at the end tells you where you landed. Evaluating every few thousand steps tells you the shape of the journey, and the shape is where the information is. But not all metrics are equally useful along the way.

Which metrics move early, and which are noise

Loss and bits per byte move smoothly from step one. Log-likelihood benchmarks with large test sets (HellaSwag, ARC-Easy, PIQA, LAMBADA) start climbing above chance early and rise steadily, so they are good progress signals even for models under a billion parameters. MMLU stays at chance (25%) for a long stretch and then lifts; for small models it is a flat line and tells you nothing. Generation benchmarks with exact match (GSM8K, HumanEval) sit near zero for most of a small run, and when they do move, they jump around from checkpoint to checkpoint because a formatting quirk can swing dozens of examples.

Practical rule: for tracking during training, watch loss, BPB, and two or three large log-likelihood benchmarks. Run the expensive generation benchmarks at milestones, and report them with error bars.

"Emergence" as a choice of metric

You will read that some abilities "emerge" suddenly at scale: flat at small sizes, then a sharp jump (Wei et al. 2022). Schaeffer et al. (2023) argued that much of this is an artefact of the metric. Exact match on a multi-digit arithmetic problem is all-or-nothing: the model gets zero credit until every digit is right, so a model whose per-digit accuracy improves smoothly shows a sudden jump in exact match once the product of per-digit accuracies crosses a threshold. Measure the same models with a continuous metric, such as token-level edit distance or the log-likelihood of the right answer, and the curve is smooth.

Worked example

A five-digit answer scored by exact match. If per-digit accuracy is 0.7, exact match is $0.7^5 = 0.17$. At 0.9 per digit it is $0.9^5 = 0.59$. At 0.97 it is $0.86$. The per-digit accuracy moved linearly; the exact-match score went from "barely works" to "mostly works" in a way that looks like a phase change. The lesson is not that emergence never happens, but that a sharp curve should make you ask what the metric is doing before you make a claim about the model.

model scale (log) → per-digit accuracy rises linearly from 0.5 to 1.0 score 01 continuous metric: per-digit accuracy (smooth) exact match on a 5-digit answer = accuracy⁵ ("emergent")
Figure 3. The same models, two metrics. Per-digit accuracy (teal) improves steadily with scale; exact match on a five-digit answer (amber) is the fifth power of it, so it stays near zero and then shoots up. The "emergence" is in the exponent, not in the model (after Schaeffer et al. 2023).

Small-scale proxies and scaling ladders

Before spending the compute on a large run, you want to know what it will do. The tool is a scaling ladder: train a sequence of small models with the same recipe, measure them, fit a trend, and extrapolate. The scaling-laws chapter does this for loss. Doing it for benchmarks is harder, because benchmark accuracy is bounded, noisy, and often flat at small scale.

Grattafiori et al. (2024) describe a two-step approach for Llama 3 (Section 3.2.1). First, fit how the negative log-likelihood of the correct answer on a benchmark decreases with training compute, using models from about 40M to 16B parameters trained with between $6\times10^{18}$ and $10^{22}$ FLOPs. That quantity is continuous and moves smoothly even when accuracy does not. Second, fit a sigmoid from that log-likelihood to accuracy, using the small models and older Llama 2 models as data points. Chain the two and you get a predicted accuracy for the 405B model on ARC-Challenge before training it; they report the prediction was close to the final result. The key move is the one from the previous section: predict a smooth quantity, then map it to the jumpy one.

Downstream versus upstream: does low loss transfer?

Loss is the "upstream" quantity; benchmarks are "downstream". Usually a lower loss means better benchmarks, and the relationship is tight enough that people use loss as the primary target. Gadre et al. (2024) showed that average downstream error across a suite of tasks is well predicted by held-out loss across a wide range of model sizes and over-training ratios.

But not always, and the exceptions are instructive. Two models trained on different data mixes can have the same held-out loss on a shared evaluation set and very different GSM8K scores, because one saw far more math. Loss on a broad mix averages over domains, and the benchmark asks about one. A model can also have lower loss and worse benchmark scores if the loss gain came from memorizing boilerplate. And a few tasks show inverse scaling, where larger models with lower loss do worse, typically because they imitate a common but wrong pattern more faithfully (McKenzie et al. 2023). Loss is the compass; benchmarks are the map; use both.

Practical evaluation

The lm-evaluation-harness

You do not have to implement any of the above yourself. EleutherAI's lm-evaluation-harness (Gao et al. 2021 onward) implements hundreds of tasks with fixed prompts, few-shot examples, and scoring rules, and runs them against any model that can return log-likelihoods or generations. It is the reference implementation behind most published base-model numbers and the Open LLM Leaderboard. Biderman et al. (2024), "Lessons from the Trenches", is the maintainers' account of why reproducible evaluation is hard: prompt formatting, tokenization of few-shot separators, and normalization choices all move scores.

Seeds and variance

Several sources of randomness sit inside an evaluation number. Which few-shot examples were chosen and in what order. The sampling temperature for generation tasks. The training seed of the model itself: two runs with identical hyperparameters and different seeds can differ by a point or two on MMLU-scale benchmarks and far more on HumanEval. When you compare two recipes, ideally compare across seeds, and at minimum fix everything but the recipe.

Confidence intervals: the binomial formula

Even with everything fixed, a benchmark score is an estimate of a "true" accuracy from a finite sample of $n$ questions. Each question is a coin flip with probability $p$ of success. The standard error of the observed accuracy $\hat p$ is:

$$\text{SE} = \sqrt{\frac{\hat p\,(1-\hat p)}{n}}, \qquad \text{95\% CI} \approx \hat p \pm 1.96\,\text{SE}$$

That is the normal approximation to a binomial proportion. It says the uncertainty shrinks with the square root of the number of questions, so four times the questions halves the interval. For small $n$ or accuracies near 0 or 1, the Wilson interval is more accurate, but the formula above is what you should be able to do in your head.

Worked example

GSM8K test has $n = 1{,}319$ questions. A model scores $\hat p = 0.70$. SE $= \sqrt{0.7 \times 0.3 / 1319} = \sqrt{0.000159} = 0.0126$. The 95% interval is $0.70 \pm 0.025$, so 67.5% to 72.5%. A second model at 71.5% is inside that interval: not a distinguishable improvement.

HumanEval has $n = 164$. At $\hat p = 0.50$: SE $= \sqrt{0.25/164} = 0.039$, so the interval is $\pm 7.7$ points. A "gain" from 50% to 55% on HumanEval is well within noise.

InteractiveBenchmark-noise explorerchange n and the true accuracy

200 simulated evaluation runs of a model whose true accuracy you set, each on n questions. The histogram is what you would observe; the bracket is the binomial 95% interval. Try n = 164 (HumanEval) versus n = 14,000 (MMLU).

Reporting

A useful evaluation report states, for every number: the benchmark and split, the number of examples, the shots and where they came from, the scoring rule and normalization, the decoding settings for generation tasks, the harness version, and a confidence interval or a standard error. If you compared two models, say whether the difference exceeds the interval. That is more words than a table cell, but a table of bare percentages without them is closer to marketing than measurement.

three layers of evaluation loss / BPBevery step, smoothtokenizer-free via BPBsays: predicting textcheap log-lik benchmarksHellaSwag, ARC, MMLUno generation neededwatch normalizationmedium generationGSM8K, HumanEval, BBHneeds few-shot formatnoisy, late-movingexpensive
Figure 1. Left to right: cheaper and smoother to more expensive and more informative about specific skills. Track the left column continuously, the middle column often, the right column at milestones and with error bars.
prompt (5-shot) Q: … A: BQ: … A: DQ: … A: AQ: … A: CQ: … A: B Q: Why is the sky blue?(A) … (B) … (C) … (D) …Answer: modelone forward pass log p(next token) " A" −1.9" B" −0.4 ← argmax" C" −2.7" D" −3.1 compare only these four
Figure 2. Log-likelihood scoring of a letter-answer benchmark like MMLU. The model never generates anything: the four candidate continuations are scored from one forward pass and the largest wins. Because the options are single tokens, length normalization is moot here; it matters for benchmarks whose options are sentences.
Symbols
$\mathcal{L}$ = mean loss, nats/token
$N_{\text{tok}}, N_{\text{bytes}}$ = tokens and bytes in the eval text
$s_i$ = option log-likelihood
$n$ = number of test questions
$\hat p$ = observed accuracy
STEP 1
Normalize the loss
Compute $\mathcal{L}$ on held-out text with long windows; convert to BPB $= \mathcal{L}/\ln 2 \times N_{\text{tok}}/N_{\text{bytes}}$ so tokenizers compare.
STEP 2
Score choices
For multiple choice, build the few-shot prompt, score each option's log-likelihood $s_i$, normalize by length if options differ in length, take the argmax.
STEP 3
Score generations
For free-form tasks, sample with fixed decoding settings, extract the answer with a fixed parser, exact-match or run tests.
STEP 4
Report with error
SE $= \sqrt{\hat p(1-\hat p)/n}$; report $\hat p \pm 1.96\,$SE, the protocol, and whether a difference clears the interval.

Practice

Exercise 1 — bits per byte on two tokenizers

Using code/lumen/eval.py, evaluate the same trained model checkpoint's held-out text with two different BPE vocabulary sizes from code/lumen/tokenizer.py (say 512 and 4096 merges; train a small model for each). Report nats per token, perplexity, and bits per byte for both. Which comparison is fair?

Solution sketch

The 4096-merge tokenizer produces fewer, longer tokens and a higher per-token loss. Bits per byte should be close between the two if the models are similarly good; any remaining gap is a real difference in modelling quality, not a tokenizer artefact. Count bytes from the UTF-8 encoding of the evaluation text, not characters.

Exercise 2 — a multiple-choice scorer

Write score_options(model, prompt, options) that returns, for each option, its total log-likelihood and its token count under the model from code/lumen/gpt2.py. Build a ten-question toy benchmark (any topic) with deliberately unequal option lengths, and compare accuracy with raw and length-normalized scoring, with 0 and 3 shots.

Solution sketch

Concatenate prompt and option, run one forward pass, and sum the log-softmax at the option positions only (the prompt positions are context, not scored). Divide by the number of option tokens for the normalized variant. With ten questions your standard error is around 15 points, so the exercise's real lesson is that you cannot conclude anything from ten questions; scale to a few hundred to see a stable difference.

Exercise 3 — how many questions do you need?

You want to detect a 2-point improvement on a benchmark where the baseline is 60%, with the interval half-widths not overlapping. Using the binomial formula, how many questions does each evaluation need? Check against the noise explorer above.

Solution sketch

Two non-overlapping intervals each of half-width 1 point need $1.96\sqrt{0.6\times0.4/n} \le 0.01$, so $n \ge (1.96^2 \times 0.24)/0.0001 \approx 9{,}220$ questions. That is why 2-point gains on HumanEval (164 questions) or GSM8K (1,319) are not evidence of anything on their own.

Check yourself
Model A has per-token perplexity 12 and model B has 16, but B's tokenizer produces 30% fewer tokens on the same text. Which is the better predictor of the text?
Perplexity is per token and tokens differ. Bits per byte charges per byte of text: with 30% fewer tokens, B's total surprise on the document may well be lower despite its higher per-token loss.
In log-likelihood scoring of a multiple-choice question, why does raw (unnormalized) scoring tend to favour short options?
Every token adds a negative number. Longer options accumulate more of them regardless of plausibility, which is why acc_norm divides by length.
Schaeffer et al. (2023) argue that many "emergent abilities" are…
Their point is about measurement: with a continuous metric the same models improve smoothly. The claim is not that scale does nothing, but that sharp curves demand a look at the metric first.
A model scores 50% on HumanEval (164 problems). The approximate 95% confidence interval is…
SE = sqrt(0.5 × 0.5 / 164) ≈ 0.039; 1.96 × 0.039 ≈ 0.077, so roughly ±8 points. A 5-point "improvement" on HumanEval is within noise.

Key takeaways

  • Held-out loss is the cheapest, smoothest signal; report bits per byte so that runs with different tokenizers can be compared.
  • Base models are scored two ways: log-likelihood of candidate answers (MMLU, HellaSwag, ARC) and few-shot generation with exact match or tests (GSM8K, HumanEval, BBH); the protocol moves scores by several points.
  • Length normalization of option likelihoods is a real choice (acc vs acc_norm) and changes who wins; always state which one you used.
  • Decontaminate with n-gram overlap and report contamination rates; expect benchmarks to saturate and the field to move to harder ones.
  • Track large log-likelihood benchmarks during training; generation benchmarks are late-moving and noisy. Apparent "emergence" often comes from all-or-nothing metrics; predict a smooth quantity and map it to accuracy, as Llama 3 did.
  • Every score has a binomial confidence interval of about ±1.96·sqrt(p(1−p)/n); on small benchmarks that is many points, so most small gains are noise.

Further reading