4. Probability and information
Why this layer exists
The last thing a language model computes is not a token. It is a vector of real numbers, one per vocabulary entry, called logits, which a softmax turns into a probability distribution over the next token. Everything downstream consumes that distribution. Generation draws a token from it, after reshaping it with temperature, top-k or top-p (chapter 12). Training compares it with the token that actually came next and adjusts the weights to raise that token’s probability; the quantity minimised is a cross-entropy (chapter 8). The number reported when models are compared on held-out text is perplexity, the same cross-entropy passed through an exponential, and it is how chapter 14 measures what quantization costs. When you send "logprobs": true to llama-server’s OpenAI-compatible /v1/chat/completions, the values that come back are natural logs of entries of that distribution.
KL divergence measures how far one distribution is from another, and it appears wherever one model is trained against another: the penalty that keeps a fine-tuned model near its starting point in RLHF-style training, the objective DPO is derived from (chapter 13), and distillation, where a small model is trained to match a large one’s outputs. This chapter builds all of these from the definition of a distribution, and the lab fits a first language model to data and measures its perplexity.
Mechanism
Distributions
A sample space is the set of things that can happen; for next-token prediction it is the vocabulary, token ids, and every sample space in this chapter is finite. A probability distribution over it assigns each outcome a number with
As a vector, has shape (V,): a vector in the sense of chapter 2, restricted to non-negative entries that sum to 1. A distribution over a finite set with one free probability per outcome is a categorical distribution, and it is what a language model outputs at each position.
Two variables and have a joint distribution , the probability that and together. Summing out one variable gives the marginal of the other, . The conditional distribution of given restricts to the cases where and renormalises:
A language model is a conditional distribution, , one categorical per context. and are independent if for every pair, equivalently : knowing says nothing about . Exercise (e) measures how far co-occurring words are from independence.
Expectation and variance
A random variable attaches a number to each outcome. Its expectation under is the probability-weighted average
the dot product of with the vector of values , both of shape (V,). Expectation is therefore linear, , because the dot product is.
From here on, name a random variable by a capital letter, , and work directly with the values it takes and their probabilities , so that : the same weighted average, summed over values instead of outcomes. The variance measures spread around the mean . Expanding the square and using linearity,
For independent and the expectation of the product factors, because the joint probability does:
Expanding gives , and the last term vanishes for independent variables: variances of independent terms add. Two consequences come back later. A sum of independent terms of variance has variance , so its standard deviation grows as , not ; chapter 9 uses this to set a layer’s initial weights. And since scaling a variable by scales its variance by , the average of independent draws has variance : averages concentrate around the expectation, with spread shrinking as . That is why an average over a held-out set estimates the expectations the definitions below are written in.
Logits and softmax
A network’s last layer is an affine map (chapter 3), and its output , shape (V,), can hold any real numbers. Exponentiating makes every entry positive and dividing by the total makes them sum to 1. That is the softmax:
shape (V,) in and out. Every output is strictly positive, and since is increasing, softmax preserves the order of its inputs. Taking logs,
so the logits are log-probabilities up to one constant shared by every entry. That constant does not matter. Subtract any from every logit; since ,
because the common factor comes out of the sum and cancels. Softmax sees only differences between logits.
That invariance is what makes softmax computable. The largest float64 is about , whose natural log is 709.78, so overflows to inf for ; the limit is 88.72 in float32 and 11.09 in float16. Logits of 1000, 1001 and 1002 have a perfectly good softmax, (0.090, 0.245, 0.665), but computed as written every exponential is inf, inf / inf is nan, and numpy returns [nan nan nan]. Choose . After the shift the largest logit is 0, so the largest exponential is 1 and none can overflow; the sum contains that 1, so the division is safe. Shifted logits below about still underflow: their exponentials, below about , round to 0. As a probability that is 0 for any practical purpose; its log is not, and the walkthrough shows how to keep it. For logits of shape (B, T, V) the max and the sum are taken along the last axis, giving shape (B, T, 1), which broadcasts back against (B, T, V) by the rules of chapter 3.
Surprise
How surprising is an outcome of probability ? Call the answer and ask three things of it: it depends only on ; it decreases as grows, with a certain event carrying none; and for independent events, whose joint probability is a product, surprises add:
satisfies all three, and it is the only choice up to the base. Write for ; the product rule becomes . Applied repeatedly it gives for positive integers , and with , for every positive rational. A monotone function that matches the line at every rational matches it everywhere, since every real is squeezed between rationals on both sides. So , and the constant only sets the unit.
is the surprisal (or information content) of the outcome. With the unit is the bit: a fair coin flip carries bit. With the natural log it is the nat, and the coin carries nats. Converting is a constant factor, , so 1 nat is bits. In this book without a base is the natural log, the one np.log computes and training losses are reported in. An outcome of probability 0.01 carries 4.605 nats, or 6.644 bits.
Entropy
The entropy of a distribution is its expected surprise:
a scalar for of shape (V,). A term with is taken as 0, which is the limit: with , , and the exponential beats the linear factor as .
Entropy is 0 exactly when one outcome has probability 1: every term is then or , both 0, and otherwise some lies strictly between 0 and 1 and contributes a positive term. The uniform distribution over outcomes has entropy , and the KL section proves no distribution on outcomes has more. For two outcomes with probabilities and the entropy is a curve:
It peaks at with nats (1 bit) and falls steeply near the ends: a coin that lands heads 90% of the time still carries 0.325 nats per flip, nearly half the maximum, while one at 99% carries 0.056.
Entropy’s meaning is compression. For symbols drawn independently from , no uniquely decodable code averages fewer than bits per symbol (entropy in bits); for such codes this lower bound follows from McMillan’s inequality (1956). Shannon’s source coding theorem (“A Mathematical Theory of Communication”, 1948) supplies the other direction: coding one symbol at a time can get within 1 bit of , and coding long blocks of symbols together gets arbitrarily close per symbol. The ideal codeword for outcome has bits. When those are integers the ideal is exact: four symbols with probabilities get the prefix-free codewords 0, 10, 110, 111, with average length
against 2 bits for a fixed-width code.
Cross-entropy
Now code data from with codeword lengths designed for a different distribution . The expected length is the cross-entropy
with both vectors of shape (V,): the expectation is over the truth, the surprise measured by the model. The fixed-width code above is uniform, , and bits against . Cross-entropy is infinite if for an outcome with : an outcome with no codeword cannot be sent at any length.
This is a language model’s training loss. At one position the “true distribution” is the token that actually came next, : a one-hot with . The sum has one nonzero term,
the surprisal the model assigned to what happened. Averaged over the positions of a batch, it is the loss minimised in chapter 8.
KL divergence and Gibbs’ inequality
The extra cost of coding -data with a -code is
the Kullback–Leibler divergence of from , with terms where counted as 0. In the four-symbol example it is bits.
Gibbs’ inequality: , with equality only when . The proof needs one fact:
Let . Its derivative is negative for and positive for , so has its minimum at , where , and is positive everywhere else.
If for some with , the divergence is and there is nothing to prove. Otherwise let be the set of outcomes with , and apply the fact with :
The last step uses , since holds all of ‘s mass, and . Equality needs both inequalities tight: the first forces on , the second forces to have no mass outside , so . Three consequences:
- No code beats the truth: . A model’s cross-entropy on data is bounded below by the entropy of the process that generated it, and reaches the bound only by matching the process.
- Uniform has maximum entropy. For uniform on outcomes, .
- KL is not a distance. It is not symmetric: for and , nats and . Exercise (c) shows what each order penalises.
Maximum likelihood
Usually the distribution is unknown and there is data instead: samples , assumed drawn independently from an unknown categorical. Which distribution , shape (V,), best explains them? Its likelihood is the probability it gives the observed data. Independence makes that a product, and grouping equal outcomes turns it into powers of the counts (the number of samples equal to , so ):
Maximum likelihood picks the that makes the data most probable. Since the log is increasing, maximise the log-likelihood instead, which has the same maximiser and does not underflow:
The maximisation is constrained, ; without that, grows without bound. The tool for an equality constraint is a Lagrange multiplier, and chapter 2’s geometry is enough to build it.
Assume first that every . Then if any , so a maximum has every . Move it by a small step , shape (V,). To first order,
where , shape (V,), collects the partial derivatives , each the ordinary derivative of with the other coordinates held fixed (chapter 5 treats these properly). The step keeps the constraint only if , that is, for the all-ones vector : allowed steps are exactly those orthogonal to . At a maximum for every allowed step; if it were positive, a small step along would increase , and if negative, a step along would.
That forces to be a multiple of . Write with the mean of its entries, so that . Then is an allowed step, and , so and
The scalar is the Lagrange multiplier: at a constrained maximum the gradient points straight out of the constraint surface, so no allowed move improves the objective. The usual packaging is with every partial derivative set to zero; is the condition above and is the constraint.
Here the condition reads , so . Summing and using the constraint, , so and
The maximum-likelihood estimate of a categorical is the normalised counts. An outcome with does not appear in at all, so probability placed on it is taken from outcomes that do appear, and the maximum puts 0 there, which the formula also gives. The multiplier argument locates the stationary point; Gibbs’ inequality shows it is the global maximum, and what maximum likelihood is doing.
Maximising likelihood is minimising cross-entropy
Let , shape (V,), be the empirical distribution of the data, . Dividing the log-likelihood by ,
Maximising likelihood is minimising the cross-entropy from the empirical distribution to the model. Since and is fixed by the data, it is also minimising , which Gibbs says is zero, its minimum, exactly at .
The same identity holds for a model with context. The average of over the positions of a text is the negative log-likelihood (NLL) per token, and it is the cross-entropy loss of the previous section averaged over positions. A network cannot set each conditional freely, since all of them come out of the same weights, so there is no closed form and the minimisation is done by gradient descent (chapter 5). The objective is the same.
Zero probabilities and smoothing
Maximum likelihood trusts the sample completely. An outcome absent from draws gets , and if it turns up in new data the likelihood of that data is 0 and its NLL infinite. With a large vocabulary and a small sample this is the normal case. Add- smoothing adds a pseudo-count to every outcome before normalising:
where the denominator is . With this is Laplace’s rule. Every outcome gets at least . The price is a pull toward uniform, which matters when is comparable to and vanishes when ; the lab shows both regimes. A softmax has the protection built in, since for every real : a neural language model never assigns exactly zero probability, except by floating-point underflow.
Perplexity
NLL in nats per token is hard to read. Its exponential is not:
using and turning the exponential of a sum into a product. Perplexity is the reciprocal of the geometric mean of the probabilities the model gave the tokens that occurred. A uniform model over outcomes has NLL and perplexity exactly , which fixes the reading: perplexity means the model is, on average in log space, as uncertain as a uniform choice among options, its effective branching factor. It is at least 1, reached only by a model that gives every occurring token probability 1.
Perplexity does not depend on the log base, since ; the NLL does. The trap is the unit of text: per-token NLL and perplexity are comparable only between models that share a tokenizer and a test set, because a tokenizer that splits the same text into more tokens spreads the same total surprise over more positions. Chapter 14 compares a model with its own quantized copy, which shares the tokenizer, so the comparison is sound.
Walkthrough
The reference module is py/tinygpt/prob.py. All logs are natural, so every function returns nats.
def softmax(logits, axis=-1):
"""exp(z_i) / sum_j exp(z_j) along axis, computed after subtracting the max for stability."""
z = np.asarray(logits, dtype=np.float64)
z = z - z.max(axis=axis, keepdims=True)
e = np.exp(z)
return e / e.sum(axis=axis, keepdims=True)
keepdims=True keeps a size-1 axis where the max and sum were taken: for logits of shape (B, T, V) and axis=-1, both have shape (B, T, 1) and broadcast back across the last axis, one per row. Without it the max would have shape (B, T), which usually fails to broadcast against (B, T, V). The dangerous case is a square (V, V) input, where a (V,) max broadcasts as a row without complaint and subtracts row ‘s maximum from column : a different constant for each entry of a row, which softmax is not invariant to.
A loss needs log-probabilities, and np.log(softmax(z)) loses them when a probability underflows: the logits (0, -800) have log-probabilities (0, -800) to within rounding, but their softmax is (1.0, 0.0) and its log is (0, -inf). Computing directly, the mechanism’s log-softmax with the same shift, returns -800 exactly. Code that computes a loss from logits should use that form.
def entropy(p):
"""H(p) = -sum p_i log p_i in nats, with 0 log 0 taken as 0."""
p = _distribution(p)
nz = p > 0
return float(-(p[nz] * np.log(p[nz])).sum())
def cross_entropy(p, q):
"""H(p, q) = -sum p_i log q_i: the average code length when data from p is coded for q."""
p, q = _distribution(p), _distribution(q)
support = p > 0
if np.any(q[support] == 0):
return math.inf
return float(-(p[support] * np.log(q[support])).sum())
def kl(p, q):
"""KL(p || q) = H(p, q) - H(p): the extra nats paid for using q when the truth is p."""
return cross_entropy(p, q) - entropy(p)
entropy and cross_entropy pass their arguments through _distribution, a private helper just above the listing, which converts to float64 and raises ValueError unless the input is one-dimensional, has no negative entry, and sums to 1 within . The tolerance allows for rounding: a computed softmax need not sum to exactly 1. The check matters because none of these formulas fails loudly on a non-distribution: of [0.5, 0.6] is a finite number, just not an entropy.
The mask nz = p > 0 implements ; without it, 0.0 * np.log(0.0) is 0.0 * -inf, which is nan, and one impossible outcome would poison the sum. cross_entropy restricts both vectors to the support of for the same reason, and returns math.inf explicitly when is zero anywhere on it. kl is cross-entropy minus entropy, the first form in the derivation, so the infinite case passes through: inf - H is inf. When the divergence is tiny compared with the entropies, the direct form is more accurate, since subtracting two nearly equal floats keeps only the digits in which they differ; the tests compare kl(p, p) with zero to a tolerance for that reason.
def fit_categorical(samples, vocab_size, alpha=0.0):
"""Maximum-likelihood (alpha=0) or add-alpha smoothed estimate of a categorical distribution."""
counts = np.bincount(np.asarray(samples, dtype=np.int64), minlength=vocab_size).astype(np.float64)
counts += alpha
return counts / counts.sum()
def nll(probs, samples):
"""Mean negative log-likelihood of samples under probs, in nats per sample."""
probs = np.asarray(probs, dtype=np.float64)
p = probs[np.asarray(samples, dtype=np.int64)]
if np.any(p == 0):
return math.inf
return float(-np.log(p).mean())
def perplexity(probs, samples):
"""exp(NLL): the effective number of equally likely choices the model is confused between."""
return math.exp(nll(probs, samples))
fit_categorical is the maximum-likelihood result plus the pseudo-count. np.bincount counts occurrences of each integer, and minlength=vocab_size extends the result to the whole vocabulary, so unseen ids get count 0. Samples must be ids in [0, vocab_size); bincount silently lengthens its output for a larger id rather than raising. Adding alpha everywhere and dividing by the new total is the smoothing formula.
nll gathers each sample’s probability with one indexing operation, probs[samples], shape (N,), and checks for a zero before taking any log, so an impossible sample returns math.inf without a divide-by-zero warning. perplexity is math.exp of that, and math.exp(math.inf) is inf, so the zero case needs no special code.
Exercises
(a) What is the entropy of a fair six-sided die, in bits and in nats?
Answer
The die is uniform on 6 outcomes, so the six terms sum to nats, or bits; the ratio is . By consequence 2 of Gibbs’ inequality this is the maximum for any six-outcome distribution.
(b) Show that for any scalar , but in general for a scalar . What does scaling do as and as ?
Answer
The shift is the mechanism’s derivation: , and cancels between numerator and denominator. Scaling does not cancel. The ratio of two outputs, in which the denominator does cancel, shows what it does:
Softmax turns logit differences into probability ratios, and scaling by raises every ratio to the power . With :
s = 0.5 (0.1863, 0.3072, 0.5065)
s = 1 (0.0900, 0.2447, 0.6652)
s = 2 (0.0159, 0.1173, 0.8668)
s = 10 (0.0000, 0.0000, 1.0000) to four places
As , every ratio against the largest logit, with a negative exponent, goes to 0 and the distribution collapses onto the argmax (split evenly among ties). As , every ratio goes to 1 and the distribution approaches uniform. This is temperature: sampling from is , so low temperature sharpens toward greedy decoding and high temperature flattens. Chapter 12 builds the sampler around it.
(c) Let and . Compute and , and explain why they differ.
Answer
In the expectation is over , half of whose samples are outcome 2, which nearly rules out: each costs nats of excess surprise. In the expectation is over , which almost never produces outcome 2, so that region barely counts; what remains is a moderate penalty for being overconfident about outcome 1.
In general, with the truth first, punishes the model for giving low probability to anything the truth produces (infinitely, for zero), so minimising it over spreads mass to cover everything does. punishes the model for putting mass where has little and ignores what does where does not go. Maximum likelihood minimises the first kind, with the data first. The RLHF penalty that keeps a policy near its reference model is usually written the second way, with the policy first and estimated on the policy’s own samples.
(d) A coin lands heads with unknown probability . In flips you see heads. Derive the maximum-likelihood by differentiating the log-likelihood.
Answer
The flips are independent, so the likelihood is and
Differentiate, using by the chain rule, and set the derivative to zero:
For the second derivative, , is negative on all of , so this is the maximum; for or , is monotone and the maximum is at the endpoint the formula gives. This is the categorical result with . No multiplier was needed because writing the probabilities as and builds the constraint into the parametrisation.
(e) Chapter 2 found that raw co-occurrence counts make cat and king look similar (cosine 0.878) because both rows are dominated by the columns for the, a, . and the adverbs. The pointwise mutual information of a word and a context word ,
is the log of how much more often they co-occur than they would if independent, and positive PMI clips it at zero: . Compute PPMI from chapter 2’s co-occurrence matrix of py/data/tiny-corpus.txt (window 2) and compare the nearest results with those from the raw counts.
Answer
Normalise the count matrix into a joint distribution over (word, context) pairs, take its two marginals, and compare. Save this as, for example, /tmp/ppmi.py and run it from py/ with PYTHONPATH=. uv run python /tmp/ppmi.py:
import pathlib
import numpy as np
from tinygpt.vectors import cooccurrence, nearest
tokens = pathlib.Path("data/tiny-corpus.txt").read_text().split()
vocab, counts = cooccurrence(tokens, window=2)
joint = counts / counts.sum() # (V, V): p(w, c)
pw = joint.sum(axis=1, keepdims=True) # (V, 1): p(w)
pc = joint.sum(axis=0, keepdims=True) # (1, V): p(c)
with np.errstate(divide="ignore"):
pmi = np.log(joint / (pw * pc)) # (V, V); log 0 = -inf
ppmi = np.maximum(pmi, 0.0)
for name, m in [("counts", counts), ("ppmi", ppmi)]:
print(name)
for word in ["king", "cat", "quickly", "the"]:
hits = nearest(m, vocab, word, k=3)
print(f" {word:8}", " ".join(f"{w} {s:.3f}" for w, s in hits))
Here . pw * pc broadcasts (V, 1) against (1, V) into the (V, V) matrix , the joint distribution the pairs would have under independence; since the count matrix is symmetric, the two marginals hold the same numbers. Pairs that never co-occur have PMI , which the clip removes along with every other negative value. Output:
counts
king queen 1.000 prince 0.999 dog 0.879
cat dog 0.999 bird 0.999 queen 0.879
quickly quietly 0.998 . 0.935 queen 0.726
the a 0.999 bird 0.557 king 0.556
ppmi
king queen 0.999 prince 0.998 quickly 0.721
cat dog 0.998 bird 0.998 quietly 0.734
quickly quietly 0.968 prince 0.725 queen 0.725
the a 0.968 bites 0.658 chases 0.640
The within-group neighbours survive and the cross-group similarity collapses: the cosine of cat and king falls from 0.878 to 0.098, and no animal is in king‘s top three. The rows show why. In king‘s PMI row, the scores 0.33 and a 0.32, while the royal verbs commands, rules and summons score 1.15 to 1.22: the appears near everything, so it appears near king only a little more often than its frequency predicts, while a royal verb appears near king far more often than chance. PMI measures association relative to frequency, which raw counts could not separate.
Two effects remain. king‘s third neighbour is now quickly: an adverb sits between subject and verb, so it has positive PMI with every verb, including the three royal ones that king‘s row is built from; cat finds quietly the same way. And quickly no longer counts . as a neighbour (0.935 under counts, 0.250 under PPMI). Clipping is not only a way to dispose of : a negative PMI claims two words avoid each other, which takes far more data to establish than a positive association, and in a sparse count matrix the negative estimates rest on small counts.
(f) A model has perplexity 20 on held-out text, with a vocabulary of 50,000 tokens. What does that mean operationally?
Answer
The NLL is nats, or bits, per token, and the geometric mean of the probabilities given to the tokens that actually came next is . The model is, on average in log space, as uncertain as a uniform choice among 20 tokens, against 50,000 (NLL nats, 15.61 bits) for a model that knows nothing. With arithmetic coding, it would compress this text to about 4.32 bits per token.
It does not mean the right token is always in the top 20. A geometric mean of 0.05 is compatible with many tokens predicted near probability 1 (the rest of a common word, a closing bracket) and a few near (a name, a number). And it is tied to the tokenizer: per-token perplexity measures surprise per token, and a tokenizer that cuts the same text into fewer, longer tokens puts more of the text, and more of the surprise, into each one.
Lab
Implement every function in py/labs/ch04/starter.py, then run
make lab CH=04 IMPL=mine
until it passes. Read py/labs/ch04/test_lab.py first. It pins what the prose leaves open: softmax must give the same result for logits (1, 2, 3) and (1001, 1002, 1003) with no inf or nan, and must work along the last axis of a matrix; entropy must raise ValueError for a vector that does not sum to 1 and for one with a negative entry even when it does; cross_entropy must return math.inf when misses part of ‘s support; fit_categorical must give for samples [0, 0, 1, 2] with and ; and perplexity must be , to within rounding, for a uniform model and inf for a sample the model gives probability 0.
Then fit the simplest language model that learns anything from data: one categorical distribution over words, the unigram model, which predicts every token the same way regardless of context. Save this script outside the repository, for example as /tmp/unigram.py:
import math
import pathlib
from tinygpt.prob import entropy, fit_categorical, perplexity
tokens = pathlib.Path("data/tiny-corpus.txt").read_text().split()
vocab = sorted(set(tokens))
ids = [vocab.index(t) for t in tokens]
cut = int(0.9 * len(ids))
train, test = ids[:cut], ids[cut:]
print(len(train), "training tokens,", len(test), "held-out tokens,", len(vocab), "words")
for n in [len(train), 40]:
for alpha in [0.0, 1.0]:
probs = fit_categorical(train[:n], len(vocab), alpha=alpha)
h = entropy(probs)
print(
f"train {n:5d} alpha={alpha:.0f} entropy {h:.4f} nats ({h / math.log(2):.4f} bits)"
f" held-out perplexity {perplexity(probs, test):.4f}"
)
and run it from py/ with PYTHONPATH=. uv run python /tmp/unigram.py. The first 90% of the token stream is the training set and the last 10% is held out. The vocabulary comes from the whole corpus so every held-out word has an id; in this corpus every held-out word also occurs in training. The script fits on all the training tokens and then on only the first 40, each with and . Change the import to from labs.ch04.starter import entropy, fit_categorical, perplexity to run yours; the output must be identical:
11998 training tokens, 1334 held-out tokens, 17 words
train 11998 alpha=0 entropy 2.6045 nats (3.7576 bits) held-out perplexity 13.5865
train 11998 alpha=1 entropy 2.6052 nats (3.7585 bits) held-out perplexity 13.5864
train 40 alpha=0 entropy 2.4329 nats (3.5099 bits) held-out perplexity inf
train 40 alpha=1 entropy 2.6578 nats (3.8344 bits) held-out perplexity 14.9375
Explain each pair of lines before moving on.
- With all the training data, smoothing makes no visible difference. Every word occurs at least 275 times in the 11,998 training tokens (
summonsis the rarest). One pseudo-count per word adds 17 to a total of 11,998 and moves the held-out perplexity in the fourth decimal place: the regime. - The numbers agree with the theory. The entropy, 2.6045 nats, is below the 17-word maximum because
a,.andtheaccount for 45% of the training tokens. Gibbs’ inequality bounds the held-out score from below by the held-out text’s own entropy: the held-out tokens’ empirical distribution has entropy 2.5968 nats, perplexity 13.42, and no unigram model can score better on them. The fitted model scores 13.59, a cross-entropy of 2.6091 nats; the 0.0122-nat gap is , the cost of the held-out frequencies differing slightly from the training ones. A uniform model would score 17. Word frequency alone cuts the effective branching factor from 17 to 13.6. - With 40 training tokens, maximum likelihood fails outright. The first 40 tokens contain 14 of the 17 words;
chases,quietlyandsniffsare missing. With they get probability 0, they occur in the held-out set, and the perplexity is infinite. With , 17 pseudo-counts against 40 real tokens pull hard toward uniform, each missing word gets , and the perplexity is 14.94: worse than the full-data model, better than uniform, finite. - The small unsmoothed model is also overconfident. Its entropy, 2.4329 nats, is below the full-data value: this small sample makes the distribution look more concentrated than it is, and maximum likelihood takes it at its word. Smoothing pushes the entropy the other way, to 2.6578, because it pulls toward uniform.
The language models of chapters 8, 9, 11 and 14 are scored the same way: fit on one part of the data, report perplexity on another. Chapter 8’s bigram model conditions on the previous token and should beat 13.59 on this corpus by a wide margin (an add-one bigram fitted on the same split scores about 3.9), because the grammar that generated the corpus makes most next words predictable from the one before.
Further reading
- Claude E. Shannon, “A Mathematical Theory of Communication” (1948). Entropy, the source coding theorem, and statistical approximations to English text built from letter and word frequencies.
- Thomas M. Cover and Joy A. Thomas, Elements of Information Theory (2nd ed., 2006), chapter 2. Entropy, relative entropy, and the inequalities between them, with proofs.
- David J. C. MacKay, Information Theory, Inference, and Learning Algorithms (Cambridge University Press, 2003), chapters 2 and 4. Probability, entropy and the source coding theorem, with many worked exercises.
- Kenneth Ward Church and Patrick Hanks, “Word Association Norms, Mutual Information, and Lexicography” (1990). Pointwise mutual information applied to word co-occurrence in a corpus, the basis of the reweighting in exercise (e).