Loss Functions Mathematical Deep Dive
P6.nn-foundations.05 · Audience: it-ml · Prerequisites: Loss Functions and the Learning Objective
Mathematical derivation of cross-entropy from MLE, MSE from the Gaussian noise assumption, the softmax+CE combined gradient, and label smoothing. Step through the four derivations one at a time (keep a pencil at hand), then work the pencil-and-paper exercises, NumPy programming tasks, and 5-question self-test below.
Prerequisite: Loss Functions and the Learning Objective. This page assumes familiarity with logarithms, probability distributions, and basic calculus (chain rule). All derivations are self-contained.
Goal: prove that minimising cross-entropy is equivalent to maximum likelihood estimation for a classifier.
Setup. Suppose the correct label for example is class . The model assigns probability to the correct class (via softmax).
Step 1 — Likelihood of one example. The categorical likelihood of observing label given the model's probabilities is:
Step 2 — Log-likelihood over the training set. Assuming examples are independent, the joint log-likelihood is:
Step 3 — Maximise log-likelihood ≡ minimise negative log-likelihood.
where is the per-example cross-entropy loss.
Step 4 — Average over examples (the batch loss).
Conclusion: minimising cross-entropy is exactly MLE for the categorical distribution — the model is trained to assign the highest possible probability to the correct class label. ∎
ⓘ Concept — why not use accuracy as the loss?
Part 2 — Exercises
Work these on paper or in the scratch console at the bottom of the page. Graded numeric practice on these formulas lives on the module 03 practice rung — here each exercise carries its worked solution behind a reveal, so check yourself as you go.
Maths exercises (pencil and paper)
M1 — Binary cross-entropy from MLE. Consider binary classification (, ). The model outputs a scalar .
- Write the likelihood of observing label given as a single expression using and without an if-else.
- Take the negative log-likelihood for one example to obtain .
- Verify: for and , BCE ; for and , BCE .
- Show that BCE is a special case of CE with classes.
Show answer — M1
- Likelihood: — takes value when , and when .
- .
- , : BCE . , : BCE . ✓
- : , . . ✓
M2 — Softmax + CE gradient for K = 3. Let and the correct class be .
- Compute . (Hint: subtract max for numerical stability, then normalise.)
- Compute the CE loss .
- Use the formula to write down the gradient vector.
- Verify: the gradient at position 0 is , and at positions 1, 2 it is .
Show answer — M2
- ; sum ; .
- .
- ; .
- ✓; ✓; ✓.
M3 — Label smoothing: compute soft targets. Given classes, correct class , smoothing factor :
- Write down the hard one-hot target .
- Compute the label-smoothed target using .
- Verify that sums to 1.
- What is the optimal logit gap for these values? (Give a numerical answer.)
Show answer — M3
- .
- (; others ).
- Sum ✓
- .
Programming exercises (NumPy)
P1 — Implement cross-entropy from logits. Fill in the stub to compute CE loss directly from logits (numerically stable):
import numpy as np
def cross_entropy_from_logits(z: np.ndarray, k_star: int) -> float:
"""Cross-entropy loss for one example."""
# STUB: compute log-softmax of z (numerically stable), then return −log_p[k_star]
log_p = ___
return float(-log_p[k_star])
z = np.array([2.0, 1.0, 0.0])
print(cross_entropy_from_logits(z, 0)) # should be ≈ 0.4076
Show solution — P1
log_p = z - np.log(np.sum(np.exp(z - z.max()))) - z.max()
# or more compactly:
log_p = z - (z.max() + np.log(np.sum(np.exp(z - z.max()))))
The log-sum-exp trick: subtract before exponentiating to avoid
overflow. .
This is how PyTorch's F.cross_entropy works internally.
P2 — Verify the gradient formula ∂L/∂z = ŷ − y numerically. Fill in the stub to verify the analytical gradient against a numerical approximation:
import numpy as np
def ce_loss(z: np.ndarray, k_star: int) -> float:
z_s = z - z.max()
log_p = z_s - np.log(np.sum(np.exp(z_s)))
return float(-log_p[k_star])
z = np.array([2.0, 1.0, 0.0])
k_star = 0
h = 1e-5
# Numerical gradient (finite differences)
num_grad = np.array([
(ce_loss(z + h * np.eye(len(z))[i], k_star) -
ce_loss(z - h * np.eye(len(z))[i], k_star)) / (2 * h)
for i in range(len(z))
])
# STUB: compute the analytical gradient ∂L/∂z = ŷ − y
analytic_grad = ___
print('Numerical:', num_grad.round(6))
print('Analytic: ', analytic_grad.round(6))
print('Match:', np.allclose(num_grad, analytic_grad, atol=1e-5))
Show solution — P2
z_s = z - z.max()
y_hat = np.exp(z_s) / np.sum(np.exp(z_s)) # softmax probabilities
y = np.zeros(len(z))
y[k_star] = 1.0
analytic_grad = y_hat - y
Numerical and analytical gradients match to within 1e-5 — confirming the derivation in the third step. The analytical gradient is vastly cheaper to compute and is exactly what backpropagation uses.
P3 — Label smoothing: compare losses and gradients. Fill in the stub to implement label smoothing and compare its CE loss with the hard-target CE:
import numpy as np
def smooth_labels(y: np.ndarray, eps: float) -> np.ndarray:
"""Apply label smoothing to a one-hot vector."""
K = len(y)
# STUB: return (1-eps)*y + eps/K
return ___
K, k_star, eps = 4, 0, 0.1
y_hard = np.zeros(K); y_hard[k_star] = 1.0
y_soft = smooth_labels(y_hard, eps)
# Suppose the model is very confident: logits favour class k_star
z = np.array([5.0, 1.0, 1.0, 1.0])
z_s = z - z.max()
log_p = z_s - np.log(np.sum(np.exp(z_s)))
p = np.exp(log_p)
loss_hard = float(-log_p[k_star])
loss_soft = float(-y_soft @ log_p) # − Σⱼ yⱼ^LS · log pⱼ
print(f'Hard CE: {loss_hard:.4f}')
print(f'Smoothed CE: {loss_soft:.4f}')
print(f'Softmax probs: {p.round(4)}')
Show solution — P3
return (1 - eps) * y + eps / K
Expected output: Hard CE: 0.0535 (very low — model is very confident and correct); Smoothed CE: 0.3535 (higher — label smoothing penalises overconfidence); Softmax probs: [0.9479, 0.0174, 0.0174, 0.0174].
Label smoothing always adds a uniform entropy term , preventing the model from assigning near-zero probability to any class.
Part 3 — Self-Test
Write your answer before revealing.
Q1 — Explain in one sentence what maximum likelihood estimation means in the context of a neural network classifier.
Q2 — What probability distribution over the prediction error (noise) makes MSE the correct MLE loss function? State the assumption precisely.
Q3 — Explain why the combined softmax + cross-entropy gradient ∂L/∂z = ŷ − y is considered particularly elegant compared to using MSE + softmax.
Q4 — What failure mode does label smoothing address, and how does it fix it?
Q5 — Numerical: given logit vector z = [2, 1, 0] and correct class k* = 0, compute softmax(z) and the CE loss −log p₀, both to 4 decimal places.
Cross-references: Loss Functions and the Learning Objective (base module) · Backpropagation Intuition — where the gradient flows backward from the CE loss — arrives with the dl-architectures track (coming soon).
Ask the mentor about this module
Ask a question about this content. The mentor explains and grounds its answer in what you are studying; asking is recorded as a learning signal, not a grade.
Try it yourself
A scratch console for this page's ideas — ungraded, nothing you run here is recorded.
Scratch console
A scratch console with the scientific stack (pandas, numpy, scikit-learn). Runs on the server — no network, resource-limited and measured.
Output appears here.