Before this lesson:lesson 04 (exp, log and the log
rules), lesson 02(∑, max and argmax) and
lesson 03 (arrays, axis, broadcasting).
Time: about 55 minutes, plus the notebook.
Almost every classifier ends with these functions. Logistic regression is σ(w⊤x+b).
An image classifier or a language model ends with a softmax over its classes or its vocabulary,
and is trained with the cross-entropy loss LSE(z)−zy. Attention in a transformer
turns similarity scores into weights with a softmax. When a chatbot "samples with temperature 0.7",
it divides the logits by 0.7 before the softmax. The stable formulas of this lesson are inside
torch.nn.CrossEntropyLoss, torch.logsumexp and scipy.special.logsumexp; when you write your
own loss, you need them too.
One score, one probability: the sigmoid. The sigmoid (also called the logistic function)
is
σ(z)=1+e−z1.
Read the formula from the inside. For large positive z,e−z is close to 0, so σ(z) is
close to 1. For large negative z,e−z is huge, so σ(z) is close to 0. At z=0,σ(0)=1/(1+1)=1/2. The graph is an S-shaped curve from 0 to 1. In a model, the score
is often z=wx+b: the weight w sets how steep the S is, and the curve crosses 1/2 where
wx+b=0, at x=−b/w.
Interactive figure: loading…
Move w and b, and drag the blue point. The orange curve is
p(x)=σ(wx+b). The yellow dot is the centre x=−b/w, where
p=1/2; the aqua line is the tangent there, with slope w/4. Predict
first: what does w<0 do? Then move the point far to one side: the curve is flat there and its
slope is almost 0 (a saturation warning appears).
Many scores, one probability vector: the softmax. For n classes with logits
z=(z1,…,zn), the softmax is
softmax(z)k=∑j=1nezjezk,k=1,…,n.
Two steps: exponentiate (every ezk is positive, and a larger zk gives a larger ezk),
then normalize (divide by the sum, so the entries add up to 1). A temperatureT>0
divides the logits first: softmax(z/T).
Interactive figure: loading…
Predict, then move. The orange bars are softmax((z+c)/T)
for the four logits z1,…,z4. First move the slider "add c to all": the logits change, the
bars do not. Then make T small (the bars become one-hot) and large (the bars become equal). Try
"all negative": softmax works, but the naive ratio zk/∑jzj below the bars gives
negative "probabilities".
Quick check
σ(2)≈0.881. What is σ(−2)?
Why.
The S-curve is symmetric around the point (0,1/2):σ(−z)=1−σ(z), so σ(−2)=1−0.881=0.119. A sigmoid value is always between 0 and 1, so −0.881 and 1.135 are impossible.
Quick check
The logits are z=(1,3,2). What does softmax(z/T) approach as the temperature T goes to 0?
Why.
Dividing by a tiny T makes the gaps between logits huge, so all probability goes to the largest logit, z2=3: a one-hot vector at the argmax. The uniform vector is the limit for T→∞. The last option puts the 1 at the last position, not at the largest logit.
Range (0,1).e−z>0, so the denominator is larger than 1: 0<σ(z)<1.
The values 0 and 1 are never reached; they are limits as z→−∞ and z→+∞.
Increasing. When z grows, e−z shrinks, the denominator shrinks, and σ(z) grows.
Symmetry:σ(−z)=1−σ(z).Proof.1−σ(z)=1+e−z1+e−z−1=1+e−ze−z.
Multiply the numerator and the denominator by ez:ez+11=σ(−z).■
Another form:σ(z)=1+ezez (multiply the numerator and the denominator by ez).
The inverse of the sigmoid is the logit. For a probability p∈(0,1), the odds are
p/(1−p) (for example, p=0.8 gives odds 4, "4 to 1"). The logit is the log of the odds:
logit(p)=log1−pp.
Why it inverts σ. Let p=σ(z)=1/(1+e−z).
Take the reciprocal: 1/p=1+e−z, so e−z=(1−p)/p.
Take the log: −z=logp1−p, so z=log1−pp.■
So the score z of a sigmoid model is exactly the log-odds of its probability. Example:
logit(0.8)=log4≈1.386, and σ(1.386)≈0.8.
Naming. "Logit" is a function of a probability. In deep learning, logits (plural) means the
raw scores that go into a sigmoid or a softmax. For a sigmoid the two meanings agree; for a softmax,
the logits are log-probabilities up to one shared constant (section 3.5).
Slope of the sigmoid. The slope (derivative) of σ at z is
σ′(z)=σ(z)(1−σ(z)).
We use this formula here without proof; lesson 07
checks it. Since s(1−s)=41−(s−21)2, the slope is at most 1/4, reached at
z=0. For large ∣z∣ the slope is tiny: σ′(5)≈0.0066,σ′(10)≈0.000045.
This flatness is called saturation; it is one cause of vanishing gradients in deep networks.
For p(x)=σ(wx+b) the slope at the centre x=−b/w is w⋅41=w/4
(the chain rule, lesson 07).
Logistic regression in one paragraph. For inputs x∈Rn, logistic regression models
P(y=1∣x)=σ(w⊤x+b). It predicts class 1 when this probability is at least
1/2, that is, when w⊤x+b≥0. So the boundary between the classes is the flat set
w⊤x+b=0 (a line in R2, a plane in R3), and w⊤x+b is the log-odds of class 1.
pk>0 for every k (an exponential is positive, and so is a sum of them);
∑kpk=∑kezk/∑jezj=1;
order is kept: zi>zj implies pi>pj (because ez is increasing and all pk share
one denominator). So argmaxkpk=argmaxkzk.
Why the exponential? The simpler idea "divide by the sum", zk/∑jzj, fails:
with z=(−1,2) it gives (−1,2): a negative "probability" and one larger than 1;
with z=(1,−1) the sum is 0: division by zero;
it changes when you add the same number to every score.
The exponential makes every score positive, keeps the order, and turns differences of scores into
ratios of probabilities: pi/pj=ezi−zj.
Theorem (shift invariance). For every real number c,softmax(z+c1)=softmax(z), where z+c1=(z1+c,…,zn+c).
Proof.
By the rule ea+b=eaeb (lesson 04): ezk+c=ecezk.
So softmax(z+c1)k=∑jecezjecezk=ec∑jezjecezk.
Cancel ec=0: the result is softmax(z)k.■
So only the differences between logits matter. This is the reason for the max trick of section 3.6.
Two classes give the sigmoid. With logits (z,0):
softmax(z,0)1=ez+e0ez=ez+1ez=σ(z).
By shift invariance, softmax(z1,z2)1=softmax(z1−z2,0)1=σ(z1−z2).
So a binary classifier needs only one score: the difference of the two logits.
For T>0,p(T)=softmax(z/T). Then pi(T)/pj(T)=e(zi−zj)/T.
T=1: the ordinary softmax.
T→0: if the largest logit zk is unique, p(T)→ the one-hot vector at k.Reason:pk(T)=1/∑je(zj−zk)/T. For j=k,zj−zk<0, so
(zj−zk)/T→−∞ and e(zj−zk)/T→0. The sum tends to e0=1, so
pk(T)→1. If several logits tie for the maximum, the probability is split equally between them.
T→∞:z/T→0, and softmax(0,…,0)=(1/n,…,1/n), the uniform vector.
Example with z=(1,2,3):T=0.5 gives (0.016,0.117,0.867),T=1 gives
(0.090,0.245,0.665),T=10 gives (0.301,0.332,0.367).
So the softmax is a smooth version of the argmax (as a one-hot vector); a better name would be
"soft argmax". Language models sample the next token from softmax(z/T):
small T gives safe, repetitive text, large T more varied text, and T→0 is greedy decoding
(always the most likely token).
It is the log of the softmax normalizer. Its name says what it does, from the inside out.
Theorem (LSE is close to the max). Let m=maxjzj. Then
m≤LSE(z)≤m+logn.
Proof of the bounds
One of the terms of ∑jezj is em, and the other terms are positive. So ∑jezj≥em.
Every term is at most em, because zj≤m and ez is increasing. So ∑jezj≤nem.
Take logs (the log is increasing, so it keeps ≤):m≤LSE(z)≤log(nem)=m+logn.■
The upper bound is an equality exactly when all zj are equal. The lower bound is strict when n≥2,
because then the other terms are >0.
Examples: LSE(1,2,3)≈3.408, which is in [3,3+log3]≈[3,4.099].LSE(5,5)=log(2e5)=5+log2≈5.693: the upper bound, since the two numbers are equal.
With a temperature, TLSE(z/T) lies in [m,m+Tlogn], so it tends to the
max as T→0. For two numbers z=(x,0),LSE(x,0)=log(1+ex) is the
softplus function, a smooth version of max(x,0) (the ReLU).
Interactive figure: loading…
Lower the temperature T. The blue kinked curve is max(x,0); the
orange curve is TLSE(z/T) for z=(x,0). It always stays
inside the yellow band[max,max+Tlog2], and the gap is largest at
x=0, where the two numbers are equal. The aqua tangent has slope
σ(x/T): the slope of LSE is the softmax.
Two more facts. First, LSE(z+c1)=LSE(z)+c (take ec
out of the sum, as in the proof of shift invariance). Second, the log-softmax: take the log of the
softmax and use the quotient rule of lesson 04,
logsoftmax(z)k=zk−logj∑ezj=zk−LSE(z).
Quick check
What is LSE(5,5)=log(e5+e5)?
Why.
e5+e5=2e5, and log(2e5)=log2+5. This is the upper bound max+logn with n=2: equal numbers give the largest gap. The answer 5 would be the exact max, but LSE is always a bit larger. The answer log10 adds the numbers before the exponential.
A classifier with logits z and true class y is trained with the cross-entropy loss, the
negative log-probability of the true class:
ℓ(z,y)=−logsoftmax(z)y=LSE(z)−zy.
The right-hand side never forms a probability, so it never takes log0. For z=(1,2,3):y=3 gives 3.408−3=0.408 (a confident, correct prediction, small loss); y=1 gives
3.408−1=2.408 (a large loss). The /information-theory/ track explains why this loss is a
cross-entropy.
The problem. A float64 number is at most about 1.8×10308, so ezoverflows to
inf for z>709.78(=log(1.8×10308)). In float32 (common on GPUs) the limit is
z>88.72. In the other direction, ezunderflows to 0 for z below about −745 in float64.
Naive softmax of (1000,1001,1002): every ezk is inf, and inf / inf is nan.
Naive softmax of (−1000,−1001,−1002): every ezk is 0, and 0 / 0 is nan.
The fix. Let m=maxjzj and use shift invariance with c=−m:
Every zj−m≤0, so every term ezj−m≤1: no overflow.
The term with zj=m is e0=1, so the sum is at least 1: no division by 0, and the log of the sum is ≥0.
Terms with zj−m<−745 underflow to 0. This is harmless: their true probability is below
10−323 anyway.
Log-softmax in one step. Compute zk−LSE(z) with the stable LSE. Never compute
np.log(softmax(z)) in two steps: for z=(0,1000), even the stable softmax gives (0,1) in
float64 (the true first entry e−1000 underflows), and log0=−∞, while the true value
z1−LSE(z) is −1000.
Interactive figure: loading…
Step through the two columns. The naive column computes ezk first and fails
(inf and nan in magenta). The stable column subtracts the max
m first and gives the correct probabilities. Try "−1000, −1001, −1002"
(underflow) and "0, 1000" (the log-softmax row). Then choose "88, 89, 90" and switch to float32:
there the limit is 88.72, not 709.78 (the figure rounds each step with Math.fround to simulate float32).
Stable sigmoid.σ(z)=1/(1+e−z) computes e1000 for z=−1000. The result
happens to be right (0), but NumPy warns about the overflow, and logσ(z) becomes log0.
Use 1/(1+e−z) for z≥0 and ez/(1+ez) for z<0: the exponent is then never
positive. Libraries do this: scipy.special.expit, torch.sigmoid, and for losses
torch.nn.functional.logsigmoid and BCEWithLogitsLoss.
In practice use the library functions: scipy.special.softmax, log_softmax, logsumexp;
torch.softmax, torch.log_softmax, torch.logsumexp; and torch.nn.CrossEntropyLoss, which takes
logits (not probabilities) for this reason.
Quick check
Why does stable code compute softmax(z−maxjzj) instead of softmax(z)?
Why.
Shift invariance says that subtracting the same number from all logits changes nothing. After the shift every exponent is ≤0, so no term overflows, and one term equals 1, so the sum is at least 1. In exact arithmetic both formulas give the same numbers. Negative logits are no problem for ez; after the shift they are all ≤0.
Accuracy, the gradient of LSE, and multi-label outputs
Gradient of LSE. The partial derivative of LSE with respect to zk is
softmax(z)k (the /calculus/ track derives it). So the gradient of the
cross-entropy LSE(z)−zy is softmax(z)−ey, where ey is
the one-hot vector of the true class: "predicted minus true". The figure above shows the
2-class case: the slope of log(1+ex) is σ(x).
Accuracy. Blanchard, Higham and Higham (2021) analyse the rounding errors of the shifted
formulas and show that they are accurate; they also discuss log1p for the case where one term
dominates: LSE(z)=m+log1p(∑j=kezj−m).
Sigmoid or softmax? Softmax for one class out of n (the probabilities compete and sum to 1).
Independent sigmoids for multi-label problems, where an image can contain a cat and a dog:
each class gets its own yes/no probability, and they need not sum to 1.
Answers to section 1. (1) The same: (101,102,103)=(1,2,3)+100⋅1, and the
softmax is shift invariant. Both give (0.090,0.245,0.665). (2) nan in every entry: each
ezk is inf, and inf / inf is nan. Subtracting the max first gives the correct
(0.090,0.245,0.665). (3) σ(−2)=1−σ(2)≈0.119.
Take the logits z=(1,2,3) of a 3-class classifier.
(a) Softmax, naive order.
Exponentials: e1≈2.718,e2≈7.389,e3≈20.086.
Sum: s=2.718+7.389+20.086=30.193.
Divide: p=(2.718,7.389,20.086)/30.193≈(0.090,0.245,0.665). The entries add up to 1.
(b) Softmax with the max trick.m=3, so z−m=(−2,−1,0).
Exponentials: e−2≈0.1353,e−1≈0.3679,e0=1.
Sum: s′=1.5032 (at least 1, as promised).
Divide: p≈(0.0900,0.2447,0.6652): the same as in (a), because s=e3s′.
(c) Log-sum-exp, both ways. Naive: log30.193≈3.4076. Stable: m+logs′=3+log1.5032=3+0.4076=3.4076.
The bounds hold: 3≤3.4076≤3+log3≈4.0986.
(d) Log-softmax and cross-entropy.logp=z−LSE(z)=(1,2,3)−3.4076=(−2.4076,−1.4076,−0.4076).
Check: e−0.4076≈0.665 ✓. If the true class is y=3, the loss is 0.4076; if it is y=1, the loss is 2.4076.
(e) Temperature.T=0.5:z/T=(2,4,6), and the same steps give (0.016,0.117,0.867): sharper.
(f) Two classes. For logits (2,0):softmax(2,0)1=e2/(e2+1)=7.389/8.389≈0.881=σ(2).
And logit(0.881)=log(0.881/0.119)≈2: back to the score.
Quick check
A spam filter outputs p=0.8 for "spam" with a sigmoid. What score (logit) z did it compute?
Why.
The score is the log-odds: z=log1−pp=log0.20.8=log4≈1.386. The value 4 is the odds before the log. log0.8 forgets the 1−p in the denominator. Check: σ(1.386)=1/(1+1/4)=0.8 ✓.
Logistic regression and every binary classifier: P(y=1∣x)=σ(w⊤x+b); the
loss is the binary cross-entropy −ylogσ(z)−(1−y)log(1−σ(z)), computed stably from
the logit z by BCEWithLogitsLoss.
The output layer of classifiers. Image classifiers (1000 ImageNet classes) and language models
(a softmax over a vocabulary of tens of thousands of tokens) end with a softmax and are trained with
the cross-entropy LSE(z)−zy. The ML Fundamentals track and the
Deep Learning track use it in every classifier.
Attention. A transformer computes weights softmax(q⊤kj/d) over
the keys kj; the d acts like a temperature
(Linear Algebra lesson 15). Fast attention kernels
(FlashAttention) keep a running max and a running sum of exponentials (the "online softmax"): the max
trick, done block by block.
Sampling from language models: temperature, and greedy decoding as T→0.
Smooth maxima. Softplus log(1+ex) is a smooth ReLU; LSE pooling and "soft-min" losses
replace a hard max by a differentiable one.
Other places: the Gumbel-softmax trick, mixture models (weights from a softmax), the
Boltzmann distribution pk∝e−Ek/(kBT) of statistical physics (the same formula,
with energies as negative logits and a physical temperature), and the softmax policies of
reinforcement learning.
Normalizing raw scores by their sum.zk/∑jzj fails for negative scores and for a zero sum. Use the softmax.
Naive exponentials.np.exp(z) / np.exp(z).sum() returns nan for large logits (overflow) and
for very negative logits (underflow to 0/0). Subtract the max first.
log(softmax(z)) in two steps. A probability that rounds to 0 gives -inf. Compute z−LSE(z).
Passing probabilities to a loss that expects logits.torch.nn.CrossEntropyLoss applies the
log-softmax itself; giving it softmax outputs applies the softmax twice and trains badly.
Softmax over the wrong axis. For a batch of logits with shape (batch, classes), use axis=-1
(or axis=1), so each row sums to 1. With axis=0 each column sums to 1, which is wrong.
Softmax for multi-label outputs. If several labels can be true at once, use one sigmoid per label.
Thinking LSE equals the max. It is always larger (for n≥2), by at most logn.
Confusing "logit" and "logits". The logit is log1−pp; "logits" are the raw scores of a model.
Compute σ(0),σ(log3) and logit(0.5).Answerσ(0)=1/2.σ(log3)=1/(1+e−log3)=1/(1+1/3)=3/4.logit(0.5)=log(0.5/0.5)=log1=0.
Compute softmax(0,log2,log3) by hand.AnswerThe exponentials are 1,2,3; their sum is 6. So the softmax is (1/6,2/6,3/6)=(1/6,1/3,1/2).
Show that softmax(z)i/softmax(z)j=ezi−zj, and use it to explain shift invariance in one sentence.AnswerThe denominators cancel: ezj/sezi/s=ezi/ezj=ezi−zj. All ratios depend only on differences of logits, and adding c to every logit does not change any difference; since the entries also sum to 1, the whole vector stays the same.
Give the bounds for LSE(z) when z=(0,0,0,0), and the exact value.Answerm=0 and n=4, so 0≤LSE≤log4. All entries are equal, so the upper bound is exact: log(4e0)=log4≈1.386.
A float32 model produces the logits (90,85,80). What happens with naive softmax? What does the stable version give?AnswerIn float32, e90 overflows (the limit is about 88.72), so the first exponential is `inf` and the result contains `nan`. Stable: z−m=(0,−5,−10), exponentials (1,0.0067,0.0000454), sum 1.00678, so p≈(0.9933,0.0067,0.0000451).
Logits z=(2,0) and true class 2. Compute the cross-entropy loss.AnswerLSE(2,0)=log(e2+1)≈2.1269. The loss is LSE(z)−z2=2.1269−0=2.1269. Equivalently −log(1−σ(2))=−log0.1192≈2.127.
Recall cardsAnswer in your head first, then reveal. Add the cards to your review deck to see them again just before you would forget.
Write the sigmoid, and give σ(0) and σ(−z).
σ(z)=1/(1+e−z);σ(0)=1/2;σ(−z)=1−σ(z).
What is the inverse of the sigmoid?
The logit (log-odds): z=log1−pp.
Compute the logit of p=0.8.
log(0.8/0.2)=log4≈1.386.
Write the softmax of z∈Rn.
softmax(z)k=ezk/∑j=1nezj.
Why does adding the same constant c to every logit not change the softmax?
ezk+c=ecezk, and the factor ec cancels between the numerator and the denominator.
What does a 2-class softmax with logits (z,0) give for class 1?
ez/(ez+1)=σ(z); in general σ(z1−z2).
State the bounds of the log-sum-exp of z∈Rn.
maxjzj≤LSE(z)≤maxjzj+logn.
How do you compute log-softmax and LSE without overflow?
With m=maxjzj:LSE(z)=m+log∑jezj−m, and logsoftmax(z)k=zk−LSE(z).
What does softmax(z/T) approach as T→0, and as T→∞?
T→0: the one-hot vector at the largest logit (split equally over ties). T→∞: the uniform vector 1/n.
What is the slope of the sigmoid, and where is it largest?
σ′(z)=σ(z)(1−σ(z)); largest at z=0, where it equals 1/4.
"Why subtract the max in softmax?" — Shift invariance makes it exact; afterwards every exponent is
≤0 (no overflow) and the denominator is ≥1 (no division by 0).
"Why does CrossEntropyLoss take logits, not probabilities?" — It computes
LSE(z)−zy in one stable step; computing a softmax and then a log can give log0.
Its gradient is softmax(z)−ey.
"Sigmoid or softmax for the output layer?" — Softmax when exactly one class is true (multi-class);
one sigmoid per class when several can be true (multi-label). For two classes they are the same model.
"What does temperature do in sampling?" — Divides the logits by T;T<1 sharpens the
distribution toward the argmax, T>1 flattens it toward uniform.
"What is LSE, and why is it called a soft maximum?" — log∑jezj, within logn above the
max, smooth everywhere, and its gradient is the softmax.
Andrew Ng and Tengyu Ma, CS229 lecture notes, §2.1
(logistic regression) and §2.3 (multi-class classification with softmax).
Blanchard, Higham and Higham (2021), Accurately computing the log-sum-exp and softmax functions,
IMA Journal of Numerical Analysis, doi:10.1093/imanum/draa038; free preprint at
MIMS EPrints 2765: the error analysis behind the max trick (advanced).
Code along in Colab
Runs in your browser with nothing to install. The notebook repeats the key demos and has exercises with checks; solutions are inside, folded.