A chapter that uses mathematics has to teach that mathematics by making the reader compute. A chapter that only displays equations has failed, however correct the equations are.
M3Load-bearing
7/5 problems6/4 variants10/10 exercisesquota met, and enforced
The contract
5 worked problems, minimum.
4 distinct variants, and no variant more than half of them.
10 exercises, every one with a published solution.
At least one numeric problem — present.
At least one symbolic problem — present.
At least one limit or counterexample problem — present.
At least one complexity or shape problem — present.
All values rounded to 4 d.p. The arithmetic is exact; only the display is rounded.
STATEMENT
Five residuals are given, one of them an outlier. Compute MSE, MAE and
Huber with δ=1 on all five. Then determine, for each loss, what share
of the total the outlier alone contributes, and what derivative each loss sends
back for it.
GIVEN
The residuals ri=y^i−yi:
r=(0.5,−0.8,0.2,−0.3,4.0),n=5
The three losses, as per-residual functions before any averaging:
The per-residual contribution under each loss; the three totals and means; the
outlier’s percentage share of each total; and dℓ/dr
evaluated at r=4.0 for each.
STRATEGY
Build one table column at a time rather than one row at a time. Each column is a
single function applied five times, so a slip is visible as a break in the
column’s pattern — whereas working row by row hides it.
SOLUTION
Step 0 — which branch of Huber each residual takes. The branch is decided by
∣r∣ against δ=1, so check all five before computing anything:
Step 5 — the derivatives, which are the operative quantity. The loss value
is a diagnostic; the derivative is what training actually uses. Differentiating
each per-residual loss at r=4.0:
For Huber on the linear branch, d/dr[δ(r−21δ)]=δ:
Huber1′(4.0)=δ=1.0000
So the outlier pulls eight times harder under MSE than under either of the
other two.
Step 6 — what the two measurements say together. Compare the share of the
value with the share of the pull:
share of loss value
derivative at the outlier
MSE
94.0%
8.0
MAE
69.0%
1.0
Huber
87.3%
1.0
Huber’s value share, 87.3%, is close to MSE’s — because the four inliers
are small and halving them makes the outlier look even more dominant. But its
derivative is MAE’s. That combination is the entire design: Huber reports a
large loss when there is a large error, while refusing to let that error
dominate the step. A loss’s value and a loss’s gradient are different
measurements and can disagree, and only the second one moves the model.
Step 7 — the four inliers alone. Removing the outlier and averaging over
n=4:
MSE fell by a factor of 3.4040/0.2550=13.35; MAE by 1.1600/0.4500=2.58.
One point in five moved MSE more than thirteenfold.
Answer
MSE=3.4040,MAE=1.1600,Huber1=0.8020
Outlier share of the total: 94.0%, 69.0%, 87.3% respectively.
Derivative at r=4.0: 8.0 (MSE), 1.0 (MAE), 1.0 (Huber).
All values are dimensionless here; in general MSE carries the square of the
target’s units while MAE and Huber carry the units themselves — which is why
MSE is usually reported as its square root.
Check — numeric · i-4-b01-three-losses.py
def huber(t): a = abs(t) return 0.5 * t * t if a <= delta else delta * (a - 0.5 * delta)def d_huber(t): a = abs(t) return t if a <= delta else delta * (1.0 if t > 0 else -1.0)
Prints every column, the three shares, the three derivatives, and the
inliers-only means.
Executed in CI. The digits above are the digits it printed.
Check — sanity
Huber sits between half-MSE and MAE, as its definition forces. Per residual,
Huber1(r)≤21r2 always (equality on the quadratic branch,
strictly below on the linear one) and Huber1(r)≤∣r∣ always. Check
the totals: 4.0100≤21(17.02)=8.51 ✓ and 4.0100≤5.80 ✓.
The two Huber branches meet. At ∣r∣=δ=1 the quadratic branch gives
21(1)2=0.5 and the linear branch gives (1)(1−0.5)=0.5. Equal, so
the function is continuous. Their derivatives also meet: r=1 against
δ=1. Continuity of the derivative is what makes Huber usable by a
gradient method, and it is not automatic — it is what the −21δ term
in the linear branch is for.
MAE’s ordering is preserved. The residual magnitudes ordered
0.2<0.3<0.5<0.8<4.0, and the MAE column reproduces that order exactly,
since ∣⋅∣ is monotone in magnitude. A column out of order would signal a
transcription error.
Units check on the derivative.d(r2)/dr has the units of
r; d∣r∣/dr is dimensionless. That is why MSE’s pull grows
with the error and MAE’s cannot — a dimensional argument reaching the same
conclusion as the arithmetic.
Where this breaks
The comparison of shares depends on δ being small relative to the outlier.
Set δ=5 and every residual takes the quadratic branch, so Huber becomes
exactly 21MSE and its derivative at the outlier becomes 4.0, not
1.0. Huber is not robust; Huber with a well-chosen δ is robust, and
δ has to be set against the scale of the residuals you are willing to
treat as signal.
That scale is not known before training and changes during it, which is the real
difficulty. The usual answers are to set δ from a robust spread estimate
of the residuals — the median absolute deviation — or to recompute it each epoch.
Neither is free, and both are a hyperparameter that MSE does not have.
Variation
Replace the outlier 4.0 by 40.0 and recompute all three means and all three
derivatives at that residual. Predict, before computing, which of the three
means changes by the largest factor — then check whether your prediction was
right, and say what the factor is for each.
Symbolic; constants are tracked explicitly rather than absorbed silently.
STATEMENT
Derive squared error as the negative log-likelihood of a Gaussian observation
model with fixed variance, and cross-entropy as the negative log-likelihood of a
categorical one. Track every constant that appears, and state exactly which ones
may be discarded and why.
GIVEN
Gaussian model. Observations are generated as
yi=f(xi;θ)+εi with
εi∼N(0,σ2) independent, σ2 fixed and
not learned. The density is
p(y∣x,θ)=2πσ21exp(−2σ2(y−f(x;θ))2)
Categorical model. A prediction is a distribution
q=(q1,…,qK) on the simplex, the observation is a class
c∈{1,…,K}, and
p(c∣x,θ)=∏k=1Kqkyk,yk=1[k=c]
FIND
−logp(D∣θ) for each model, reduced to a loss, with every
discarded term named.
STRATEGY
Write the likelihood of the whole dataset, take a logarithm to turn the product
into a sum, negate, then separate the terms containing θ from those that
do not. Only the first group can affect the minimiser, and the second group is
where the constants go.
SOLUTION
Part 1 — the Gaussian case
Step 1 — the dataset likelihood. Independence turns a joint density into a
product:
The exponential and the logarithm are inverses, so the second term simplifies
outright:
=i=1∑n[−21log(2πσ2)−2σ2ri2]
Step 3 — separate. The first term does not depend on i, so summing it n
times gives a single constant:
logp(D∣θ)=−2nlog(2πσ2)−2σ21i=1∑nri2
Step 4 — negate.
−logp(D∣θ)=A2nlog(2πσ2)+B2σ21i=1∑nri2
Step 5 — account for A and B precisely.
Term A is additive and θ-free. Adding a constant to a function shifts
its graph vertically and moves no stationary point:
∇θ(g(θ)+A)=∇θg(θ). So A may be dropped
without changing the minimiser or any gradient.
Term B is a positive multiplicative constant. Since σ2>0 we have
B>0, and argminθBg(θ)=argminθg(θ) for any
B>0. So B may be dropped from the objective. It may not be dropped
from the gradient if the learning rate is fixed, because
∇(Bg)=B∇g — dropping B rescales every step by 1/B, which is a
change of effective learning rate and nothing more.
■ Minimising squared error is maximum likelihood under a
fixed-variance Gaussian.
Part 2 — the categorical case
Step 7 — one example. The indicator exponent means all but one factor is
raised to the power zero:
p(c∣x,θ)=∏k=1Kqkyk=qc
Step 8 — take the logarithm and negate.
−logp(c∣x,θ)=−logk∏qkyk=−k=1∑Kyklogqk
using log(ab)=bloga on each factor. The right-hand side is exactly the
cross-entropy H(y,q) of Definition 8.
Step 9 — the dataset. By independence again,
−logp(D∣θ)=∑i=1nH(yi,qi)
■
Note the asymmetry with Part 1: there is no constant to discard. The
categorical density has no normalising factor outside the probabilities
themselves, because ∑kqk=1 is built into the parameterisation. Every
term of the cross-entropy depends on θ.
What the correspondence costs
Reading Steps 1–6 backwards is the uncomfortable direction. If minimising MSE is
maximum likelihood under a Gaussian, then choosing MSE asserts a Gaussian,
whether or not anyone intended to assert anything. Three properties come with
that assertion:
Symmetry.p(ε)=p(−ε), so over-prediction and
under-prediction cost the same. False whenever the two have different
consequences.
Constant variance. One σ2 for every x. False whenever the noise
scales with the signal, which is the ordinary situation for counts, prices and
concentrations.
Unbounded support.ε may take any real value, so y may too. False
for anything bounded — a probability, a proportion, a nonnegative count.
Chapter VII.2 will meet count data where all three fail at once, and will need a
negative binomial likelihood instead. The route there is exactly this derivation
run forwards with a different density.
Answer
−logpGauss(D∣θ)=2nlog(2πσ2)+2σ21i∑ri2
The first term is additive and θ-free; the second’s prefactor is a
positive constant. Discarding both leaves ∑iri2, so MSE is Gaussian
maximum likelihood.
−logpcat(D∣θ)=−i∑k∑yiklogqik
which is cross-entropy exactly, with no constant to discard.
Check — sanity
The Gaussian result reproduces the known optimum. For a constant model
f=μ, minimising ∑(yi−μ)2 gives μ=yˉ, the sample mean
— which is the maximum-likelihood estimate of a Gaussian mean. Two routes, one
answer.
Dropping B is exactly a learning-rate change. With σ2=1,
B=21. Training on ∑ri2 at rate η and on
21∑ri2 at rate 2η produce identical parameter sequences. This
is checkable in three lines of code, and it is why the factor of 21 in
front of squared losses is a convention rather than a claim.
The categorical result reduces to the binary case. At K=2 with
q2=1−q1 and y one-hot, Step 8 becomes
−[y1logq1+(1−y1)log(1−q1)], which is binary cross-entropy — the
identity established in I.1.B04, recovered here as a special case rather than
assumed.
The units are consistent. A log-likelihood is dimensionless (a log of a
probability), and so is cross-entropy. But ∑ri2 carries the square of
y‘s units — the mismatch is absorbed by 1/(2σ2), whose units are the
inverse square of y‘s. Discarding B therefore discards the dimensional
bookkeeping too, which is a small reason MSE values are hard to interpret across
problems.
Where this breaks
Step 5 discards A=2nlog(2πσ2) because it is θ-free.
That holds only while σ2 is fixed. Learn the variance — predict
σ2(x) as a second output head, as heteroscedastic regression does — and
A becomes 21∑ilogσ2(xi), which depends on θ and
cannot be dropped.
The resulting loss is
∑i[2σi2ri2+21logσi2], and its
behaviour is different in kind: the first term rewards predicting a large
variance, the second punishes it, and the balance is what makes the model report
calibrated uncertainty. Dropping A there would let the model claim infinite
variance everywhere and drive the loss to −∞. The constant was never
inert; it was inert given an assumption.
Variation
Derive the loss implied by a Laplace observation model,
p(ε)∝exp(−∣ε∣/b) with b fixed. Identify which
of this chapter’s losses it is, and state what that tells you about when to
prefer it.
Derive ∂L/∂z=p−y for softmax followed by
cross-entropy. Do not quote the result: obtain the softmax Jacobian from the
quotient rule, apply the chain rule through it in full, and show explicitly
which terms cancel and why. Then instantiate the whole calculation on three
logits.
GIVEN
Logits z∈RK, predictions and target
pi=∑j=1Kezjezi,L=−k=1∑Kyklogpk,yone-hot at class c
For the numeric part, z=(2,1,0) and c=1 (the first entry).
FIND
∂pi/∂zj for all i,j; then ∂L/∂zj;
then both evaluated at the given logits.
STRATEGY
Differentiate softmax by the quotient rule, splitting into the i=j and
i=j cases because the numerator depends on zj only in the first. Then
push the loss gradient through the Jacobian and use ∑kyk=1 — that one
identity is what collapses a K×K matrix product to a subtraction.
SOLUTION
Part 1 — the softmax Jacobian
Step 1 — name the denominator. Let
S=∑j=1Kezj,sopi=Sezi
The key observation before any differentiation: S depends on every logit.
So pi depends on zj even when i=j — through the denominator alone.
That is the whole source of the off-diagonal terms.
Differentiating S:
∂zj∂S=∂zj∂∑mezm=ezj
since every term but the j-th is constant in zj.
Step 2 — the diagonal case, i=j. Apply the quotient rule
(vu)′=v2u′v−uv′ with u=ezi and
v=S. Here u′=ezi and v′=ezi:
∂zi∂pi=S2eziS−eziezi
Split the fraction into two, so each piece becomes a p:
Step 3 — the off-diagonal case, i=j. Now u=ezi does not
depend on zj, so u′=0 and only the denominator contributes:
∂zj∂pi=S20⋅S−eziezj=−Sezi⋅Sezj=−pipj
Step 4 — combine. Using the Kronecker delta
δij=1 if i=j and 0 otherwise, the two cases are one formula:
∂zj∂pi=pi(δij−pj)
This is the softmax Jacobian of The softmax Jacobian· 0.MC.06, derived here
rather than cited, because the two cancellations that follow depend on knowing
where each factor came from.
Check it reproduces both branches: at i=j, pi(1−pi) ✓; at i=j,
pi(0−pj)=−pipj ✓.
Part 2 — the chain rule through it
Step 5 — differentiate the loss with respect to the probabilities.
∂pi∂L=∂pi∂(−∑kyklogpk)=−piyi
only the k=i term surviving.
Step 6 — assemble. The chain rule for a vector-to-vector map sums over the
intermediate index (The chain rule· 0.MC.03):
Step 7 — the first cancellation. The factor pi from the Jacobian meets
the 1/pi from the loss and they cancel exactly:
=−i=1∑Kyi(δij−pj)
This is the step that makes the whole thing work, and it is why softmax and
cross-entropy are paired rather than chosen independently. Had the loss been
anything but a logarithm, the 1/pi would not have appeared and nothing would
cancel — which is exactly what problem I.4.B06 shows happening with MSE.
Step 8 — expand the bracket and use ∑iyi=1.
=−i∑yiδij+i∑yipj
The first sum has exactly one non-zero term, at i=j, giving yj. In the
second, pj does not depend on i, so it factors out:
=−yj+pj=1i∑yi=pj−yj∂z∂L=p−y(I.4.4)
■
Where each hypothesis was used. Step 7 needed the loss to be logarithmic.
Step 8 needed y to sum to one — note it did not need y to be
one-hot, so the result holds for soft targets and therefore for label smoothing
unchanged. That is worth recording, because it is often stated as requiring
one-hot labels and does not.
Part 3 — the numbers
Step 9 — softmax at z=(2,1,0). Subtract the maximum first, which
changes nothing and prevents overflow (Log-sum-exp· 0.NU.02):
At z=(2,1,0) with the true class first:
p=(0.6652,0.2447,0.0900), L=0.4076 nats, and
∂z∂L=(−0.3348,+0.2447,+0.0900)
a dimensionless vector of length K, summing to zero.
Check — numeric · i-4-b03-softmax-ce-gradient.py
J = [[p[i] * ((1.0 if i == j else 0.0) - p[j]) for j in range(3)] for i in range(3)]dL_dp = [-(y[k] / p[k]) for k in range(3)]dL_dz = [sum(dL_dp[i] * J[i][j] for i in range(3)) for j in range(3)]
The snippet computes the gradient twice — once through the full Jacobian and
once as p−y — and prints agreement: True. That is the point of
running it: the two routes are independent, so agreement is evidence rather than
restatement.
Executed in CI. The digits above are the digits it printed.
Check — sanity
The gradient sums to zero.−0.3348+0.2447+0.0900=−0.0001≈0.
This must hold: softmax is invariant to adding a constant λ to every
logit, so the directional derivative along (1,1,…,1) is zero, which is
exactly ∑j∂L/∂zj=0. A gradient not summing to zero
means an arithmetic slip.
The signs are right. The true class has a negative gradient, so gradient
descent raises its logit; every other class has a positive gradient, so their
logits are lowered. That is the behaviour the loss should produce, read directly
off the sign pattern.
The magnitudes are bounded. Every entry of p−y lies in
[−1,1], since pj∈(0,1) and yj∈{0,1}. The gradient can never
explode, whatever the logits. Contrast with the MSE-through-sigmoid gradient of
I.4.B06, which is bounded too — but by a number that shrinks to zero exactly when
it is needed.
The Jacobian is symmetric with zero row sums.J12=J21=−0.1628,
and 0.2227−0.1628−0.0599=0.0000. Both properties follow from the formula:
pi(δij−pj) is symmetric because pipj is, and rows sum to
pi(1−∑jpj)=pi(1−1)=0.
Where this breaks
The clean result needs softmax and cross-entropy to be fused. Computing
p first, storing it, and then computing −logpc gives the same number
but a worse computation: when pc underflows to 0 the logarithm is −∞,
and the 1/pi in Step 5 is a division by zero even though the final answer
p−y is perfectly well behaved.
This is why every framework has a single cross_entropy(logits, target) rather
than a softmax followed by a log — the fused version computes
zc−log∑jezj directly via log-sum-exp and never forms the
intermediate that overflows. The mathematics is identical; the arithmetic is not,
and I.4.B04 makes the same point for the binary case in detail.
Variation
Redo Steps 5–8 with a label-smoothed target
y′=(1−ε)y+ε/K. Verify the derivation still
goes through, state the resulting gradient, and find the logit gap at which it
vanishes for ε=0.1, K=3.
6 d.p. where precision is the subject; otherwise 4 d.p.
STATEMENT
Evaluate binary cross-entropy at four logits by two routes: the naive one that
forms a probability first, and the stable identity that never does. Derive the
identity, show the naive route failing on two ordinary inputs, and state the
logit at which each failure begins.
GIVEN
A logit z∈R, a label y∈{0,1}, and p=σ(z)=1/(1+e−z).
The naive computation is
BCEnaive=−[ylogp+(1−y)log(1−p)]
Test at (z,y)∈{(2,1),(0,1),(−5,1),(−50,1),(−800,1),(800,0)}.
IEEE double precision: ex overflows for x>709.78, and σ(z) rounds
to exactly 1.0 once e−z<2−53≈1.11×10−16.
FIND
The stable identity; both routes’ values at each test point; and the two
thresholds at which the naive route breaks.
STRATEGY
Derive the identity by substituting σ into the definition and simplifying
until no probability appears — only z and a logarithm of something safely near
one. Then evaluate both routes and watch where they part.
SOLUTION
Part 1 — deriving the stable form
Step 1 — substitute for y=1. With p=1/(1+e−z):
−logp=−log1+e−z1=log(1+e−z)
using −log(1/a)=loga.
Step 2 — substitute for y=0. First simplify 1−p:
1−p=1−1+e−z1=1+e−z(1+e−z)−1=1+e−ze−z
so
−log(1−p)=−loge−z+log(1+e−z)=z+log(1+e−z)
Step 3 — one formula for both. Combining Steps 1 and 2:
BCE(z,y)=−zy+z(1−y)⋅0+…
More carefully — write the two cases and look for the pattern:
Step 4 — the remaining danger. This is exact, but e−z still overflows
for z<−709.78. Fix it by pulling out the larger of the two terms inside the
logarithm. For z<0 write 1+e−z=e−z(1+ez), so
log(1+e−z)=−z+log(1+ez)
Substituting into Step 3’s formula for z<0 and combining with the z≥0
case gives the symmetric form
BCE(z,y)=max(z,0)−zy+log(1+e−∣z∣)(I.4.5)
Why this one is safe. The exponential’s argument is −∣z∣≤0, so
e−∣z∣∈(0,1] and can never overflow. It can underflow to 0, but then
log(1+0)=0 exactly, which is the correct limit rather than an error. Every
other term is elementary arithmetic on z itself.
Part 2 — the two routes side by side
z
y
σ(z)
naive
stable
2.0
1
8.807971e−1
0.126928
0.126928
0.0
1
5.000000e−1
0.693147
0.693147
−5.0
1
6.692851e−3
5.006715
5.006715
−50.0
1
1.928750e−22
50.000000
50.000000
−800.0
1
overflow
OverflowError
800.000000
800.0
0
1.000000e+0
ValueError
800.000000
Step 5 — verifying agreement where both work. At the three safe points the
two routes agree to ten decimal places, with ∣diff∣≤2.78×10−17
— one unit in the last place of a double. So (I.4.5) is not an approximation; it
is the same number computed differently.
Step 6 — the first failure, z=−800, y=1. The naive route needs
σ(−800)=1/(1+e800). But e800 exceeds the largest double
(1.798×10308) and overflows, raising OverflowError before any
logarithm is reached.
which is correct: a logit of −800 with target 1 is wrong by 800 nats.
Step 7 — the second failure, z=800, y=0. Here
e−800 underflows to 0, so σ(800) evaluates to exactly 1.0. The
naive route then needs log(1−1.0)=log(0)=−∞, and Python raises
ValueError. In a framework that returns −∞ silently instead, the loss
becomes inf, every gradient becomes nan, and the entire model is destroyed
in one step with no message.
The stable route gives max(800,0)−(800)(0)+log(1+e−800)=800+0=800.000000.
Step 8 — the thresholds.
Overflow.e−z overflows when −z>709.78, so the naive route fails for
z<−709.78.
Rounding to one.σ(z) becomes exactly 1.0 once e−z falls below
the spacing of doubles near 1, that is e−z<2−53, giving
z>53ln2=36.74. This is the more dangerous of the two, because
z=37 is an entirely ordinary logit — it appears whenever a model becomes
confident — and the failure is a silent −∞ rather than a raised
exception.
In float32 the corresponding threshold is z>24ln2=16.6, which is
reached routinely within the first epoch of ordinary training.
Answer
BCE(z,y)=max(z,0)−zy+log(1+e−∣z∣)
Both routes agree to within 2.78×10−17 where the naive one works, and
it fails at z=−800 (overflow) and z=800 (log of zero), where the stable
form returns 800.000000 in both cases.
Thresholds in double precision: overflow below z=−709.78; silent saturation
to p=1 above z=36.74. In float32 the second is z=16.6.
Check — numeric · i-4-b04-bce-in-logit-space.py
def bce_stable(z, y): return max(z, 0.0) - z * y + log(1.0 + exp(-abs(z)))
Prints the six-row table with both routes, the two exception names, and the
ten-digit agreement check on the safe points.
Executed in CI. The digits above are the digits it printed.
Check — sanity
The identity gives the right answer at z=0. There p=0.5 and the loss
should be −log0.5=log2=0.693147. The formula gives
max(0,0)−0+log(1+e0)=log2 ✓.
Large-∣z∣ behaviour is linear, as it must be. For z→−∞ with
y=1, −logσ(z)=log(1+e−z)≈−z. The table confirms it:
z=−50⇒50.000000 and z=−800⇒800.000000, both equal
to ∣z∣ to six decimals. A loss growing linearly rather than exponentially in
the logit is exactly why cross-entropy’s gradient stays bounded.
The two failures are the two ends of the same problem. Underflow of
e−∣z∣ is harmless — log(1+0)=0 is correct. Overflow of e+∣z∣ is
fatal. The identity’s whole content is arranging that only the harmless one can
occur.
Symmetry check.BCE(z,1)=BCE(−z,0): predicting logit
z for a positive should cost the same as predicting −z for a negative. From
the formula at z=2: BCE(2,1)=2−2+log(1+e−2)=0.126928
and BCE(−2,0)=0−0+log(1+e−2)=0.126928 ✓.
Where this breaks
The identity is exact in exact arithmetic and nearly exact in floating point —
the 2.78×10−17 discrepancy is real, not a display artefact. It comes
from log(1+x) losing precision when x is tiny: the addition 1+x discards
most of x‘s bits before the logarithm sees it.
The remedy is log1p(x), which computes log(1+x) accurately for small x by
a series expansion rather than by forming the sum. Every serious implementation
uses it. The point generalises: this problem removed one catastrophic failure and
left a benign one, and knowing which is which is the actual skill
(Catastrophic cancellation· 0.NU.04).
Variation
Derive the analogous stable form for the multi-class case,
L=−zc+log∑jezj, and show that subtracting maxjzj from
every logit leaves it unchanged. Then evaluate at
z=(1000,999,998) with c=1, where the naive route overflows.
A binary dataset holds 950 negatives and 50 positives. Derive the class
weights that make the two classes contribute equal gradient mass, compute them,
verify the loss scale is unchanged, and compare with the effective-number
weighting of Cui et al. (2019).
GIVEN
n−=950, n+=50, so N=1000 and K=2. The weighted empirical risk is
R^(θ)=N1i=1∑Nwc(i)ℓ(f(xi;θ),yi)
where c(i) is example i‘s class. Assume each example’s loss has comparable
magnitude, so that a class’s contribution is proportional to its count times its
weight.
FIND
Weights w− and w+ equalising the two contributions; their ratio; a check
that the mean weight is 1; and the same quantities under effective-number
weighting at β=0.999.
STRATEGY
Write the condition “the two classes contribute equally” as one equation, add
the normalisation “the average weight is one” as a second, and solve the pair.
Two conditions, two unknowns — the weights are then determined, not chosen.
SOLUTION
Step 1 — the unweighted imbalance. Without weights, class c contributes
nc of the N terms, so its share of the gradient is
Nn−=1000950=95%,Nn+=100050=5%
The negatives outvote the positives nineteen to one. A model that predicts
“negative” always achieves 95% accuracy and a low loss, and the gradient
pushing it away from that solution is one-nineteenth of the gradient holding it
there.
Step 2 — the equalisation condition. Class c‘s weighted contribution is
ncwc. Requiring the two to be equal:
n_- w_- = n_+ w_+ \tag{i}
Step 3 — the normalisation condition. Requiring the mean weight over the
dataset to be 1, so the weighted loss has the same scale as the unweighted one
and the learning rate need not be retuned:
The ratio equals the imbalance ratio, 950/50=19, which it must:
dividing (i) by n+w− gives w+/w−=n−/n+ directly.
Step 6 — check both conditions.
Equal contributions.n−w−=950×0.5263=500.0 and
n+w+=50×10.0000=500.0. Equal ✓
Unit mean weight.(500.0+500.0)/1000=1.0000 ✓ — so a loss of 0.5
before weighting is a loss of about 0.5 after, and the learning rate carries
over.
Step 7 — effective-number weighting. The inverse-frequency weight assumes
each example contributes independent information. Cui et al. argue that examples
of the same class overlap, so the n-th example of a class adds less than the
first. Modelling the effective number of examples as a geometric sum,
En=1−β1−βn,and weighting wc∝Enc1=1−βnc1−β
The parameter β∈[0,1) says how fast the overlap sets in: β=0
gives En=1 for all n (every example redundant beyond the first, so uniform
weights), and β→1 gives En→n (no overlap, recovering inverse
frequency).
Normalising so the two average to 1 across classes:
w−=0.1474,w+=1.8526,w−w+=12.5720
Step 8 — compare.
Scheme
w−
w+
ratio
none
1.0000
1.0000
1.00
inverse frequency
0.5263
10.0000
19.00
effective number, β=0.999
0.1474
1.8526
12.57
Effective-number weighting is less aggressive: 12.57 against 19. Its
argument is that the 950 negatives are not 950 independent facts, so
down-weighting them to one-nineteenth over-corrects. Whether that is right is an
empirical question about the data, and β is the knob that encodes the
answer.
Answer
wc=KncN⟹w−=0.5263,w+=10.0000,w−w+=19
Each class then contributes 500.0 of weighted mass, and the mean weight is
exactly 1.0000, so the loss scale is preserved.
Effective-number weighting at β=0.999 gives w−=0.1474,
w+=1.8526, a ratio of 12.5720 — a deliberately weaker correction.
Prints both schemes, the two weighted masses, the mean weight and both ratios.
Executed in CI. The digits above are the digits it printed.
Check — sanity
A balanced dataset gives unit weights. With n−=n+=500,
wc=1000/(2×500)=1 for both. A weighting scheme that changed
anything on balanced data would be wrong, and this one does not.
The ratio is forced by the counts alone.w+/w−=n−/n+=19 follows
from (i) without reference to N or K. So the ratio is a property of the
imbalance and the scale is a property of the normalisation — two independent
choices that are easy to confuse.
The two limits of β behave. At β=0: En=1 for every n, so
both weights are equal and the ratio is 1 — no correction. As β→1:
En→n by L’Hôpital, so wc∝1/nc and the ratio approaches 19 —
inverse frequency. The computed 12.57 lies between 1 and 19 as it must.
Dimensional check.N/(Knc) is a count over a count, so weights are
dimensionless and the weighted loss carries the loss’s own units. A weighting
scheme with units would be a rescaling in disguise.
Where this breaks
Step 2’s premise is that a class’s gradient contribution is proportional to its
count. That holds when every example’s loss has comparable magnitude — true at
initialisation, and false soon after.
Once the model has learned to classify the majority easily, those 950 examples
have small losses and, by (I.4.4), small gradients p−y. Their actual
contribution collapses well below 95%, and the fixed weight w−=0.5263
keeps suppressing them anyway. Static weights correct a static imbalance in a
dynamic quantity.
That observation is precisely the argument for focal loss (Lin et al., 2017),
which multiplies each example’s loss by (1−pt)γ — a factor computed
from the current prediction rather than from the class count. It down-weights
easy examples whichever class they belong to, and needs no counts at all.
Variation
A three-class problem has counts (900,90,10). Compute the inverse-frequency
weights and verify each class contributes N/3. Then find the β at which
effective-number weighting gives the rarest class exactly half the weight
inverse frequency would give it.
Gradients in scientific notation to 6 s.f.; ratios to 1 d.p.
STATEMENT
Construct a classification case in which squared loss produces a vanishing
gradient and cross-entropy does not. Derive both gradients with respect to the
logit, evaluate them at five logits, and identify precisely which factor is
responsible.
GIVEN
A binary classifier emitting a logit z, with p=σ(z) and target
y=1. Two candidate losses:
LMSE=21(p−y)2,LBCE=−[ylogp+(1−y)log(1−p)]
Recall σ′(z)=σ(z)(1−σ(z))=p(1−p) from I.3.B02.
FIND
dL/dz for each loss in closed form; both evaluated at
z∈{−1,−3,−5,−10,−20}; and their ratio.
STRATEGY
Differentiate each loss with respect to p, then apply the chain rule through
σ. The whole result turns on whether the σ′(z) factor survives or
cancels, so keep it visible rather than simplifying early.
SOLUTION
Step 1 — MSE’s gradient. Differentiating with respect to p first:
The σ′ factor cancelled exactly. The logarithm in the loss produced a
1/[p(1−p)] that met the p(1−p) from the sigmoid. This is the same
cancellation as I.4.B03’s Step 7, in the binary case.
Step 3 — compare the two closed forms.
dzdLMSE=(p−y)σ′(z),dzdLBCE=(p−y)
They differ by exactly one factor, σ′(z)∈(0,1/4]. So
dLMSE/dzdLBCE/dz=σ′(z)1=p(1−p)1
Step 4 — evaluate. With y=1:
z
p=σ(z)
MSE dL/dz
BCE dL/dz
ratio
−1
2.689414e−1
−1.437348e−1
−0.731059
5.1
−3
4.742587e−2
−4.303412e−2
−0.952574
22.1
−5
6.692851e−3
−6.603562e−3
−0.993307
150.4
−10
4.539787e−5
−4.539375e−5
−0.999955
22,028.5
−20
2.061154e−9
−2.061154e−9
−1.000000
485,165,197.4
Step 5 — read the two columns. As z becomes more negative the model becomes
more wrong: p→0 while y=1.
Cross-entropy’s gradient grows toward its maximum magnitude of 1. At
z=−20 it is −1.000000: the loss is shouting.
MSE’s gradient shrinks toward zero. At z=−20 it is −2.06×10−9.
In float32, where the smallest normal value is about 1.18×10−38, this
is still representable — but multiplied through a few more layers of I.3’s
saturation factors it is not, and in fp16 it underflowed long before.
The model is as wrong as it is possible to be, and MSE reports almost
nothing. That is the counterexample.
Step 6 — which factor is responsible. Not the squaring. Substituting
y=1 into (a):
dzdLMSE=(p−1)p(1−p)=−p(1−p)2
As p→0 this behaves as −p, and p=σ(z)→0 exponentially in
z. The culprit is the σ′ factor that (b) cancels and (a) keeps —
exactly the saturation of Chapter I.3, reaching the loss instead of a hidden
layer.
Step 7 — the other end, which is the honest caveat. At a point the model
already gets right:
Both shrink, and MSE shrinks faster. So MSE is not uniformly worse — it is
quieter everywhere. The asymmetry that matters is that cross-entropy stays loud
where the model is wrong and goes quiet where it is right, while MSE goes quiet
in both directions.
Answer
dzdLMSE=(p−y)p(1−p),dzdLBCE=p−y
They differ by the factor σ′(z)=p(1−p)≤1/4, which cross-entropy’s
logarithm cancels and squared loss does not.
At z=−10, y=1: MSE gives −4.539×10−5 against BCE’s
−0.999955, a ratio of 22,029. At z=−20 the ratio is
4.85×108.
Check — numeric · i-4-b06-mse-vanishes.py
d_mse = (p - y) * p * (1 - p) # chain rule through sigma'd_bce = p - y # sigma' cancels
Prints both columns at all five logits, their ratios, and the two
already-correct points.
Executed in CI. The digits above are the digits it printed.
Check — sanity
BCE’s gradient is bounded by 1. Every entry satisfies
∣p−y∣≤1 since p∈(0,1) and y∈{0,1}. The table’s largest is
−1.000000, approached but not exceeded ✓
The ratio equals 1/[p(1−p)] exactly. At z=−5:
1/(6.692851×10−3×0.993307)=150.4, matching the table’s ratio
column — computed from the closed form rather than by dividing the two columns,
so it is an independent check.
The two gradients agree where σ′ is largest. At z=0,
σ′=1/4, so the ratio would be 4 — the smallest it can ever be. The
table’s smallest ratio, 5.1 at z=−1, is consistent with approaching 4 as
z→0.
Signs are correct throughout. With y=1 and p<1, both gradients are
negative, so descent raises z — which is what should happen when the model
under-predicts the positive class.
Where this breaks
The vanishing is a property of the pair, not of squared loss alone. Remove
the sigmoid — regress on an unbounded output with squared loss, as in I.1.B03 —
and the gradient is (y^−y) with no saturating factor anywhere. Squared
loss is entirely well behaved for regression; it is squared loss composed with a
saturating output that fails.
The general lesson is worth stating in its own right: check what the loss and
the output nonlinearity do together, not separately. Cross-entropy pairs with
softmax and sigmoid because the logarithm inverts the exponential in them. Any
other pairing has to be checked, and the check is one line — differentiate and
see whether the output’s derivative cancels.
Variation
Repeat the derivation for MSE composed with a linear output on a
classification target in {0,1}. Show the gradient no longer vanishes, then
say what new problem appears instead — and why it makes the arrangement
unusable anyway.
A language model emits logits of shape (B,T,∣V∣). Trace every shape on the
path from that tensor to the single number the optimiser differentiates. Compute
the memory the logits occupy, and determine what masking does to the reduction —
including the size of the error if it is done wrongly.
GIVEN
Batch B=4, sequence length T=512, vocabulary ∣V∣=32,000. Targets
are token indices, shape (B,T). Fifteen per cent of positions are padding and
must be excluded. Cross-entropy is applied per position and then reduced to one
scalar.
FIND
The shape after each stage; the element count and memory of the logits in fp32
and bf16; and the two possible reductions under masking, with the discrepancy
between them.
STRATEGY
Follow the rank down. The logits are rank 3; the loss is rank 0. Two things
remove a rank — indexing away the vocabulary axis, and reducing away the
position axes — and the whole trace is deciding where each happens.
The shapes do not match, and they should not. The targets are indices, not
one-hot vectors: integers in [0,∣V∣), one per position. A one-hot target of
shape (4,512,32000) would hold the same information in
65,536,000 numbers instead of 2,048, of which all but 2,048 are
zero. Frameworks index rather than multiply for exactly this reason.
Step 2 — the element count.
B×T×∣V∣=4×512×32,000=65,536,000
Step 3 — flatten the position axes. Cross-entropy treats every position
independently, so the batch and time axes carry no meaning for it and can be
merged:
(4,512,32000)⟶(2048,32000),(4,512)⟶(2048,)
2048=4×512, and the element count is unchanged — a reshape moves no
data. Every framework’s cross-entropy expects exactly this two-dimensional form,
which is why calling it on rank-3 logits requires an explicit reshape.
Step 4 — the per-position loss. For each of the 2,048 rows, take the
row’s 32,000 logits and its one target index and produce one number:
(2048,32000)×(2048,)⟶(2048,)
The vocabulary axis is gone. This is where −zc+log∑jezj is
evaluated per row — never by forming probabilities first, for the reasons of
I.4.B04.
Step 5 — the reduction.(2048,)⟶(), rank 0. This is the
one number ∇θ is taken of, and Step 7 shows it is the step most
often got wrong.
And if softmax probabilities are materialised as a separate tensor of the same
shape — which the naive route of I.4.B04 requires — that doubles to
524.3 MB in fp32 and 262.1 MB in bf16.
This single tensor is often the largest in the model. At B=4 it already
rivals the activations of an entire transformer block, and it grows linearly in
both B and ∣V∣. It is why the loss is computed in chunks over the batch for
large vocabularies, and why ∣V∣ appears in memory budgets as prominently as
depth does.
Step 7 — masking, and the reduction it changes. With 15% padding:
total positions=2,048,valid positions=round(2048×0.85)=1,741
Padded positions contribute a loss of 0, having been masked. But there are two
different things one can then divide by.
Mean over all positions.20481i∑ℓi — divides
by the number of slots.
Mean over valid positions.17411i∑ℓi —
divides by the number of real tokens.
The ratio is
17412048=1.1763
so the first understates the loss by 17.6% relative to the second.
Why this matters more than it looks. The reported loss is wrong by a fixed
factor, which is merely embarrassing. The gradient is wrong by the same factor,
which is an unintended 17.6% reduction in effective learning rate. And the
factor is not fixed across batches: it depends on how much padding each batch
happens to contain, so the effective learning rate fluctuates from step to step
with the batch’s sequence-length distribution. Sorting examples by length into
buckets — done for speed — changes the padding fraction systematically, and so
silently changes the learning rate schedule.
Dividing by the valid count is the correct choice, and it is not the default in
every framework.
Answer
(4,512,32000)→(2048,32000)→(2048,)→()
Logits hold 65,536,000 values: 262.1 MB in fp32, 131.1 MB in bf16, and
double that if probabilities are materialised too.
With 15% padding, 1,741 of 2,048 positions are valid. Reducing over
all positions rather than valid ones understates the loss and the gradient by a
factor of 2048/1741=1.1763, or 17.6%.
Check — numeric · i-4-b07-loss-shapes.py
logits = B * T * Vvalid = round(B * T * (1 - PAD_FRACTION))print(f"ratio {total / valid:.4f}")
Prints the full shape trace, both memory figures, and the 1.1763 ratio.
Executed in CI. The digits above are the digits it printed.
Check — sanity
The reshape conserves elements.4×512×32000=65,536,000
and 2048×32000=65,536,000. A reshape that changed the count would
be a copy or a truncation, not a reshape.
Rank falls exactly twice. Rank 3→2 by the flatten, 2→1 by
indexing away the vocabulary, 1→0 by the reduction. Three drops, three
identifiable operations, no rank lost silently.
bf16 is exactly half of fp32.262.1/131.1=2.0, as two bytes against
four requires.
The masking ratio bounds correctly.1≤2048/1741≤1/0.85=1.1765.
The computed 1.1763 sits just inside, the difference being the rounding of
1741. At zero padding the ratio would be exactly 1 and the two reductions
would agree — which is why this bug is invisible on fixed-length data.
Where this breaks
The trace assumes every position has exactly one target. Two common cases break
it, and both are worth recognising by their shapes.
Soft targets. With label smoothing or distillation the target is a full
distribution, shape (2048,32000) rather than (2048,). The indexing step of
Step 4 becomes a contraction over the vocabulary axis, the targets now cost the
same memory as the logits, and the total doubles again.
Multi-label. When a position may carry several correct classes, softmax is
wrong outright — it forces the outputs to sum to one, and K independent
sigmoids with binary cross-entropy is the right structure instead. The shape
(2048,32000) survives but the reduction is over ∣V∣ as well as over
positions, and the loss is a sum of 32,000 binary terms per position rather
than one categorical term.
Variation
Recompute every figure for ∣V∣=128,000 at the same B and T. State the
new fp32 memory, and find the batch size at which the logit tensor alone exceeds
10 GB.
Exercises
Every one has a published solution. A hidden solution is a solution; a missing one is an abandonment.
I.4.X01Three losses, two moderate outliersnumeric▲△△
Compute MSE, MAE and Huber1 on the residuals
(1.0,−1.5,0.4,−2.5,0.1). Say which branch of Huber each residual
takes, and what share of each total the two residuals with ∣r∣>1 take
together.
Hint
Decide the branches before computing anything, as in I.4.B01.
Solution
Branches first.∣1.0∣=1.0≤1 — quadratic, exactly at the join.
∣−1.5∣>1 and ∣−2.5∣>1 — linear. ∣0.4∣ and ∣0.1∣ — quadratic.
Working the two linear-branch entries.Huber1(−1.5)=(1)(1.5−0.5)=1.0000 and
Huber1(−2.5)=(1)(2.5−0.5)=2.0000.
The shares. The two large residuals contribute
2.25+6.25=8.50 of 9.67; 1.5+2.5=4.0 of 5.5; and
1.0+2.0=3.0 of 3.585:
MSE 87.9%,MAE 72.7%,Huber 83.7%
What is different from I.4.B01. There, one extreme outlier at r=4 took
94% of MSE. Here two moderate ones at 1.5 and 2.5 take 87.9%. The
concentration is milder because the outliers are milder — MSE’s dominance grows
with the square of how unusual the outlier is, so it is a problem of degree,
not a switch that flips.
The residual at exactly ∣r∣=1 is worth noticing. It sits on the join, and
both branches give 0.5: quadratic 21(1)2=0.5, linear
(1)(1−0.5)=0.5. Continuity holds, as I.4.B01’s sanity check argued it must.
An implementation that used < where it should use ≤ would still give the
right answer here — which is exactly why such a bug survives testing.
I.4.X02Why Huber has that $-\tfrac12\delta$ in itsymbolic▲△△
Show that Huberδ is continuous and has a continuous derivative
at ∣r∣=δ. Then show that removing the −21δ term — using
δ∣r∣ on the outer branch — destroys continuity of the value while
leaving the derivative continuous, and say why that is the worse of the two
failures.
Hint
Evaluate both branches, and both their derivatives, at r=δ exactly.
Solution
Continuity of the value. At r=δ, approaching from inside:
21r2r=δ=21δ2
and from outside:
δ(r−21δ)r=δ=δ(δ−21δ)=δ⋅21δ=21δ2
Equal, so the function is continuous. The −21δ is precisely the
offset that makes the two branches meet.
Continuity of the derivative. Differentiating each branch:
drd21r2=r⟶δ at r=δdrdδ(r−21δ)=δ⟶δ everywhere on that branch
Both give δ. So Huberδ∈C1: value and slope both
match, and the function has no kink. It is not C2 — the second derivative
jumps from 1 to 0 — but C1 is what a first-order optimiser needs.
Removing the offset. Define H~(r)=21r2 for ∣r∣≤δ
and δ∣r∣ beyond. Its derivative on the outer branch is still δ, so
the derivative is still continuous. But the value jumps:
r→δ−limH~=21δ2,r→δ+limH~=δ2
a discontinuity of size 21δ2.
Why the value discontinuity is worse than a derivative one. This is the part
worth thinking about, because the naive ranking is the other way round.
A discontinuous derivative — a kink, as MAE has at zero — is survivable. The
subgradient convention of I.2.X09 covers it, the set of points where it matters
has measure zero, and every ReLU network already lives with it.
A discontinuous value is not survivable, for a reason that has nothing to do
with differentiability. The reported loss becomes uninterpretable: two models
whose residuals differ infinitesimally, one just inside δ and one just
outside, report losses differing by 21δ2. Loss curves acquire jumps
that look like instability and are not. Comparisons between runs with different
δ are meaningless. And any early-stopping or model-selection rule reading
the loss inherits the artefact.
Worse, gradient descent does not even notice: the gradients are identical to
Huber’s, so the optimisation proceeds normally while the number reported about it
is wrong. A bug that changes the metric but not the training is harder to find
than one that breaks training, because nothing fails.
The general form. Whenever a piecewise loss is defined, check the value and
the derivative at every join, separately. Continuity of one does not imply the
other, and they fail in different ways.
I.4.X03Squared loss asks for the conditional meanproof▲▲△
Prove that the constant c minimising E[(Y−c)2] is
c⋆=E[Y], and that the minimum value is Var(Y). Then
state the conditional version and say what it implies about what a
squared-loss-trained network is estimating.
Hint
Add and subtract E[Y] inside the square, then expand and use
linearity of expectation.
Solution
Step 1 — decompose. Write μ=E[Y] and insert μ−μ:
E[(Y−c)2]=E[((Y−μ)+(μ−c))2]
Step 2 — expand the square.
=E[(Y−μ)2+2(Y−μ)(μ−c)+(μ−c)2]
Step 3 — take expectations term by term, using linearity
(Expectation· 0.PR.02) and noting (μ−c) is a constant:
=Var(Y)E[(Y−μ)2]+2(μ−c)=0E[Y−μ]+(μ−c)2
The middle term vanishes because E[Y−μ]=E[Y]−μ=0
by the definition of μ. That cancellation is the whole proof.
Step 4 — read off the minimum.
E[(Y−c)2]=Var(Y)+(μ−c)2
The first term does not involve c; the second is a square, so non-negative,
and is zero exactly when c=μ. Hence
c⋆=E[Y],mincE[(Y−c)2]=Var(Y)
■
Step 5 — the conditional version. Applying the same argument at each x
separately, with all expectations conditioned on X=x:
f⋆(x)=E[Y∣X=x]
What this says about a trained network. Three things, in order of how often
they are missed.
The target of training is the conditional mean, not a sample. Given a dataset
with two identical inputs and different labels — say y=0 and y=10 — the
squared-loss optimum predicts 5, a value that appears nowhere in the data and
may be impossible. On a bimodal conditional distribution, the mean can sit in a
region of zero density.
The irreducible loss is the conditional variance.Var(Y∣X=x)
cannot be reduced by any model whatsoever. A training loss that has plateaued at
a nonzero value may be at the optimum, and no architecture change will move it.
Knowing that number — estimable from repeated measurements at the same input —
tells you when to stop trying.
The optimum is over all functions, not over the hypothesis class. The network
approaches E[Y∣X] only insofar as that function lies in its class and
the optimiser finds it. I.4.T2’s scope note says exactly this, and it is the same
gap I.1.T1 identified between existence and reachability.
The connection to blurry generative outputs. A model trained with squared
loss to produce images predicts the pixel-wise conditional mean. Where several
sharp outputs are equally plausible, their mean is a blur. This is not a failure
of capacity or of data — it is the loss doing exactly what this proof says it
does, and no amount of training fixes it. Changing the loss does.
I.4.X04Absolute loss asks for the medianproof▲▲△
Prove that the constant minimising E∣Y−c∣ is a median of Y. Then
contrast with I.4.X03 on a concrete skewed example, and state which loss to
choose when the two answers differ.
Hint
Differentiate under the expectation. The derivative of ∣y−c∣ with respect to
c is −sign(y−c), which takes only two values.
Solution
Step 1 — differentiate. For Y with a density, differentiating under the
expectation:
dcdE∣Y−c∣=E[∂c∂∣Y−c∣]=E[−sign(Y−c)]
Step 2 — write the sign as a difference of probabilities. Since
sign takes only ±1 (ignoring the measure-zero tie):
E[sign(Y−c)]=(+1)P(Y>c)+(−1)P(Y<c)=P(Y>c)−P(Y<c)
so
dcdE∣Y−c∣=P(Y<c)−P(Y>c)
Step 3 — set to zero.
P(Y<c)=P(Y>c)
which, with the two probabilities summing to 1, gives
P(Y<c)=P(Y>c)=21. That is the definition of a median.
■
Step 4 — confirm it is a minimum. The derivative P(Y<c)−P(Y>c) is
non-decreasing in c (as c rises, P(Y<c) rises and P(Y>c) falls), so it
crosses zero from below: negative then positive. That is a minimum, and the
objective is convex.
Step 5 — the contrast, made concrete. Take Y taking values
1,2,3,4,100 with equal probability 1/5.
Mean.(1+2+3+4+100)/5=110/5=22.
Median. The middle of five ordered values: 3.
Squared loss would have the model predict 22; absolute loss, 3. Four of the
five actual values are closer to 3 than to 22, and 22 is not near any of
them.
Step 6 — why the difference is structural, not a quirk. From Step 2, each
observation contributes ±1 to the derivative of E∣Y−c∣ —
its magnitude is irrelevant, only which side it is on. Changing 100 to
106 leaves the median at 3 and moves the mean to 200,002. Under squared
loss the derivative contribution is (c−y), proportional to distance, so one
distant point can outvote many near ones. This is the same fact as I.4.B01’s
derivative column, stated in expectation instead of on a sample.
Which to choose. The question is not which is more robust; it is which
summary you actually want reported.
If the quantity of interest is a total — total revenue, total dose, total
count — the mean is correct, because means add and medians do not. Predicting the
median and summing gives the wrong total.
If the quantity of interest is a typical case — a typical delivery time, a
typical house price — the median is correct, and the mean is distorted by a tail
you were never asking about.
If large errors are disproportionately costly, squared loss encodes that
directly, and choosing it is a statement about consequences rather than about
robustness.
The honest summary. “MAE is robust to outliers” is true and is the wrong
framing. Both losses answer a well-posed question exactly; they answer different
well-posed questions. Deciding between them means deciding which question you
are asking, which is a modelling decision and not a numerical one.
I.4.X05The finite logit gap label smoothing asks forsymbolic▲▲△
With one-hot targets, cross-entropy is minimised only as the true-class logit
goes to infinity. Show that label smoothing replaces that with a finite optimum,
derive the optimal logit gap, and evaluate it for ε=0.1, K=3.
Hint
The gradient is still p−y′ by I.4.B03 — that derivation never
needed y to be one-hot, only to sum to one.
Solution
Step 1 — the smoothed target. For true class c,
yk′=(1−ε)1[k=c]+Kε
Check it sums to one: (1−ε)(1)+K⋅ε/K=1−ε+ε=1 ✓.
That is the only property I.4.B03’s Step 8 used, so the gradient result carries
over unchanged:
∂z∂L=p−y′
Step 2 — set the gradient to zero. The stationary point is p=y′:
pc=1−ε+Kε,pj=Kε(j=c)
These are attainable probabilities, both strictly inside (0,1). Contrast
with ε=0, where the requirement is pc=1 and pj=0 — values
softmax approaches but never reaches for finite logits.
Step 3 — convert to a logit gap. From pi=ezi/S, the ratio of two
probabilities has the shared denominator cancel:
pjpc=ezjezc=ezc−zj
Taking logarithms,
zc−zj=logpjpc=log(ε/K1−ε+ε/K)
Step 4 — simplify. Multiply numerator and denominator by K:
Or from the closed form: (3(0.9)+0.1)/0.1=2.8/0.1=28 ✓.
Step 6 — the limits. As ε→0+ the argument of the logarithm
is K/ε→∞, so the gap diverges — recovering the unsmoothed
case where no finite logit configuration is optimal. As ε→1 the
argument tends to 1 and the gap to 0: the target becomes uniform and the
model is asked to predict nothing at all.
What this buys, and what it costs.
Bounded logits. The optimum is at a gap of 3.33 rather than at infinity, so
there is no incentive to keep growing the weights. That is a regularisation
effect, obtained without a penalty term.
Better calibration. An unsmoothed model driven toward pc=1 is
systematically overconfident. Smoothing caps the confidence at a chosen value,
and 0.9333 is a defensible one.
Worse for distillation. Müller et al. (2019) show smoothing collapses the
geometry of the penultimate layer: the logits of the wrong classes are pushed to
be equally wrong, destroying the relative information a student model would
learn from. A smoothed teacher is a worse teacher, and this is the standard
reason not to smooth when distillation is planned.
A caution on reading the loss. The minimum value is no longer zero. At the
optimum the loss equals the entropy of y′, which for ε=0.1,
K=3 is −0.9333log0.9333−2(0.0333)log0.0333=0.0644+0.2266=0.2910
nats. A smoothed run that plateaus at 0.29 has converged; comparing it to an
unsmoothed run’s 0.05 is comparing two different objectives.
I.4.X06A step that improves the loss and worsens the accuracycounterexample▲▲△
Construct a two-example case in which cross-entropy strictly decreases while
accuracy strictly decreases as well. Give both numbers before and after, and
explain the mechanism in one sentence.
Hint
Accuracy counts only which side of 0.5 each prediction is on. Cross-entropy
also counts how far.
Solution
The construction. Two examples, both with label y=1.
before
after
example A
p=0.51
p=0.49
example B
p=0.10
p=0.60
Accuracy. With threshold 0.5:
Before. A is correct (0.51>0.5), B is wrong (0.10<0.5). Accuracy
=1/2=50%.
After. A is now wrong (0.49<0.5), B is now correct (0.60>0.5). Accuracy
=1/2=50%.
That is a tie, so push it further. Take three examples, all y=1:
before
after
A
0.51
0.49
B
0.51
0.49
C
0.10
0.98
Accuracy before: A ✓, B ✓, C ✗ — 2/3=66.7%.
Accuracy after: A ✗, B ✗, C ✓ — 1/3=33.3%. Halved.
Cross-entropy. With y=1 the loss per example is −logp.
The loss fell from 1.2164 to 0.4823 — a 60% improvement — while accuracy
fell from 66.7% to 33.3%.
The mechanism in one sentence. Accuracy is a step function of each
prediction and cannot see the difference between 0.51 and 0.98, while
cross-entropy is a smooth function of it and rewards the enormous gain on C far
more than it punishes the two tiny losses on A and B.
Why this is not a pathology. Gradient descent requires a differentiable
objective, and accuracy has zero gradient almost everywhere — its derivative is
zero wherever it is defined, and undefined at the threshold. It is unoptimisable
by any first-order method. So the loss is not an approximation to accuracy that
occasionally goes wrong; it is a different objective, chosen because it is
differentiable, and the two agreeing most of the time is a convenience rather
than a guarantee.
What follows in practice. Three habits.
Report both. A run whose loss improves while its validation accuracy stalls is
not necessarily broken, and is not necessarily fine either. Only both numbers
together say which.
Select on the metric you care about. Early stopping on validation loss and
early stopping on validation accuracy choose different checkpoints, and the gap
widens with calibration effects. Choose deliberately.
Do not read a small loss improvement as a small accuracy improvement. There is
no monotone relationship between them, as this construction shows in three lines.
Chapter VIII.5 makes this quantitative for model comparison; the same disconnect
between a differentiable surrogate and the quantity of interest reappears there
as the difference between AUROC and clinical utility.
I.4.X07When the implied noise model is falsecounterexample▲▲△
The first assumption of this chapter is that the loss’s implied noise model
matches the data. Take count data, show all three Gaussian properties fail,
quantify one of the failures, and name the loss that does not fail.
Hint
I.4.B02 identified three properties the Gaussian asserts. Check each against a
Poisson count.
Solution
The data. Read counts from an RNA-sequencing experiment: a gene’s expression
in one cell, a non-negative integer, typically between 0 and a few thousand,
with most genes at 0 in most cells.
The three Gaussian assertions, checked in turn.
Symmetry — false. If the model predicts y^=3, the residual can be
−3 at most (the count cannot go below zero) but can be +100 or more. The
error distribution is right-skewed by construction, and squared loss treats
−3 and +3 as equally likely and equally costly.
Constant variance — false, and quantifiably so. For a Poisson count,
Var(Y)=E[Y]: the variance equals the mean. A gene
expressed at 10 has standard deviation 10=3.16; one expressed at
1000 has 1000=31.6. Squared loss assumes one σ2 for both.
Quantify what that costs. Maximum likelihood weights each residual by
1/σi2; squared loss weights every residual equally. So relative to the
correct weighting, squared loss over-weights the high-expression gene by
σlow2σhigh2=101000=100
A hundredfold. The fit is dominated by a handful of highly expressed genes
whose residuals are large only because their noise is large. In practice these
are housekeeping genes, and the model spends its capacity on the least
informative part of the data.
Unbounded support — false. The Gaussian assigns positive density to
y=−5, an impossible count, and a squared-loss model will happily predict
negative values. Every such prediction is not merely inaccurate but
meaningless.
A fourth failure specific to this data. Counts are discrete and heavily
zero-inflated: a typical single-cell matrix is over 90% zeros. A continuous
symmetric density is a poor description of a distribution with an atom at zero
holding most of its mass.
The loss that does not fail. The negative log-likelihood of a negative
binomial:
p(y∣μ,ϕ)=(yy+ϕ−1−1)(μ+ϕ−1μ)y(μ+ϕ−1ϕ−1)ϕ−1
with mean μ and variance μ+ϕμ2. It is discrete, supported on
non-negative integers, right-skewed, and its variance grows with its mean — with
ϕ tuning how much faster than Poisson. Chapter VII.2 derives it as a
Poisson–Gamma mixture and Chapter VII.5 builds a model on it.
The route from here to there is I.4.B02 run forwards. Write the density, take
the negative logarithm, discard the terms free of θ, and what remains is
the loss. That is the general procedure, and squared error is only the instance
of it where the density happens to be Gaussian.
The habit this exercise is for. Before choosing a loss, write down the
noise model it implies and ask whether you believe it. Two minutes of that
catches most of the failures in this exercise — and the failure mode when it is
skipped is not a crash but a model that trains, converges, and is quietly fitting
the wrong thing.
I.4.X08The reduction is a choice, and it moves the learning rateshape▲▲△
The second assumption of this chapter is that the reduction is a plain mean over
examples. Show that summing instead of averaging changes the effective learning
rate, quantify it for two batch sizes, and identify a case where the choice
varies within a training run.
Hint
The gradient of a sum is n times the gradient of a mean.
Solution
Step 1 — the two reductions.
Lmean=n1i=1∑nℓi,Lsum=i=1∑nℓi=nLmean
Step 2 — the gradients. Differentiation is linear, so the factor passes
straight through:
∇θLsum=n∇θLmean
Step 3 — the update. With learning rate η:
θ←θ−η∇Lsum=θ−(nη)∇Lmean
Summing rather than averaging is exactly training at learning rate nη.
Not approximately, and not “roughly like a bigger step” — identically.
Step 4 — quantify. At n=32 and η=10−3, the effective rate under
summation is 3.2×10−2; at n=256 it is 2.56×10−1. The
same code, the same η, and an eightfold difference in effective rate purely
from the batch size. A configuration tuned at n=32 diverges at n=256,
and the reduction is nowhere in the hyperparameter file.
Step 5 — the case that varies within a run. This is the part worth
remembering, because it is invisible.
Consider token-level cross-entropy over variable-length sequences with padding,
as in I.4.B07. Suppose the implementation sums the per-token losses and divides
by the batch size rather than by the token count:
L=B1∑b∑tℓbt
Then a batch of long sequences has more tokens contributing to the same
denominator, so its gradient is larger. With B=4:
A batch averaging 500 tokens per sequence contributes about 2,000 token
losses over a denominator of 4 — an effective per-token weight of 500.
A batch averaging 50 tokens contributes 200 losses over the same
denominator — an effective weight of 50.
A tenfold swing in effective learning rate, batch to batch, driven entirely
by the sequence lengths that happened to be sampled. And length-bucketing —
grouping similar lengths together for throughput — makes it systematic rather
than random: early buckets of short sequences train at one rate and later buckets
of long ones at another.
Step 6 — the correct reduction, and the check. Divide by the number of
valid tokens:
L=∑b,tmbt∑b,tmbtℓbt
with m the mask. Then the denominator tracks the numerator and the effective
per-token weight is 1 regardless of lengths or padding.
The check is one line: log the denominator. If it varies across steps by more
than the padding fraction should allow, the reduction is wrong. Nothing else in
the run will tell you.
Why this belongs with the losses rather than with the engineering. The
reduction does not appear in the loss’s formula and is not part of its
definition — which is exactly why it is assumed rather than stated, and why the
assumption is worth writing down as this chapter does.
I.4.X09Focal loss, and the gradient it reshapesgradient▲▲△
Focal loss is FL=−(1−pt)γlogpt, where pt is the
probability assigned to the true class. Tabulate the modulating factor, derive
dFL/dz for the binary case, evaluate at five
logits with γ=2, and say how it differs from the class weighting of
I.4.B05.
Hint
Use the product rule on −(1−p)γlogp, then chain through
dp/dz=p(1−p).
Solution
Step 1 — the modulating factor.
pt
γ=0
γ=1
γ=2
γ=5
0.10
1.00000
0.90000
0.81000
0.59049
0.50
1.00000
0.50000
0.25000
0.03125
0.90
1.00000
0.10000
0.01000
0.00001
0.99
1.00000
0.01000
0.00010
0.00000
At γ=0 the factor is 1 everywhere and focal loss is cross-entropy.
As γ grows, well-classified examples (pt near 1) are suppressed
sharply while hard ones (pt near 0) are barely touched: at γ=2 the
suppression is 100× at pt=0.9 and only 1.23× at pt=0.1.
Step 2 — derive the gradient. Write L=−(1−p)γlogp with y=1,
so pt=p. By the product rule on the two p-dependent factors:
taking care with the sign: dpd(1−p)γ=−γ(1−p)γ−1,
and the leading minus of L flips it back.
Step 3 — chain through the sigmoid. With dp/dz=p(1−p):
dzdL=[γ(1−p)γ−1logp−p(1−p)γ]p(1−p)
Distribute p(1−p) into the bracket:
=γp(1−p)γlogp−(1−p)γ+1
and factor out (1−p)γ:
dzdL=(1−p)γ(γplogp+p−1)
Check it reduces correctly. At γ=0: (1)(0+p−1)=p−1=p−y,
which is I.4.4 ✓.
Step 4 — evaluate at γ=2, y=1.
z
p
CE
FL
dCE/dz
dFL/dz
−4.0
0.01799
4.01815
3.874907
−0.98201
−1.086396
−2.0
0.11920
2.12693
1.650078
−0.88080
−1.076714
0.0
0.50000
0.69315
0.173287
−0.50000
−0.298287
2.0
0.88080
0.12693
0.001804
−0.11920
−0.004871
4.0
0.98201
0.01815
0.000006
−0.01799
−0.000017
Step 5 — read the last column. At z=4 — an example the model already
gets right — cross-entropy still sends −0.01799, while focal loss sends
−0.000017: a thousandfold smaller. At z=−4 — an example it gets wrong —
focal loss sends −1.086, larger in magnitude than cross-entropy’s −0.982.
So focal loss does not merely rescale; it reorders. Under cross-entropy the
hard example’s gradient is 55× the easy one’s; under focal loss it is
64,000×.
Step 6 — how this differs from class weighting.
class weighting (I.4.B05)
focal loss
computed from
the class counts
the current prediction
fixed during training
yes
no
distinguishes easy from hard
no
yes
needs counts
yes
no
Class weighting asks which class is this? and applies a constant. Focal loss
asks how wrong is the model here, right now? and applies a factor that changes
every step.
That difference is exactly the objection raised in I.4.B05’s Where this breaks:
static weights correct a static imbalance in a quantity that is not static. Once
the model has learned the majority class, those examples’ gradients have already
collapsed by (I.4.4), and the fixed weight keeps suppressing them anyway. Focal
loss suppresses them because they are easy, and stops suppressing anything that
becomes hard again.
The cost.γ is a new hyperparameter with no principled setting — the
original paper’s γ=2 was chosen by sweep — and the loss no longer has
the log-likelihood interpretation of I.4.T1. It is a heuristic reshaping of a
principled loss, and worth using with that clearly in view.
I.4.X10What a per-example loss cannot encodelimit▲▲▲
The chapter’s open exercise. Every loss in this chapter has the form
n1∑iℓ(y^i,yi) — a mean of a function of one prediction and
one target. Determine what objectives that form structurally cannot express, and
give a worked case for at least two of them.
Hint
Ask what happens to ℓ if you shuffle the examples, or if you change the
prediction for one example while holding the rest fixed.
Solution
The structural constraint. Two properties follow from the form alone, before
any particular ℓ is chosen.
Permutation invariance. The mean is unchanged by reordering, so no objective
that depends on the order or grouping of examples can be expressed.
Separability.∂L/∂y^i depends on example i alone. No
objective in which the right prediction for one example depends on the
predictions made for others can be expressed.
Everything below is a consequence of one of these two.
Case 1 — a ranking objective (separability fails)
The objective. Rank documents so relevant ones come above irrelevant ones.
What matters is the relative order of scores, not their values.
Why it cannot be written per example. Take two documents with true relevance
1 and 0 and scores y^A=0.6, y^B=0.4. The ranking is
correct. Now consider 0.9 and 0.8: also correct. And 0.3, 0.2: also
correct. A per-example loss must assign each of these six predictions a value
based on that prediction alone, yet the quantity of interest — is A above
B? — is identical in all three.
Worse, it can be destroyed by changing only B: with y^A=0.6 fixed,
y^B=0.4 is correct and y^B=0.7 is not. So the correct value
for B depends on A‘s prediction, which separability forbids.
Worked numbers. Under per-example squared loss with targets (1,0):
The loss prefers the first, though both rank correctly and the second is more
confident. And:
(0.5,0.5):21[(0.5)2+(0.5)2]=0.2500
which ranks incorrectly (a tie) yet scores better than (0.9,0.8), which
ranks correctly. The loss and the objective disagree in sign.
What is done instead. Pairwise losses of the form ℓ(y^A−y^B),
which are per-pair rather than per-example — a different form, with O(n2)
terms and a gradient that couples examples.
Case 2 — a constraint across examples (permutation invariance fails)
The objective. Predicted probabilities should be calibrated: among examples
predicted at 0.7, about 70% should be positive.
Why it cannot be written per example. Calibration is a statement about a
set of predictions. For any single prediction there is no fact of the matter —
p=0.7 on one example with label 1 is neither calibrated nor miscalibrated.
The quantity requires binning, and binning requires seeing the other examples.
Worked numbers. Ten examples, all predicted p=0.7, of which 7 are
positive. Perfectly calibrated. Cross-entropy:
Now a model predicting p=1.0 for the seven positives and p=0.0 for the
three negatives — also perfectly calibrated, and with loss 0. And one
predicting 0.7 for all ten when only 3 are positive — badly miscalibrated —
gives
103(0.3567)+7(1.2040)=0.9498
So the loss does respond to calibration here, but only through accuracy: it
cannot distinguish “well calibrated and uncertain” from “poorly calibrated”,
because it never sees a group.
Case 3 — fairness across a subgroup (both fail)
The objective “the error rate on group A must not exceed group B’s by more than
ε” is a constraint on two aggregates. A per-example loss can
approximate it with group weights, as I.4.B05 does — but weights control expected
contribution, not a realised gap, and the constraint can be violated while every
weight is respected. This is the same gap between a surrogate and a target that
I.4.X06 exhibited for accuracy.
The strongest true claim
A per-example mean is a separable, permutation-invariant objective. Any
quantity of interest that is genuinely a property of the set of predictions —
an ordering, a rate within a group, a distributional match, a constraint
between subgroups — is not in that class, and can only be approached by a
surrogate whose disagreement with the target has to be measured rather than
assumed.
Why the form is used anyway. Separability is what makes the gradient
computable in one pass and the loss decomposable over a minibatch. Give it up and
the gradient of one example requires the others, minibatching becomes an
approximation rather than an identity, and the whole training loop changes shape.
That is a real cost, and it is why the answer is nearly always a surrogate plus a
separately reported metric — which is exactly the discipline Chapter VIII.5 is
about.