Skip to content
ml-recall

Topic notes

Logistic Regression & Softmax

Linear classifiers that output probabilities — sigmoid and log-odds, odds ratios, thresholds and decision boundaries, log loss, regularization, softmax regression and numerically stable softmax.

4-min read AI-checked

Practise 46 questions Take a test

Key ideas

The model1. Despite its name, logistic regression is a classifier4: it predicts a category (ripe or not, spam or not) from a linear score z=b+w⊤xz = b + \mathbf{w}^\top\mathbf{x}. The sigmoid σ(z)=1/(1+e−z)\sigma(z) = 1/(1 + e^{-z}) turns the score into a probability strictly between 0 and 1. Solving for zz gives z=ln⁡p1−pz = \ln\frac{p}{1 - p}: the linear part is the log-odds (logit)1. Useful values: σ(0)=0.5\sigma(0) = 0.5 and σ(−z)=1−σ(z)\sigma(-z) = 1 - \sigma(z). Pick it over linear regression because the target is a category, not because the features correlate weakly with it.

Odds and coefficients5. The odds are p/(1−p)=ezp/(1 - p) = e^{z}. One more unit of xjx_j adds wjw_j to zz, so it multiplies the odds by ewje^{w_j} — the odds ratio; the change in pp itself depends on where you start. With an interaction term β3XZ\beta_3 XZ, one more unit of XX adds β1+β3Z\beta_1 + \beta_3 Z to the log-odds. Statistically it is a generalized linear model: Bernoulli response, linear predictor, logit link5.

Decisions. Predict class 1 when p≥tp \ge t. Since σ\sigma is increasing, that is the same as z≥ln⁡t1−tz \ge \ln\frac{t}{1 - t}, so the decision boundary w⊤x+b=ln⁡t1−t\mathbf{w}^\top\mathbf{x} + b = \ln\frac{t}{1-t} is a hyperplane (a line for 2 features) — a linear classifier, even though pp is a nonlinear function of x\mathbf{x}. Changing tt shifts the boundary in parallel and changes decisions, not probabilities. Points near the boundary get p≈0.5p \approx 0.5; points far away get confident probabilities that can still be wrong. When a missed positive costs cFNc_{FN} and a false alarm cFPc_{FP}, the expected cost is lowest if you predict positive whenever p>cFP/(cFP+cFN)p > c_{FP}/(c_{FP} + c_{FN}) — far below 0.5 when misses are expensive.

Training. Maximum likelihood means minimizing the log loss (binary cross-entropy)2. There is no closed-form solution5, but the log loss is the convex logistic loss of the margin6, and zz is linear in w\mathbf{w}, so the objective is convex in the weights: gradient descent reaches the global minimum from any start — no bad local minima. The gradient per example is (p−y) x(p - y)\,\mathbf{x}: prediction error times input. With the squared error (p−y)2(p - y)^2 the gradient is 2(p−y) p(1−p) x2(p - y)\,p(1 - p)\,\mathbf{x}; the extra factor 2p(1−p)2p(1 - p) nearly vanishes exactly when the model is confidently wrong (at z=−5z = -5, y=1y = 1 the gradient is about 75 times smaller than with log loss).

Regularization4. scikit-learn's LogisticRegression is regularized by default, and C is the inverse strength: smaller C → stronger penalty, smaller weights, simpler model; a very large C means effectively none. An ℓ2\ell_2 penalty shrinks weights; an ℓ1\ell_1 penalty sets some exactly to zero4. On linearly separable data the unpenalized loss keeps falling as the weights grow, so some penalty (or early stopping) keeps them finite.

More than two classes2. Softmax regression (multinomial logistic regression4) computes one score oko_k per class and normalizes with the softmax. The softmax keeps the order of the logits, so the predicted class is arg max⁡kok\operatorname*{arg\,max}_k o_k. The loss is the cross-entropy −ln⁡y^true-\ln \hat y_{\text{true}}, and its gradient with respect to the logits is simply y^−y\hat{\mathbf{y}} - \mathbf{y}2. With two classes, softmax over (o1,o2)(o_1, o_2) equals σ(o1−o2)\sigma(o_1 - o_2): binary logistic regression on the score difference. The ratio of two class probabilities, eoi−oje^{o_i - o_j}, does not depend on the other classes. Dividing logits by a temperature TT flattens the distribution (higher entropy) for T>1T > 1 and sharpens it toward the arg max as T→0T \to 0. Alternatives are one-vs-rest binary models, and ordinal logistic regression for ordered categories5.

