Softmax Function and its Derivative
Raw scores can be any numbers, while probabilities must be positive and sum to 1. Softmax bridges the gap by exponentiating each score and dividing by the total.
Why Does This Exist?
Classifiers output raw scores called logits: any real numbers, in any range, with no promise they sum to anything. Training and sampling need probabilities instead: positive numbers that sum to . Normalizing by the sum fails the moment scores go negative, and clipping breaks gradients.
Softmax fixes the mismatch in one smooth step that keeps order, stays differentiable, and pairs cleanly with the standard classification loss. This page covers the function and its derivative. The loss it feeds lives in cross-entropy and common loss functions. A cousin that turns distances into probabilities appears in t-SNE and UMAP.
The one idea you need first
A logit is an unconstrained score , while a probability must satisfy and . Exponentiation maps any real to a positive number, and dividing by the total forces the sum to . Those two moves are the whole function.
Think of It Like This
Splitting a prize by loudness of applause
Three street performers earn applause measured at levels , , and . You must split $100 in proportion to enthusiasm, but applause levels can be negative on a bad night and they never sum to .
So you convert first: exponentiate each level to get positive tickets, then share the prize by ticket counts. The loudest act gets the most tickets and the largest share, yet nobody gets everything. Louder overall applause does not change the split, only the gaps between acts do.
Where it stops: prize shares are spent once, while softmax outputs are reused as weights that blend values downstream. The split is the start of computation, not the payout.
How It Actually Works
For logits , where each is one raw score and counts classes:
In plain words: exponentiate each score with , sum those positives, then divide each by the sum. Outputs are positive and sum to by construction. Shifting all logits by the same constant cancels out, so only gaps matter. Large gaps concentrate mass, which is why attention blends rather than selects until gaps grow wide.
Why the derivative is a matrix
Softmax outputs share one denominator, so nudging moves every , not just . Its Jacobian , where and is the -th output, is:
Here is when and otherwise. Diagonal terms say each output rises with its own logit but saturates near or . Off-diagonal terms say raising one logit steals share from the rest. Rows sum to zero because total mass is conserved.
Paired with cross-entropy loss for the true class , the chain collapses to , where is one-hot. That clean gradient is why the pair dominates classification.
Worked example
Take .
Exponentiate: , , . Sum to . Divide:
The top score takes two-thirds of the weight, not all of it. Sum check: .
Jacobian diagonal for the first output is . Off-diagonal stealing from the second is . Every row sums to zero up to rounding, confirming mass conservation.
Code
The point is stability, not the formula retyped. Subtracting the max before exponentiating prevents overflow without changing the result.
import numpy as np
def softmax(z: np.ndarray) -> np.ndarray: e = np.exp(z - z.max(axis=-1, keepdims=True)) # shift so max is 0, exp cannot overflow return e / e.sum(axis=-1, keepdims=True)
z = np.array([2.0, 1.0, 0.0])print(np.round(softmax(z), 3)) # -> [0.665 0.245 0.09 ]print(float(softmax(z).sum())) # -> 1.0Outputs sum to , exactly the hand computation. Without the shift, overflows to infinity on the same inputs shifted up.
Watch Out For
Exponentiating without subtracting the max
Calling np.exp(z) directly overflows once logits pass about in float64 and in float32, returning infinity and then NaN probabilities. Large logits are normal before training settles, so this breaks early runs rather than edge cases.
Symptom: loss turns NaN while logits look merely large. Fix: always subtract the row max first, as the snippet does. The math is identical because the shift cancels in numerator and denominator.
Reading softmax outputs as calibrated confidence
Softmax must sum to , so it always looks confident even on garbage inputs. A split on unfamiliar data does not mean 66.5 percent accuracy. Temperature scaling, label smoothing, and calibration checks exist because raw shares mislead.
Symptom: high-confidence errors on shifted data, worse when gaps are large. Fix: treat outputs as weights for blending or ranking, calibrate before quoting confidence, and never use argmax probabilities as reliability scores without validation.
The Quick Version
- Softmax maps any real logits to positive probabilities that sum to via exponentiate then normalize.
- Only gaps between logits matter: shifting all scores leaves every output unchanged.
- On , exponentials sum to and give .
- The Jacobian is : each output steals share from the rest, and rows sum to zero.
- With cross-entropy, the gradient collapses to , which is why the pair trains well.
- Always subtract the max before
exp, and never read raw shares as calibrated confidence.