KL divergence and cross-entropy
Define KL divergence, prove it is nonnegative, and connect cross-entropy to maximum likelihood.
Training a classifier means making a predicted distribution match a true one. The gap between two distributions is measured by the KL divergence, and the quantity actually minimized in practice, cross-entropy, differs from it only by a constant. Minimizing cross-entropy turns out to be exactly maximum likelihood.
Cross-entropy
The cross-entropy of a distribution relative to is the expected surprise of outcomes drawn from but scored with :
It is the average number of bits to encode samples from the true using a code optimized for the model . If it reduces to the entropy . Using the wrong code costs extra bits, and that excess is the KL divergence.
KL divergence
The Kullback-Leibler divergence from to is the cross-entropy minus the entropy[1, 2]:
It is the expected log-ratio under . It quantifies the penalty for modeling with instead of the truth.
Nonnegativity (Gibbs' inequality)
Theorem. , with equality if and only if [3].
Proof. Write the divergence with a sign flip and apply Jensen to the concave logarithm:
The expectation inside is , so the bound is . Therefore , i.e. . Jensen is tight only when is constant, which with both summing to 1 forces .
Asymmetry
KL is not symmetric: in general, so it is not a distance. The two directions behave differently. is "mean-seeking": it is huge where has mass but does not, so minimizing it forces to cover all of 's support. is "mode-seeking": it lets concentrate on one mode. Variational inference minimizes the second; maximum likelihood, the first.
Cross-entropy loss is maximum likelihood
For classification, is the one-hot true label and the model's predicted class probabilities. The per-example cross-entropy is . Averaged over a dataset,
which is the negative average log-likelihood. Minimizing cross-entropy is maximizing likelihood. Since is fixed by the data, minimizing cross-entropy also minimizes : the model is pushed toward the true label distribution.
Check it on arrays
import numpy as np
rng = np.random.default_rng(14)
def kl(p, q):
p, q = np.asarray(p, float), np.asarray(q, float)
mask = p > 0
return np.sum(p[mask] * np.log(p[mask] / q[mask]))
def cross_entropy(p, q):
p, q = np.asarray(p, float), np.asarray(q, float)
mask = p > 0
return -np.sum(p[mask] * np.log(q[mask]))
def entropy(p):
p = np.asarray(p, float)
mask = p > 0
return -np.sum(p[mask] * np.log(p[mask]))
p = np.array([0.5, 0.3, 0.2])
q = np.array([0.4, 0.4, 0.2])
print("KL(p||q):", round(kl(p, q), 4), " >= 0")
print("KL(p||p):", round(kl(p, p), 4), " == 0")
print("H(p,q) - H(p):", round(cross_entropy(p, q) - entropy(p), 4),
" == KL(p||q):", round(kl(p, q), 4))
print("asymmetry: KL(q||p) =", round(kl(q, p), 4), "!= KL(p||q)")
# Cross-entropy loss == negative log-likelihood on one-hot labels
logits = rng.normal(size=(5, 3))
probs = np.exp(logits) / np.exp(logits).sum(axis=1, keepdims=True)
labels = rng.integers(0, 3, size=5)
ce = -np.log(probs[np.arange(5), labels]).mean()
print("mean cross-entropy loss:", round(ce, 4))KL is nonnegative and zero only against itself, the cross-entropy minus entropy identity holds, the two KL directions disagree, and the classification loss is the mean negative log-likelihood.
Exercises
Exercise 1. With and , compute and in bits by hand, and confirm they differ.
Solution
Step 1. Forward direction, :
With , this is bits.
Step 2. Reverse direction, :
With , this is bits.
Step 3. Both are positive, as Gibbs' inequality requires, and : KL is not symmetric.
Exercise 2. Show that the cross-entropy is minimized over exactly when , and that its minimum value is the entropy .
Solution
Step 1. Use the identity from the lesson, . The first term does not depend on , so minimizing over is minimizing .
Step 2. By Gibbs' inequality, with equality if and only if . So the cross-entropy is minimized precisely at .
Step 3. At that minimizer the divergence term vanishes and . The best a model can do is match the true distribution, and then it pays only the irreducible cost .
Exercise 3 (code). Sample-estimate the cross-entropy as the mean of over draws , and confirm it equals computed exactly.
Solution
import numpy as np
rng = np.random.default_rng(15)
p = np.array([0.5, 0.3, 0.2])
q = np.array([0.4, 0.4, 0.2])
# Monte Carlo cross-entropy: E_{X~p}[-log q(X)]
X = rng.choice(3, size=2_000_000, p=p)
ce_mc = -np.log(q[X]).mean()
H_p = -(p * np.log(p)).sum()
kl_pq = (p * np.log(p / q)).sum()
ce_exact = H_p + kl_pq
assert np.isclose(ce_mc, ce_exact, atol=2e-3)
print("cross-entropy MC:", round(ce_mc, 4), " H(p)+KL:", round(ce_exact, 4))The sampled cross-entropy matches , the decomposition the whole lesson rests on.
The next lesson uses KL to measure how much two variables tell you about each other: mutual information.
References
- [1]Cover, T. M., & Thomas, J. A. (2006). Elements of Information Theory (2nd ed.). Wiley. §2.3, relative entropy and cross-entropy. doi:10.1002/047174882X↩
- [2]Bishop, C. M. (2006). Pattern Recognition and Machine Learning. Springer. §1.6.1, relative entropy and its link to maximum likelihood.↩
- [3]MacKay, D. J. C. (2003). Information Theory, Inference, and Learning Algorithms. Cambridge University Press. §2.6, Gibbs' inequality and nonnegativity of the KL divergence.↩