Perplexity
Perplexity is your model's average surprise on text it has never seen, turned into a headcount. A score of 1.62 means it wavers among fewer than two live options at each step.
Why Does This Exist?
You train a model with next-token prediction and at every position it hands you a full distribution over the vocabulary. Staring at a few samples tells you nothing, but shipping without a number is worse. You need one score that says how well those distributions matched real text the model never trained on.
Perplexity is that score, and it's not a new invention. It is the training loss itself, reshaped into units you can picture. Where cross-entropy reports surprise in nats, a log-scale unit nobody feels, perplexity converts it into an effective headcount of options. A score of 1.62 says the model behaved as if it hesitated among fewer than two live candidates per step. A score of 50000 says it guessed blindly across a 50000 word vocabulary.
The one idea you need first is the negative log-probability. If the model gives the true next token probability , its surprise at that position is . Right and confident gives a tiny number, wrong or timid gives a large one. Perplexity just averages those surprises and undoes the log. This page covers that intrinsic number only. Task skill and factuality live in post-training evaluation, and confidence quality lives in LLM calibration.
Think of It Like This
Calling a friend's lunch order
You eat lunch with a friend every day for a month. Each morning you write down your guess for where they will want to go, split as six percentages across six spots. Some days you put 80 percent on tacos because Tuesday is taco day. Other days you split evenly because you have no clue.
At month end you score yourself. On days you put 80 percent on the right spot, you were barely surprised. On days you put 5 percent on it, you were stunned. Average that daily surprise, then convert it back into a headcount. If your score is 1.6, you behaved as if you dithered among fewer than two spots each morning. If it is 5.8, you behaved as if nearly all six spots were live every day.
Where it stops: you can learn your friend's habits perfectly and still eat badly. Perplexity rewards matching the pattern in front of you, not picking a good pattern. A friend who always picks the same greasy counter is easy to predict and scores well, even if the choice is poor.
How It Actually Works
Take held-out text with next-token positions. At position , the model sees the context and assigns some probability to whatever token actually came next, written . Here counts scored positions, is a token, and is your trained model with weights . The log is the natural log, so surprise is measured in nats.
Perplexity averages the surprise, then exponentiates:
In plain words: read off the probability given to each true token, take the negative log of each, average, and raise to that average. If you use log base 2 instead, you get the same idea in bits, and perplexity equals raised to the average bits. Same score, different ruler.
Why the exponent matters
Cross-entropy already averages surprise, so why add the ? Because logs compress differences your intuition needs. An average surprise of 0.48 nats versus 2.99 nats looks like a small gap on paper, but the first means fewer than two live options per step while the second means twenty. Exponentiating restores the linear headcount. That's the whole trick, and it is why a drop from 20 to 10 matters far more than a drop from 110 to 100, even though both shave the same 10 points.
Worked example: four tokens score 1.62
Say your model reads four unseen positions and gives the true next tokens probabilities . You have seen nothing else. That list is the entire fixture, and the diagram above draws exactly these four bars.
Turn each into surprise with , rounded to two places:
Add them: displayed, before rounding. Divide by positions: , shown as nats. Exponentiate: .
So this model scores about 1.62. Read it as a headcount: at each step it behaved as if torn among roughly 1.6 equally likely tokens. For contrast, a model giving to every true token scores , or twenty live options. Same formula, far more confusion.
What the number means, and what it costs
A perplexity of means the model gave probability to every true token, perfect and never observed on real text. A perplexity near the vocabulary size means guessing uniformly, the floor you must beat. Real models sit between, and lower is better only when everything else is fixed: same tokenizer, same test text, same token count. For background on surprise itself, see entropy.
The trade is scope for convenience. You get a cheap single number straight from the loss, no judges or tasks needed, but you buy silence on everything beyond pattern match. Perplexity assumes the held-out text looks like the world you care about, that you scored enough tokens for the mean to settle, and that no test sentence leaked into training. Don't use it to judge truth, helpfulness, or style. A model can predict fluent nonsense with total confidence and score beautifully, which is exactly why teams pair it with task tests and contamination checks such as benchmark contamination.
Code
This snippet recomputes the fixture above, so you can see the average-then-exponentiate step instead of taking it on faith.
import numpy as np
def perplexity_from_probs(probs: list[float]) -> float: """Perplexity from the true-token probs at each position.""" arr = np.asarray(probs, dtype=float) avg_neg_log_prob = float(-np.log(arr).mean()) return float(np.exp(avg_neg_log_prob))
fixture = [0.80, 0.50, 0.90, 0.40]print(f"{perplexity_from_probs(fixture):.2f}") # -> 1.62print(f"{perplexity_from_probs([0.05, 0.05, 0.05, 0.05]):.2f}") # -> 20.00The first line prints , the number the worked example derived by hand. The second shows a uniformly confused model at , since . Change one input probability and rerun: you'll feel how harshly a single near-zero probability punishes the mean.
Watch Out For
Comparing scores across different tokenizers
Splitting the same sentence into fewer, larger tokens shrinks and reshuffles every , so the average moves for bookkeeping reasons alone. You will see a model with a chunky tokenizer post a lower number and conclude it predicts better, when the tokenization did half the work.
Symptom: a cross-model leaderboard where the ranking flips whenever anyone re-tokenizes the test set. Fix: compare perplexity only under one identical tokenizer and test split, and carry enough text that the mean is stable. When tokenizers must differ, switch to bits per byte or bits per character instead of per-token perplexity.
Reading low perplexity as low falsehood
Perplexity checks fit to a text distribution, never truth against the world. A model soaked in a repeated myth predicts that myth fluently and scores well. Memorized test text does the same: surprise collapses because the model recalls, not because it reasons.
Symptom: a model with glowing perplexity still invents dates and citations, or its score drops suspiciously far on one specific benchmark. Fix: treat perplexity as the intrinsic check and add extrinsic ones, task accuracy plus a leakage probe. If one split looks too good, suspect contamination before you celebrate.
The Quick Version
- Perplexity is exponentiated average surprise: of the mean over true next tokens on unseen text.
- Read the result as a headcount of live options per step, where 1 is perfect and the vocabulary size means blind guessing.
- Four true-token probabilities of 0.8, 0.5, 0.9 and 0.4 average to 0.48 nats of surprise and score about 1.62.
- Perplexity inherits the training loss, so it is cheap and intrinsic, with no say on truth or task skill.
- Scores compare only under the same tokenizer and test set, since token splits reshape the average.