Linear Classifiers › Multiclass Classification: Softmax

Michael BrenndoerferApril 28, 20255 min read
Language AI HandbookAll chapters
Part 10 of 67Neural Network Foundations
Chapter 61Linear Classifiers › Multiclass Classification: Softmax
Reading section 6 of 16 · Multiclass Classification: Softmax · 5 minSection 6 of 16 · 5 min

Book contents

Section 6 of 16 · 5 min read

Linear Classifiers › Multiclass Classification: SoftmaxOne section · Sections in this chapter6 / 16 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Binary classification (two classes) covers many problems, but NLP is full of multiclass problems: classifying documents into dozens of topics, assigning one of hundreds of part-of-speech tags, or selecting the next word from a vocabulary of 50,000 tokens. Logistic regression extends to multiple classes through the softmax function.

For KK classes, we define KK weight vectors w1,w2,…,wK\mathbf{w}_1, \mathbf{w}_2, \ldots, \mathbf{w}_K and KK biases b1,b2,…,bKb_1, b_2, \ldots, b_K. The model computes one score per class. For class kk and input x\mathbf{x}:

zk=wk⋅x+bkfor k=1,2,…,Kz_k = \mathbf{w}_k \cdot \mathbf{x} + b_k \quad \text{for } k = 1, 2, \ldots, K

where:

  • wk∈Rd\mathbf{w}_k \in \mathbb{R}^d: the weight vector for class kk, one per class
  • bkb_k: the bias for class kk
  • zkz_k: the logit (raw score) for class kk

The resulting score vector z=[z1,z2,…,zK]\mathbf{z} = [z_1, z_2, \ldots, z_K] is called the vector of logits. To convert logits into a probability distribution, we apply the softmax function. For class kk:

P(y=k∣x)=ezk∑j=1KezjP(y = k \mid \mathbf{x}) = \frac{e^{z_k}}{\sum_{j=1}^{K} e^{z_j}}

where:

  • ezke^{z_k}: the exponential of the kk-th class logit, which ensures all values are positive
  • ∑j=1Kezj\sum_{j=1}^{K} e^{z_j}: the sum of exponentials across all KK classes, the normalizing constant
  • P(y=k∣x)∈(0,1)P(y = k \mid \mathbf{x}) \in (0, 1): the resulting probability for class kk

The softmax output is a valid probability distribution: all values are positive (because exponentials are always positive) and they sum to exactly 1 (by construction). The class with the highest logit always receives the highest probability. The exponential function amplifies differences: if class AA has a logit 2 units above class BB, then AA receives e2≈7.4e^2 \approx 7.4 times the unnormalized probability mass of BB.

Softmax

Softmax converts a vector of real-valued logits into a probability distribution over KK classes. It is the multiclass generalization of the sigmoid function. When K=2K = 2, softmax with two outputs is equivalent to using a single sigmoid.

The softmax function is ubiquitous in modern deep learning. Every language model that predicts the next token applies softmax over a vocabulary of tens of thousands of entries to produce a distribution over what comes next. Every classification network ends with a softmax layer. Understanding how softmax works at the scale of logistic regression gives you the intuition to understand what is happening at vastly larger scale in transformer models.

Numerical Stability with Log-Sum-Exp

Computing ezke^{z_k} directly causes overflow when logits are large (for example, when zk=1000z_k = 1000, e1000e^{1000} exceeds the floating-point limit). The standard fix is to subtract the maximum logit before exponentiating. This does not change the result because, for any constant cc:

ezk∑j=1Kezj=ezk−c∑j=1Kezj−c\frac{e^{z_k}}{\sum_{j=1}^{K} e^{z_j}} = \frac{e^{z_k - c}}{\sum_{j=1}^{K} e^{z_j - c}}

where:

  • c=max⁡jzjc = \max_j z_j: the constant we subtract (chosen as the maximum so that the largest exponential is e0=1e^0 = 1)
  • All other values ezj−c≤1e^{z_j - c} \leq 1: avoiding overflow

Setting c=max⁡jzjc = \max_j z_j ensures the numerically largest exponential equals 1 and all others are at most 1. This technique appears in every modern framework, including NumPy, PyTorch, and TensorFlow. If you ever implement softmax from scratch and forget this step, your code will silently produce NaN values on inputs with large logits.

In[9]:
Code
def softmax(z):
    """Convert a logit vector to a probability distribution (numerically stable)."""
    z_shifted = z - np.max(z)  # Subtract max for stability
    exp_z = np.exp(z_shifted)
    return exp_z / exp_z.sum()


# Multiclass text classifier: 3 classes (sports, politics, technology)
# Features: word count vector for 5 key words
# ["game", "election", "server", "team", "vote"]
W = np.array(
    [
        [0.9, -0.3, 0.1, 0.8, -0.2],  # sports
        [-0.1, 0.9, -0.2, -0.1, 0.8],  # politics
        [0.1, -0.1, 0.9, 0.1, -0.1],  # technology
    ]
)
b_multi = np.array([0.0, 0.1, -0.1])

doc_1 = np.array([1, 0, 1, 1, 0])  # "game server crashed during finals"
doc_2 = np.array([0, 1, 0, 0, 1])  # "election results shocked the nation"
Out[10]:
Console
Sports+Tech: 'game server crashed during finals'
  sports      : logit=1.80  P=0.636  ############
  politics    : logit=-0.30  P=0.078  #
  technology  : logit=1.00  P=0.286  #####
  Predicted: sports

Politics: 'election results shocked nation'
  sports      : logit=-0.50  P=0.082  #
  politics    : logit=1.80  P=0.818  ################
  technology  : logit=-0.30  P=0.100  ##
  Predicted: politics

The first document, mentioning "game," "server," and "team," gets split probability between sports and technology because it matches both class templates. The second document, mentioning "election" and "vote," is confidently classified as politics. This ambiguity in the first document reflects semantic ambiguity: "game server crashed during finals" could plausibly come from either a gaming article or a sports one. The model's uncertainty is well-calibrated.

The Weight Matrix View

When we have KK classes, the individual weight vectors w1,…,wK\mathbf{w}_1, \ldots, \mathbf{w}_K can be stacked as rows of a weight matrix W∈RK×d\mathbf{W} \in \mathbb{R}^{K \times d}. The logit vector becomes:

z=Wx+b\mathbf{z} = \mathbf{W} \mathbf{x} + \mathbf{b}

This is a matrix-vector product: each row of W\mathbf{W} computes a dot product with x\mathbf{x}, producing one score per class. This operation is the first linear layer of any neural network. In a deep network, you stack many such transformations, but each individual transformation has exactly this form. Recognizing this pattern across different scales of complexity is key to understanding neural network architecture.