Concept units

Cross-entropy: scoring a choice among many

Intermediate

Read these first if they are new to you

The idea in one paragraph

A model that picks one class out of several gives each class a probability, usually with a softmax. Cross-entropy is the loss that grades those probabilities once the right class is known. The charge is minus the natural logarithm of the probability given to the right class. Probability 1 costs nothing; each halving of that probability adds the same amount, ln 2 ≈ 0.693. A model that spreads its probability evenly over K classes pays ln K.

Only the probability given to the right class enters the charge

Picture a model that labels photos as cat, dog or bird. For one photo it says cat 0.659, dog 0.242 and bird 0.099. The photo shows a dog. The model gave the truth a probability of 0.242, so it pays

L = −ln pright = −ln 0.2424 ≈ 1.417

Had the photo shown a cat, it would pay −ln 0.659 ≈ 0.417. Here ln is the natural logarithm, from the exponentials unit. With two classes this is exactly binary cross-entropy.

Predict first. The photo shows a dog, and the model gives the dog 0.242. Would the charge change if the other 0.758 went all to the bird instead of mostly to the cat?

Worked example: three photos
PhotocatdogbirdRight classCharge
10.6590.2420.099dog1.417
20.1110.8210.067dog0.197
30.1070.1070.787cat2.240

Each charge is −ln of the bold probability, computed before rounding. The loss for the set is the average: (1.417 + 0.197 + 2.240) / 3 ≈ 1.284. The other probabilities in each row do not enter the sum. So the answer to the prediction is no: the charge depends only on the 0.242.

Each halving of the right class's probability adds the same charge
4 2 0 0 0.5 1 probability given to the right class charge even guess, 3 classes: ln 3 = 1.099

−ln(0.24) = 1.427 (worse than an even guess among 3)

Try it. Read the charge at 1.00, 0.50 and 0.25. Predict the charge at 0.12, then drag there to check. Where does the curve cross the dashed line?

What to notice. Going from 1 to 0.5 adds 0.693, and so does going from 0.5 to 0.25, and from 0.25 to 0.125. Below the dashed line, the model does better than an even guess among three classes; above it, worse.

The full formula compares two lists of probabilities

The textbook formula looks larger than the rule above. Write the truth as a list too: 1 for the right class and 0 for every other class. For a dog this list is (0, 1, 0), which is called a one-hot list. Call it y, and call the model's probabilities p. Then

H(y, p) = −( y1 ln p1 + … + yK ln pK )

Every term with yi = 0 vanishes, which leaves −ln pright. The name comes from information theory, where cross-entropy measures how well one probability list describes another. The full sum matters only when the truth is itself spread over several classes, for example 0.9 on dog and 0.05 on each of the others.

Lowering the charge raises the right score and lowers the others

In practice the loss is computed straight from the scores z that went into the softmax. Taking the logarithm of the softmax formula gives

L = −zright + ln( ez1 + … + ezK )

The loss falls when the right class's score rises. It also falls when any other score drops, because that shrinks the sum. For readers who know derivatives: the derivative of L with respect to score i is pi − yi. In the dog photo that is +0.659 for cat, −0.758 for dog and +0.099 for bird. Gradient descent moves each score against its derivative. So the dog's score goes up, and each wrong score goes down in proportion to the probability it took.

ce.py

import numpy as np

scores = np.array([[2.0, 1.0, 0.1],    # one row of scores per example
                   [0.5, 2.5, 0.0],
                   [1.0, 1.0, 3.0]])
right = np.array([1, 1, 0])            # the index of the right class

# -log softmax, computed straight from the scores
m = scores.max(axis=1, keepdims=True)
log_p = scores - m - np.log(np.exp(scores - m).sum(axis=1, keepdims=True))
# From each row i, take the entry in column right[i]; np.arange(len(right)) is [0 1 2]
loss = -log_p[np.arange(len(right)), right]
print(np.round(loss, 3))
print(round(loss.mean(), 3))
[1.417 0.197 2.24 ]
1.284

The three rows of scores are the ones behind the worked example's table. The code subtracts each row's largest score first, as the softmax unit explains, so large scores do not overflow.

Library loss functions usually expect scores, not probabilities

PyTorch's cross_entropy, for example, takes the raw scores and applies the softmax itself. Passing it probabilities that have already been through a softmax applies the softmax twice. The code still runs, but the loss is wrong and training slows. Check which input your library expects.

This page also uses the natural logarithm. Information theory often uses log base 2 and measures in bits. The two differ only by a constant factor, ln 2.

Check yourself

  1. A model says cat 0.7, dog 0.2, bird 0.1. What is the charge if the photo shows a bird? A cat?

    Answer

    Bird: −ln 0.1 ≈ 2.303. Cat: −ln 0.7 ≈ 0.357.

  2. A new model sorts images into 10 classes. Before training it gives every class 0.1. What loss should you expect at the first step?

    Answer

    −ln 0.1 = ln 10 ≈ 2.303 on every example, so the average is 2.303. A first loss far above that often points to a bug, such as scores that start out very large.

  3. Over a set of examples, the average charge is 0.105. If every example got the same probability on its right class, what was that probability?

    Answer

    e−0.105 ≈ 0.90. Undo the minus sign and the logarithm.

Go further

Optional background, for readers who want more than this page.

Where this shows up

No unit or explanation builds on this one yet.