Numerics3. eoe^{o} overflows for large logits (above about 88.7 in float32, about 11.09 in float16), and inf / inf is nan. Subtracting the largest logit leaves the softmax unchanged and prevents overflow; combining softmax and log into one log-sum-exp step avoids log⁡0\log 0 as well. That is why framework cross-entropy losses (e.g. PyTorch's F.cross_entropy) take raw logits and apply log-softmax themselves3.

Formulas

σ(z)=11+e−z,z=b+w⊤x=ln⁡p1−p\sigma(z) = \frac{1}{1 + e^{-z}}, \qquad z = b + \mathbf{w}^\top\mathbf{x} = \ln\frac{p}{1 - p} L=−1N∑i=1N[yiln⁡pi+(1−yi)ln⁡(1−pi)],∂Li∂w=(pi−yi) xiL = -\frac{1}{N}\sum_{i=1}^{N}\big[y_i \ln p_i + (1 - y_i)\ln(1 - p_i)\big], \qquad \frac{\partial L_i}{\partial \mathbf{w}} = (p_i - y_i)\,\mathbf{x}_i y^k=eok∑jeoj=eok−m∑jeoj−m (m=max⁡joj),∂(−ln⁡y^true)∂ok=y^k−yk\hat y_k = \frac{e^{o_k}}{\sum_j e^{o_j}} = \frac{e^{o_k - m}}{\sum_j e^{o_j - m}} \ (m = \max_j o_j), \qquad \frac{\partial(-\ln \hat y_{\text{true}})}{\partial o_k} = \hat y_k - y_k

Threshold on the logit scale: t=0.8t = 0.8 gives z≥ln⁡4≈1.386z \ge \ln 4 \approx 1.386. Log-sum-exp: ln⁡∑iexi+c=c+ln⁡∑iexi\ln\sum_i e^{x_i + c} = c + \ln\sum_i e^{x_i} — it shifts by cc; only the softmax is shift-invariant.

Worked example

w=(0.8,−0.5)\mathbf{w} = (0.8, -0.5), b=−1b = -1, x=(3,2)\mathbf{x} = (3, 2):

Softmax of the logits (3,1,0)(3, 1, 0) is about (0.844,0.114,0.042)(0.844, 0.114, 0.042). If the true class is the second one, the loss is −ln⁡0.114≈2.170-\ln 0.114 \approx 2.170 and the gradient is (0.844,−0.886,0.042)(0.844, -0.886, 0.042): the true logit is pushed up, the others down.

In code

import numpy as np

def softmax(o):
    e = np.exp(o - o.max())                  # shift by the largest logit: same result
    return e / e.sum()

o = np.array([3.0, 1.0, 0.0])                # logits
print(softmax(o).round(4))                   # [0.8438 0.1142 0.042 ]
print(softmax(o + 1000).round(4))            # [0.8438 0.1142 0.042 ]  shift-invariant
with np.errstate(over="ignore", invalid="ignore"):
    print(np.exp(o + 1000) / np.exp(o + 1000).sum())   # [nan nan nan]  naive overflow
lse = o.max() + np.log(np.exp(o - o.max()).sum())       # stable log-sum-exp
print(round(lse - o[1], 4))                  # 2.1698 = cross-entropy, true class = 2nd
print((softmax(o) - [0, 1, 0]).round(4))     # [ 0.8438 -0.8858  0.042 ] = gradient wrt o

Common pitfalls

References

  1. Machine Learning Crash Course — Logistic regression: Calculating a probability with the sigmoid function
  2. Dive into Deep Learning — Sec. 4.1 Softmax Regression (4.1.1.2 The Softmax, 4.1.2 Loss Function, 4.1.3 Information Theory Basics)
  3. Dive into Deep Learning — Sec. 4.5.2 Softmax Revisited
  4. scikit-learn User Guide — Sec. 1.1.11 Logistic regression (intro notes on regularization and GLM; 1.1.11.1 Binary Case; 1.1.11.2 Multinomial Case)
  5. Wikipedia: Logistic regression — Background (Definition of the odds, The odds ratio); Interpretations (As a generalized linear model); Model fitting; Extensions
  6. Wikipedia: Loss functions for classification — Logistic loss