Cross-Entropy
The price you pay for being confidently wrong: it reads off the probability your model gave the correct answer and charges you the negative logarithm of it.
Why Does This Exist?
Classification needs a loss that punishes confident mistakes far harder than hesitant ones, and accuracy cannot do it. A model that says 51 percent for the right class and one that says 99 percent both count as correct and score identically. There is no gradient to follow, so there is nothing to train on.
Cross-entropy fixes exactly this. A prediction of on the right answer costs . A prediction of on it costs , over four hundred times as much. Being confidently wrong is expensive, being tentatively wrong is survivable, and the resulting slope points somewhere useful.
It is also the principled choice rather than a convenient one: minimising cross-entropy is mathematically identical to maximum likelihood estimation under a categorical assumption. It is not a heuristic that happens to work. It is what the probability theory tells you to do.
Think of It Like This
A bookmaker settling up
You are a bookmaker who posted odds on a three-horse race. Your posted probabilities are your prediction. One horse wins.
The settlement rule is simple: you pay the negative logarithm of the probability you gave the horse that actually won. Nothing else on your board matters.
Post on the winner and you pay . Post and you pay . Post and you pay almost nothing. Post a flat zero on the winner and you owe infinity, which is the mathematics telling you that declaring something impossible and watching it happen is unrecoverable, not small.
Two consequences follow. Your best strategy is to post odds matching your true beliefs, since exaggeration eventually costs more than it gains. And because your probabilities total one, generosity to one horse means stinginess elsewhere. There is no hedge.
How It Actually Works
Cross-entropy measures the average surprise of using distribution to describe outcomes actually drawn from :
In plain words: weight the surprise of each outcome under your predicted distribution by how often it truly happens under . Compare entropy with : the only change is that the logarithm is taken of rather than . Same average surprise, computed with the wrong probabilities.
Why the formula collapses to one term
For classification the true distribution is one-hot: the correct class has probability and every other class has . Every term where vanishes, and the single surviving term has :
In plain words: the loss is the negative log of the probability assigned to the right answer, full stop. Wrong-class probabilities never appear in the formula. They matter only indirectly, because the softmax forces probabilities to total , so raising a wrong class lowers the right one.
Its relationship to entropy and KL divergence
Cross-entropy decomposes cleanly:
In plain words: the cost of using splits into the uncertainty genuinely present plus the extra paid for being wrong. Since depends only on the data and not on the model, minimising cross-entropy and minimising KL divergence are the same optimisation.
This also explains why the loss rarely reaches zero on real data. Its floor is , the irreducible uncertainty in the labels. If two identical inputs carry different labels, no model drives below that, and chasing zero means memorising noise.
The gradient is the reason it is used
Pair a softmax output with cross-entropy and the gradient with respect to the pre-softmax logits is startlingly simple:
In plain words: predicted probabilities minus the one-hot target. That is the entire backward pass for the output layer. The gradient scales with the error, so badly wrong predictions produce large gradients and learning is fast where needed. No derivative of the exponential survives, which is why the two are always implemented as one fused operation.
Worked example
Three classes, the true class is the second one, so . The model predicts .
Only the true class contributes:
Hand check: , so negating gives , rounded to . With a worse prediction on the same label:
Hand check: , so the loss is . Four and a half times the first loss from the same label. The gradient in the first case is : push the true class up by and push the wrong classes down. A useful reference: a uniform guess over classes gives . Any loss above that means the model does worse than knowing nothing.
Code
The snippet below uses only the standard library. It recomputes both hand losses and shows the stable logit path that survives large magnitudes.
import math
def cross_entropy_from_logits(logits: list[float], target: int) -> float: # Log-sum-exp: subtract the max first so exp() can never overflow. m = max(logits) # softmax is unchanged by shifting every logit shifted = [v - m for v in logits] log_sum = math.log(sum(math.exp(v) for v in shifted)) log_probs = [v - log_sum for v in shifted] # log softmax, stable return -log_probs[target]
print(round(-math.log(0.7), 4)) # -> 0.3567 the true classprint(round(-math.log(0.2), 4)) # -> 1.6094 confidently wrongprint(round(-math.log(1.0 / 3.0), 4)) # -> 1.0986 uniform over 3
logits = [800.0, 802.0, 801.0] # naive math.exp(800) overflows hereprint(round(cross_entropy_from_logits(logits, 1), 4)) # -> 0.4076try: naive = [-math.log(math.exp(v) / sum(math.exp(u) for u in logits)) for v in logits] print(naive[1])except OverflowError as e: print(type(e).__name__) # -> OverflowErrorThe first three prints match the hand arithmetic: , , and for uniform. The last pair is the point: identical mathematics, and only the shifted version survives realistic logit magnitudes because the largest exponent becomes .
Watch Out For
Computing softmax and log separately
log(softmax(x)) and log_softmax(x) are the same function on paper and not in floating point.
Softmax exponentiates. A logit of gives , which overflows every float type, while a small probability underflows to exactly and is negative infinity. The contaminating inf or nan then spreads through every gradient.
The fix is the log-sum-exp trick used above: subtract the maximum logit before exponentiating, which is exact rather than approximate. In practice always use the fused API on raw logits, never nll(log(softmax(x))) assembled by hand. If the final layer already applies softmax and the loss expects logits, it gets applied twice, and the symptom is a loss stuck near the uniform value.
Chasing a loss of zero
The floor on real data is , the entropy of the labels, not zero. Genuine label noise or ambiguity puts a hard bound on the loss, and a training loss heading to zero means memorisation.
The mechanism is a stability problem too. Driving a probability to needs the winning logit to run toward infinity, so weights grow without bound and calibration collapses: the model reports percent confidence on inputs it gets wrong. Label smoothing, such as on the true class with the rest spread across the others, gives a finite minimum at finite logits. It costs a little raw accuracy and buys calibration, which is usually the right trade when probabilities are used downstream.
The Quick Version
- Cross-entropy is the average surprise of describing reality with prediction : .
- With one-hot targets it collapses to . Wrong-class probabilities never appear directly.
- Confidently wrong is punished enormously: costs while costs , and zero on the truth costs infinity.
- It decomposes as , so minimising it is minimising KL divergence.
- Its floor is , not zero. A uniform guess over 3 classes gives .
- Paired with softmax, the gradient on the logits is just , which is why they are fused.
- Minimising cross-entropy is maximum likelihood under a categorical assumption.
- Always compute from logits with log-sum-exp. Separate softmax and log overflows on ordinary magnitudes.