Regularisation Mathematical Deep Dive
P6.dl-architectures.06 · Audience: it-ml · Prerequisites: Regularisation and Normalisation
Mathematical derivation of the bias-variance decomposition, the ridge regression closed-form solution, LASSO sparsity, dropout as approximate Bayesian inference, and LayerNorm. Step through the five derivations one at a time (keep a pencil at hand), then work the pencil-and-paper exercises, NumPy programming tasks, and 5-question self-test below.
Prerequisite: Regularisation and Normalisation. This page assumes familiarity with basic probability, linear algebra, and calculus (partial derivatives, matrix inverse). All derivations are self-contained.
Goal: derive the expected squared error of a predictor trained on a random dataset, with true target .
Setup. Assume:
- True function:
- Noise: , independent of
- Predictor: — a random variable over different training sets
Decomposition (for a fixed ). Insert and subtract and :
Expanding using the identity , where the cross terms vanish under independence and zero-mean noise:
Bias : how much the average prediction misses the true function. A simple model (few parameters) has high bias — it cannot fit the data.
Variance : how much the prediction varies across different training sets. A complex model (many parameters) has high variance — it memorises each training set differently.
Irreducible noise : cannot be reduced by any model — it is measurement noise in the data itself. ∎
ⓘ Concept — bias-variance for neural networks
Part 2 — Exercises
Work these on paper or in the scratch console at the bottom of the page. Each exercise carries its worked solution behind a reveal, so check yourself as you go.
Maths exercises (pencil and paper)
M1 — Bias and variance of a constant predictor. Consider a predictor that always predicts the training mean: , independent of . Assume the true function is and noise .
- What is in terms of values seen during training?
- What is the Bias² of this predictor at if and the training data has ?
- Is the variance of this predictor zero? Explain.
- What can you say about the bias-variance trade-off for this predictor?
Show answer — M1
- = mean of the training targets — does not depend on .
- Bias² .
- Not zero: varies across different training sets because depends on which samples are drawn. Variance .
- The constant predictor has high bias (it ignores ) but relatively low variance (the average is stable). It is the extreme underfitting case.
M2 — Ridge regression limit as λ → ∞. Show algebraically that as , the ridge regression solution .
- Start from .
- Factor out : .
- Apply the matrix limit as .
- Interpret: what does a model with predict for every input?
Show answer — M2
- .
- Factor: .
- As , , so . Therefore . ∎
- With , for all inputs — the model predicts zero (or the bias/intercept only). Infinite regularisation kills all learned signal.
M3 — Soft-thresholding: LASSO solution in 1D. In the 1D LASSO problem, the objective (after orthonormal ) is:
where is the OLS estimate.
- For , : compute the LASSO solution . (Soft-thresholding: .)
- For , : compute . Is it zero?
- What is the threshold on below which ?
Show answer — M3
- → . LASSO shrinks the OLS estimate from 3.0 to 2.0.
- → . LASSO sets this coefficient to exactly zero — the feature is excluded.
- when . Sparsity threshold : any OLS estimate smaller than this is zeroed out.
Programming exercises (NumPy)
P1 — Ridge regression closed-form vs OLS. Fill in the stub to implement ridge regression and compare with OLS (λ = 0):
import numpy as np
np.random.seed(42)
n, d = 20, 5
X = np.random.randn(n, d)
w_true = np.array([3.0, -1.5, 0.0, 0.5, 2.0])
y = X @ w_true + 0.5 * np.random.randn(n)
lam = 1.0
# STUB: compute the ridge regression solution
w_ridge = ___
# OLS (lambda = 0): may be ill-conditioned if n < d
w_ols = np.linalg.lstsq(X, y, rcond=None)[0]
print('True w: ', w_true.round(3))
print('OLS w: ', w_ols.round(3))
print('Ridge w: ', w_ridge.round(3))
print('OLS MSE:', ((X @ w_ols - y)**2).mean().round(4))
print('Ridge MSE:', ((X @ w_ridge - y)**2).mean().round(4))
Show solution — P1
w_ridge = np.linalg.solve(X.T @ X + lam * np.eye(d), X.T @ y)
Expected output — True w: [3.0, -1.5, 0.0, 0.5, 2.0]; OLS w: [3.119, -1.327, 0.035, 0.365, 1.984]; Ridge w: [2.863, -1.278, 0.016, 0.405, 1.887]; OLS MSE: 0.2147; Ridge MSE: 0.2629.
Ridge shrinks all coefficients toward zero (and trades a little training
MSE for stability). np.linalg.solve is preferred over an explicit matrix
inverse — it is faster and numerically more stable.
P2 — Compare L1 and L2 regularisation: sparsity. Fill in the stub to apply soft-thresholding (LASSO) and ridge shrinkage to a 1D array of OLS coefficients and compare the results:
import numpy as np
# Simulate OLS estimates (orthonormal X, so w_ols = XᵀY directly)
np.random.seed(7)
c = np.random.uniform(-3, 3, 10) # 10 OLS estimates
lam = 2.0
# Ridge shrinkage: w_ridge_j = c_j / (1 + lambda) [when XᵀX = I]
w_ridge = c / (1 + lam)
# STUB: soft-thresholding (LASSO solution when XᵀX = I)
# w_lasso_j = sign(c_j) * max(|c_j| - lam/2, 0)
w_lasso = ___
print('OLS: ', c.round(3))
print('Ridge: ', w_ridge.round(3), f' ({(w_ridge == 0).sum()} zeros)')
print('LASSO: ', w_lasso.round(3), f' ({(w_lasso == 0).sum()} zeros)')
Show solution — P2
w_lasso = np.sign(c) * np.maximum(np.abs(c) - lam / 2, 0)
Expected output — OLS: [-2.542, 1.68, -0.37, 1.341, 2.868, 0.231, 0.007, -2.568, -1.389, -0.001]; Ridge: [-0.847, 0.56, -0.123, 0.447, 0.956, 0.077, 0.002, -0.856, -0.463, -0.0] (0 zeros — shrinks but never zeroes); LASSO: [-1.542, 0.68, -0.0, 0.341, 1.868, 0.0, 0.0, -1.568, -0.389, -0.0] (4 zeros — true sparsity).
Ridge scales every coefficient by 1/(1+λ). LASSO zeroes any coefficient with — exactly the feature selection property described in the LASSO step.
P3 — LayerNorm: implement and verify. Fill in the stub to implement LayerNorm and verify mean = 0, variance = 1:
import numpy as np
def layer_norm(x: np.ndarray, eps: float = 1e-5) -> np.ndarray:
"""Normalise x across feature dimension (γ=1, β=0)."""
# STUB: compute mean and variance, return (x - mean) / sqrt(var + eps)
return ___
np.random.seed(0)
x = np.random.randn(8) * 5 + 10 # large scale and offset
x_hat = layer_norm(x)
print('Input mean: ', x.mean().round(4))
print('Input std: ', x.std().round(4))
print('LN mean: ', x_hat.mean().round(8)) # should be ~0
print('LN var: ', x_hat.var().round(8)) # should be ~1
print('LN output: ', x_hat.round(4))
Show solution — P3
mu = x.mean()
var = x.var() # population variance: (1/d) Σ (xᵢ - μ)²
return (x - mu) / np.sqrt(var + eps)
Expected output — Input mean: 14.4205, std: 5.1133; LN mean: 4.16e-16 (≈ 0 ✓); LN var: 0.99999962 (≈ 1 ✓); LN output: [0.8604, -0.4732, 0.0925, 1.3267, 0.9617, -1.8201, 0.0645, -1.0125].
LayerNorm removes any mean offset and scales to unit variance — regardless of how large or skewed the inputs are. The learnable γ and β then allow the network to rescale and shift the normalised output to whatever range the next layer needs.
Part 3 — Self-Test
Write your answer before revealing.
Q1 — State the bias-variance decomposition of the expected squared error E[(y − f̂)²] as a sum of three terms. Name each term.
Q2 — Ridge regression is equivalent to MAP estimation with a specific prior on the weights. What is that prior? What does λ correspond to?
Q3 — Explain geometrically why L1 regularisation produces exact zeros in the solution, while L2 only shrinks coefficients without zeroing them.
Q4 — How do you use a dropout-trained network to estimate predictive uncertainty at test time? What kind of uncertainty does this estimate?
Q5 — Numerical: given x = [1.0, −1.0, 2.0, −2.0] with γ = 1, β = 0, ε = 0, compute μ, σ², and the normalised output x̂ (to 4 decimal places), then verify mean(x̂) = 0 and var(x̂) = 1.
Cross-references: Regularisation and Normalisation (base module) · Training Loop and Optimisers — module 03 of this track (AdamW = Adam + L2 weight decay) · The Encoder Block (dropout and LayerNorm in the full architecture).
Ask the mentor about this module
Ask a question about this content. The mentor explains and grounds its answer in what you are studying; asking is recorded as a learning signal, not a grade.
Try it yourself
A scratch console for this page's ideas — ungraded, nothing you run here is recorded.
Scratch console
A scratch console with the scientific stack (pandas, numpy, scikit-learn). Runs on the server — no network, resource-limited and measured.
Output appears here.
Where next?
Later in Deep-Learning Architectures