Part IV Theory 4 Training

Optimization

Every model you train is the answer to an optimization problem. Know the theory, and you can tell why a run diverged, stalled or overfit.

Interviewers rarely ask you to prove a rate. They ask why training blew up at step 200. They ask why the loss plateaued, or why a bigger batch hurt. The answers come from a small set of ideas. These are curvature, noise, conditioning and constraints. This page builds those ideas from the ground up. It goes deeper than the optimizer comparison in Deep Learning. The goal is to know where each rule comes from. Then you can reason about a case you have never seen.

Throughout, we minimize a loss f(θ) over parameters θ ∈ ℝd. The gradient is ∇f and the Hessian is ∇2f. The best value is f* at a minimizer θ*.

Contents

  1. Convex sets and functions
  2. Gradient descent and its rates
  3. Newton and quasi-Newton methods
  4. Stochastic gradient descent theory
  5. Momentum and Nesterov
  6. Adaptive methods and their caveats
  7. Constrained optimization and duality
  8. Non-convex landscapes
  9. Learning rate schedules and warmup
  10. Coordinate descent and proximal methods
  11. EM as optimization
  12. Hyperparameter optimization

1. Convex sets and functions

Convex, in plain words. A set is convex if the straight line between any two of its points stays inside it. A function is convex if the line between any two points on its graph sits on or above the graph. A convex bowl has no false bottoms. Every local minimum is a global minimum.

The definitions

A set C is convex if for all x, y ∈ C and t ∈ [0, 1], the point tx + (1 − t)y is also in C. A function f is convex if its domain is convex and:

f(t x + (1 - t) y)  ≤  t f(x) + (1 - t) f(y)        for all t in [0, 1]

For smooth functions there are two easier tests. They say the same thing in different words.

chord: t f(x) + (1 − t) f(y) tangent at x₀ xy Chord lies above the curve. Tangent lies below it everywhere.
The two faces of convexity. The chord bounds f from above. Any tangent bounds f from below.

Strong convexity and smoothness

Convexity alone says the bowl has no false bottoms. It says nothing about how steep or flat the bowl is. Two numbers pin that down.

So f is trapped between two parabolas. One opens with width μ, and one opens with width L. Almost every rate on this page is a function of κ.

Why convexity matters. It turns optimization from a search into a solved problem. Any local method finds the global answer. Rates are provable. The answer does not depend on initialization. Linear and logistic regression, SVMs and lasso are all convex. Neural nets are not, and that is why their training needs tricks.

A useful relaxation: the PL condition

The Polyak–Łojasiewicz (PL) condition is weaker than strong convexity:

½ ‖∇f(θ)‖2  ≥  μ ( f(θ) - f* )

It says a small gradient means you are close to optimal in value. It does not need convexity. Gradient descent still converges linearly under PL. Wide, over-parameterized networks satisfy PL near their initialization. That is one theory for why they train so reliably.

Why it matters in practice

Interview check

2. Gradient descent and its rates

Gradient descent, in plain words. Stand on the loss surface. Find the direction of steepest descent, which is minus the gradient. Take a step of size η that way. Repeat. The theory answers two questions. How big can the step be? How many steps will it take?
θk+1 = θk - η ∇f(θk)

The descent lemma

Plug the GD step into the L-smooth upper bound with y = θk+1:

f(θk+1)  ≤  f(θk) - η (1 - Lη/2) ‖∇f(θk)‖2

The loss must drop whenever 0 < η < 2/L. The guaranteed drop is largest at η = 1/L. There it is (1/2L)‖∇f‖2. This one line is the root of the classic rule. Set the step to one over the largest curvature.

The three rates

Why the condition number controls everything

Take a quadratic f(θ) = ½θTAθ. In the eigenbasis of A, each coordinate evolves on its own:

θi(k+1) = (1 - η λi) θi(k)

Each direction shrinks by the factor |1 − ηλi|. The steep direction needs η < 2/λmax, or it blows up. But then the flat direction shrinks by only 1 − 2λmin/λmax per step. The best fixed step is η = 2/(L + μ). It gives the factor (κ − 1)/(κ + 1). With κ = 1000, that is 0.998 per step. You need thousands of steps to make progress along the flat valley.

start GD: zigzags across the steep axis momentum: averages out the zigzag Contours of an ill-conditioned quadratic (κ large)
High κ makes plain GD bounce across the narrow axis and crawl along the long one.

Line search

You rarely know L. Backtracking line search finds a safe step on the fly. Start with a large η. Shrink it by a factor β until the Armijo condition holds:

f(θ - η∇f)  ≤  f(θ) - c η ‖∇f‖2        with c in (0, 1), often 1e-4

Full-batch solvers like L-BFGS use line search. Deep learning does not. Each extra loss evaluation costs a forward pass on noisy minibatches. So deep learning uses schedules instead.

Why it matters in practice

Interview check

3. Newton and quasi-Newton methods

Newton's method, in plain words. Fit a parabola to the loss at the current point using the gradient and the Hessian. Jump straight to the bottom of that parabola. Repeat. It uses curvature to pick both the direction and the step size.

The update

The second-order Taylor model is f(θ + p) ≈ f(θ) + ∇fTp + ½pT∇2f p. Set its gradient in p to zero:

θk+1 = θk - [∇2f(θk)]-1 ∇f(θk)

Second-order intuition

In the Hessian eigenbasis, Newton divides each gradient component by its curvature λi. Steep directions get small steps. Flat directions get big steps. That is exactly the cure for the zigzag in the GD figure. Every adaptive optimizer is an attempt to get this effect cheaply.

Newton loves saddles. If λi < 0, dividing by it flips the sign. Newton then walks uphill in that direction, toward the saddle. Pure Newton converges to any stationary point. Non-convex use needs fixes like damping (∇2f + λI), trust regions, or using |λi|.

Far from the optimum the quadratic model can be poor. Damped Newton takes θ − t[∇2f]-1∇f with t from line search. For logistic regression, Newton is the classic IRLS algorithm (iteratively reweighted least squares).

Newton on regularized logistic regression

import numpy as np

rng = np.random.default_rng(0)
n, d = 500, 5
X = rng.normal(size=(n, d)); w_true = rng.normal(size=d)
y = (rng.random(n) < 1 / (1 + np.exp(-X @ w_true))).astype(float)
lam = 1e-2

def grad_hess(w):
    p = 1 / (1 + np.exp(-X @ w))
    g = X.T @ (p - y) / n + lam * w
    H = (X * (p * (1 - p))[:, None]).T @ X / n + lam * np.eye(d)
    return g, H

w = np.zeros(d)
for k in range(8):
    g, H = grad_hess(w)
    print(k, "%.2e" % np.linalg.norm(g))
    w = w - np.linalg.solve(H, g)       # Newton step
# gradient norm: 3.3e-01, 7.6e-02, 1.6e-02, 1.1e-03, 6.3e-06, 2.1e-10, 3.0e-17

Watch the exponent. It goes −3, −6, −10, −17. That is quadratic convergence. GD would need hundreds of steps for the same accuracy.

Quasi-Newton: BFGS

Quasi-Newton methods build a Hessian estimate from gradients alone. Define the step sk = θk+1 − θk and the gradient change yk = ∇fk+1 − ∇fk. A true Hessian roughly satisfies ∇2f sk ≈ yk. So we ask the new estimate Bk+1 to satisfy the secant condition Bk+1sk = yk. BFGS picks the closest such matrix to the old one. It updates the inverse H ≈ [∇2f]-1 directly:

ρk = 1 / (ykT sk)
Hk+1 = (I - ρk sk ykT) Hk (I - ρk yk skT) + ρk sk skT

L-BFGS

L-BFGS never stores H. It keeps the last m pairs (s, y), often m = 5 to 20. A "two-loop recursion" computes H∇f from those pairs in O(md) time and memory. That makes quasi-Newton work for millions of parameters.

Why it matters in practice

Interview check

4. Stochastic gradient descent theory

SGD, in plain words. Computing the full gradient over a billion examples is too slow. So estimate it from a small random batch. The estimate is right on average but noisy. The theory explains what that noise costs and what it buys.

The setup

The loss is an average f(θ) = (1/n)Σi fi(θ). Draw a minibatch S of size B. Use the minibatch gradient:

g = (1/B) Σi∈S ∇fi(θ)        E[g] = ∇f(θ)        Cov[g] ≈ Σ(θ) / B

Here Σ is the covariance of per-example gradients. The estimate is unbiased. Its variance falls as 1/B. Its standard error falls as 1/√B. So a 4× bigger batch only halves the noise.

What the noise does to convergence

Add noise to the descent lemma. With variance bound σ2, one step gives:

E[f(θk+1)]  ≤  f(θk) - η(1 - Lη/2) ‖∇f‖2 + (Lη2/2) σ2/B

The last term never goes away with a fixed η. Progress stops once ‖∇f‖2 is about Lησ2/B. So SGD with a constant step converges to a noise ball around the optimum. Its radius is proportional to ησ2/B.

Why SGD wins anyway. Training error below the statistical error is wasted. With n examples, the test error floor is about O(1/n). SGD reaches that level in one pass over the data. Full-batch GD needs many passes at n gradients each. Bottou and Bousquet called this the trade-off between optimization and estimation error.

Noise scale and batch size

Model SGD as a stochastic differential equation. Then the noise "temperature" scales like η/B. Two runs with the same ratio of η to B behave alike. That gives the linear scaling rule. When you multiply the batch by k, multiply the learning rate by k.

Why it matters in practice

Interview check

5. Momentum and Nesterov

Momentum, in plain words. Let the parameters build up speed. Each step adds a bit of the last step to the new gradient. Directions that agree speed up. Directions that flip sign cancel. It is a ball rolling downhill with friction.

Heavy ball (Polyak)

vk+1 = β vk - η ∇f(θk)
θk+1 = θk + vk+1

The physics view. Think of a ball with mass m and friction γ on the surface f. Its motion is mθ̈ + γθ̇ + ∇f(θ) = 0. Discretize it and you get heavy ball. Here β plays the role of 1 minus friction. Plain GD is the massless limit, where velocity equals force. A massless ball stops dead in a flat valley. A heavy ball keeps rolling. It also overshoots, which is the price of speed.

The quadratic analysis. On a quadratic with curvature between μ and L, choose:

η = 4 / (√L + √μ)2        β = ( (√κ - 1) / (√κ + 1) )2

The error then shrinks by (√κ − 1)/(√κ + 1) per step. That needs about √κ log(1/ε) steps instead of κ log(1/ε). With κ = 10,000 that is a 100× speedup.

Heavy ball has no global guarantee. Lessard, Recht and Packard built a smooth, strongly convex function where heavy ball cycles forever. The √κ rate holds for quadratics and locally. Nesterov's method is what carries the proof.

Nesterov accelerated gradient

Nesterov looks ahead first. It evaluates the gradient where momentum is about to carry you:

yk     = θk + βk (θk - θk-1)
θk+1 = yk - (1/L) ∇f(yk)

Seeing the √κ speedup

import numpy as np

def run(kappa, method, tol=1e-6, max_it=100000):
    # f(x) = 0.5 x^T A x with eigenvalues 1 and kappa
    A = np.diag([1.0, kappa]); L, mu = kappa, 1.0
    x = np.array([1.0, 1.0]); v = np.zeros(2); y = x.copy()
    for t in range(max_it):
        if np.linalg.norm(x) < tol:
            return t
        if method == "gd":
            x = x - (1 / L) * (A @ x)
        elif method == "heavy":
            a = 4 / (np.sqrt(L) + np.sqrt(mu)) ** 2
            b = ((np.sqrt(kappa) - 1) / (np.sqrt(kappa) + 1)) ** 2
            x_new = x - a * (A @ x) + b * v
            v = x_new - x; x = x_new
        elif method == "nesterov":
            b = (np.sqrt(kappa) - 1) / (np.sqrt(kappa) + 1)
            x_new = y - (1 / L) * (A @ y)
            y = x_new + b * (x_new - x); x = x_new
    return max_it

for k in [10, 100, 1000]:
    print(k, {m: run(k, m) for m in ["gd", "heavy", "nesterov"]})
# 10   {'gd': 132,   'heavy': 27,  'nesterov': 44}
# 100  {'gd': 1375,  'heavy': 95,  'nesterov': 158}
# 1000 {'gd': 13809, 'heavy': 321, 'nesterov': 519}

GD steps grow 10× each time κ grows 10×. Momentum steps grow about 3.2×, which is √10. On a pure quadratic, tuned heavy ball edges out Nesterov.

Momentum in deep learning

Deep learning uses a fixed β near 0.9, not the tuned values above. The steady-state step is η/(1 − β), or 10η at β = 0.9. So changing β changes the effective learning rate. With noisy gradients, momentum also acts as a low-pass filter. Its main gain is averaging out minibatch noise along consistent directions.

Why it matters in practice

Interview check

6. Adaptive methods and their caveats

Adaptive methods, in plain words. Give each parameter its own step size. A parameter with large gradients so far gets a small step. A parameter with rare or small gradients gets a big step. It is a cheap diagonal stand-in for Newton.

AdaGrad

Gt = Gt-1 + gt ⊙ gt
θt+1 = θt - η gt / (√Gt + ε)

RMSProp

RMSProp swaps the sum for an exponential moving average. It forgets old gradients:

vt = β2 vt-1 + (1 - β2) gt2
θt+1 = θt - η gt / (√vt + ε)

Adam

Adam is RMSProp plus momentum plus bias correction for the zero start:

mt = β1 mt-1 + (1 - β1) gt          m̂t = mt / (1 - β1t)
vt = β2 vt-1 + (1 - β2) gt2         v̂t = vt / (1 - β2t)
θt+1 = θt - η m̂t / (√v̂t + ε)

The update rules and AdamW are covered in Deep Learning, question 3. Here we focus on what the theory does and does not promise.

What Adam really does

The theory caveats

Why it matters in practice

Interview check

7. Constrained optimization and duality

Constrained optimization, in plain words. Minimize a loss while obeying rules, like a budget or a margin. Lagrange multipliers turn each rule into a price. At the optimum, the push of the loss is exactly balanced by the push of the active rules.

The problem and the Lagrangian

minimize    f(x)
subject to  gi(x) ≤ 0,   i = 1..m
            hj(x) = 0,   j = 1..p

L(x, λ, ν) = f(x) + Σi λi gi(x) + Σj νj hj(x)        λi ≥ 0

Equality case first. At a constrained optimum, you cannot lower f by moving along the constraint surface. So ∇f must be normal to the surface. That gives ∇f = −ν∇h. The multiplier ν is the exchange rate between the two gradients.

KKT conditions

For a well-behaved problem, x* is optimal only if there exist λ*, ν* with:

  1. Stationarity. ∇f(x*) + Σλi*∇gi(x*) + Σνj*∇hj(x*) = 0.
  2. Primal feasibility. gi(x*) ≤ 0 and hj(x*) = 0.
  3. Dual feasibility. λi* ≥ 0. An inequality can only push you back, never pull.
  4. Complementary slackness. λi*gi(x*) = 0. Either a constraint is tight, or its price is zero.

For convex problems that satisfy Slater's condition, KKT is also sufficient. Slater asks for one strictly feasible point.

Duality

The dual function is the best Lagrangian value for fixed prices:

q(λ, ν) = infx L(x, λ, ν)

Worked example: the SVM dual

The soft-margin SVM primal is:

minw,b,ξ  ½ ‖w‖2 + C Σi ξi
s.t.      yi(wTxi + b) ≥ 1 - ξi,    ξi ≥ 0

Give multiplier αi to the margin rule and ri to ξi ≥ 0. Set the Lagrangian's gradients to zero:

∂/∂w :  w = Σi αi yi xi
∂/∂b :  Σi αi yi = 0
∂/∂ξi:  C - αi - ri = 0   ⇒   0 ≤ αi ≤ C

Substitute back. The dual is a quadratic program in α:

maxα  Σi αi - ½ ΣiΣj αi αj yi yj xiTxj
s.t.   0 ≤ αi ≤ C,    Σi αi yi = 0

Why it matters in practice

Interview check

8. Non-convex landscapes

Non-convex landscape, in plain words. The loss surface of a neural net has many valleys, ridges and flat plateaus. Theory cannot promise the global minimum. Yet training works well. The reasons are that bad local minima are rare and saddles are escapable. Many good minima exist.

Critical points and the Hessian

At a point with ∇f = 0, the Hessian eigenvalues tell you what you found:

Saddles dominate in high dimensions

Picture a random critical point in d dimensions. If each eigenvalue sign were a coin flip, the chance all d are positive is 2−d. So most critical points are saddles. Dauphin et al. found that in real nets, the saddle index grows with loss. Critical points with high loss are almost all saddles. Local minima mostly sit near the global loss.

flat: test loss barely moves sharp: test loss jumps Solid: train loss. Dashed: test loss, shifted by a small data change.
A small shift between train and test barely changes loss at a flat minimum. It changes loss a lot at a sharp one.

Flat vs sharp minima

Sharpness is often measured by λmax(∇2f) or by the worst loss in a small ball. The intuition is in the figure. Test data shifts the loss surface a little. A flat minimum barely notices. A sharp one does. MDL and PAC-Bayes give the same story in theory terms. A flat minimum needs fewer bits to describe.

What the neural net loss surface looks like

Why it matters in practice

Interview check

9. Learning rate schedules and warmup

A schedule, in plain words. Change the learning rate over training. Start low to stay stable. Go high to make fast progress. End low to settle into the minimum. The shape of that curve often matters as much as the optimizer.

Why decay at all

Recall the SGD noise ball. Its radius scales with η. Early on you want a large η to cover distance and explore. Late you want a small η to shrink the ball. A schedule trades between the two. It is the deep learning version of Robbins–Monro.

The common shapes

ηstep warmup + cosine one-cycle step decay warmup
Three schedule shapes. Warmup plus cosine is the default for transformers.

Why warmup helps, especially for Adam

Warmup ramps η from near zero over the first few hundred to few thousand steps. Several reasons stack up:

Why it matters in practice

Interview check

10. Coordinate descent and proximal methods

Proximal methods, in plain words. Some losses have a sharp corner, like the L1 penalty at zero. Gradients do not exist there. So split the loss into a smooth part and a simple non-smooth part. Take a gradient step on the smooth part, then solve the non-smooth part exactly.

Coordinate descent

Minimize over one coordinate at a time while holding the rest fixed. Cycle through coordinates.

Lasso and soft-thresholding

minw  (1/2n) ‖y - Xw‖2 + λ ‖w‖1

Fix all weights except wj. Let r−j be the residual without feature j. Define ρj = xjTr−j/n and zj = ‖xj‖2/n. The one-variable problem is a parabola plus λ|wj|. Its subgradient condition gives:

wj = S(ρj, λ) / zj        S(z, t) = sign(z) · max(|z| - t, 0)

S is the soft-thresholding operator. If the correlation |ρj| is below λ, the weight is exactly zero. Otherwise it shrinks toward zero by λ. That is how lasso produces sparse models.

−λλ zS(z, λ) shrink by λ zero dashed: identity
Soft-thresholding. Inputs within λ of zero map to exactly zero. Others shrink by λ.
import numpy as np

def soft(z, t):
    return np.sign(z) * np.maximum(np.abs(z) - t, 0.0)

def lasso_cd(X, y, lam, n_iter=200):
    n, d = X.shape
    w = np.zeros(d)
    r = y - X @ w                     # residual
    col_sq = (X ** 2).sum(axis=0) / n
    for _ in range(n_iter):
        for j in range(d):
            r += X[:, j] * w[j]       # remove feature j
            rho = X[:, j] @ r / n
            w[j] = soft(rho, lam) / col_sq[j]
            r -= X[:, j] * w[j]       # add it back
    return w

rng = np.random.default_rng(0)
X = rng.normal(size=(200, 10))
w_true = np.array([3, -2, 0, 0, 1.5, 0, 0, 0, 0, 0.0])
y = X @ w_true + 0.5 * rng.normal(size=200)
print(np.round(lasso_cd(X, y, lam=0.1), 2) + 0.0)
# [ 2.93 -1.88  0.    0.    1.37 -0.01  0.    0.    0.    0.  ]

Lasso keeps the three true features and zeros almost all the rest. The kept weights shrink by about λ. That bias is why people often refit the kept features without the penalty.

The proximal operator

proxηh(v) = argminx  h(x) + (1/2η) ‖x - v‖2

It finds a point that keeps h small but stays close to v. Some well-known cases:

Proximal gradient (ISTA) and FISTA

For f = g + h with g L-smooth and h simple:

θk+1 = proxηh( θk - η ∇g(θk) )        η = 1/L

ISTA keeps the O(1/k) rate of GD, even though f is not smooth. Add Nesterov momentum and you get FISTA, with rate O(1/k2). The subgradient method, by contrast, only gets O(1/√k).

Why it matters in practice

Interview check

11. EM as optimization

EM, in plain words. Some models have hidden variables, like which cluster a point came from. If you knew them, fitting would be easy. So guess them softly from the current model. Then refit the model as if the guesses were right. Repeat. Each round can only raise the likelihood.

The lower bound

Observed data x, hidden z, parameters θ. For any distribution q(z):

log p(x; θ) = Eq[ log p(x, z; θ) ] - Eq[ log q(z) ]  +  KL( q(z) ‖ p(z | x; θ) )
              =            ELBO(q, θ)                      +  KL( q ‖ posterior )

KL is never negative. So the ELBO (evidence lower bound) is always below the log-likelihood. EM is coordinate ascent on the ELBO:

Why the likelihood never drops. After the E-step, log p(x; θold) = ELBO(q, θold). The M-step gives ELBO(q, θnew) ≥ ELBO(q, θold). The bound gives log p(x; θnew) ≥ ELBO(q, θnew). Chain the three and you are done.

Gaussian mixture example

Model p(x) = Σk πk N(x; μk, σk2). The hidden zi is the component for point i.

E-step:  rik = πk N(xi; μk, σk2) / Σj πj N(xi; μj, σj2)
M-step:  Nk = Σi rik,   πk = Nk/n
         μk = Σi rik xi / Nk,   σk2 = Σi rik (xi - μk)2 / Nk

The M-step is just weighted maximum likelihood. Each point counts toward component k with weight rik.

import numpy as np

def em_gmm_1d(x, k=2, n_iter=100, seed=0):
    rng = np.random.default_rng(seed)
    pi = np.full(k, 1 / k)
    mu = rng.choice(x, k, replace=False)
    var = np.full(k, x.var())
    prev = -np.inf
    for it in range(n_iter):
        # E-step: responsibilities r[i, j] = p(z = j | x_i), in log space
        logp = (-0.5 * np.log(2 * np.pi * var)
                - 0.5 * (x[:, None] - mu) ** 2 / var + np.log(pi))
        m = logp.max(axis=1, keepdims=True)
        log_lik = (m.ravel() + np.log(np.exp(logp - m).sum(axis=1))).sum()
        r = np.exp(logp - m); r /= r.sum(axis=1, keepdims=True)
        # M-step: weighted MLE
        nk = r.sum(axis=0)
        pi = nk / len(x)
        mu = (r * x[:, None]).sum(axis=0) / nk
        var = (r * (x[:, None] - mu) ** 2).sum(axis=0) / nk
        assert log_lik >= prev - 1e-9   # EM never lowers the likelihood
        if log_lik - prev < 1e-8:
            break
        prev = log_lik
    return pi, mu, var, it

rng = np.random.default_rng(1)
x = np.concatenate([rng.normal(-2, 0.5, 300), rng.normal(3, 1.0, 700)])
pi, mu, var, it = em_gmm_1d(x)
print(np.round(pi, 2), np.round(mu, 2), np.round(np.sqrt(var), 2), it)
# [0.3 0.7] [-2.05  2.96] [0.46 1.02] 21

EM recovers the true weights 0.3 and 0.7, means −2 and 3, and spreads 0.5 and 1.0. The assert checks the monotone guarantee on every step.

Properties and pitfalls

Why it matters in practice

Interview check

12. Hyperparameter optimization

Hyperparameter optimization, in plain words. Some settings, like learning rate or depth, are not learned by gradients. Each trial means a full training run, so every trial is expensive. The goal is to find good settings in as few runs as possible.

The problem

Minimize validation loss F(λ) over hyperparameters λ. F is a black box. It has no gradients, each call is costly, and it is noisy across seeds. Some dimensions are continuous, some are integers, and some are choices.

Grid search

Try every combination on a grid. With k values per dimension and d dimensions, that is kd runs. It wastes budget badly. Suppose only one of three dimensions matters. A 5×5×5 grid runs 125 trials but tests only 5 distinct values of the one that matters.

Random search

Sample each hyperparameter from a distribution. Bergstra and Bengio showed it beats grid search for the same budget. Every trial tests a new value of every dimension. With 125 random trials, you test 125 values of the one that matters.

Bayesian optimization with a GP and expected improvement

BO fits a cheap surrogate model to the trials so far. It then picks the next trial by maximizing an acquisition function that balances exploration and exploitation.

The surrogate. A Gaussian process gives a posterior mean μ(λ) and standard deviation σ(λ) at every point. With kernel matrix K over observed points, k* between a new point and observed points, and targets y:

μ(λ)  = k*T (K + σn2I)-1 y
σ2(λ) = k(λ, λ) - k*T (K + σn2I)-1 k*

A Matérn 5/2 kernel is the usual choice. It is smooth but not too smooth.

Expected improvement. Let fbest be the lowest loss so far. The improvement at λ is max(fbest − F(λ), 0). Under the GP it has a closed-form mean:

Z     = (fbest - μ(λ) - ξ) / σ(λ)
EI(λ) = (fbest - μ(λ) - ξ) Φ(Z) + σ(λ) φ(Z)

Here Φ and φ are the standard normal CDF and PDF. The first term rewards a low predicted mean, which is exploitation. The second rewards high uncertainty, which is exploration. The small ξ ≥ 0 tilts toward exploration.

import numpy as np
from math import erf, sqrt, pi

def rbf(a, b, ls=0.3):
    return np.exp(-0.5 * (a[:, None] - b[None, :]) ** 2 / ls ** 2)

def gp_posterior(X, y, Xs, noise=1e-6):
    K = rbf(X, X) + noise * np.eye(len(X))
    Ks = rbf(X, Xs)
    Lc = np.linalg.cholesky(K)
    alpha = np.linalg.solve(Lc.T, np.linalg.solve(Lc, y))
    mu = Ks.T @ alpha
    v = np.linalg.solve(Lc, Ks)
    sd = np.sqrt(np.maximum(1.0 - (v ** 2).sum(axis=0), 1e-12))
    return mu, sd

def expected_improvement(mu, sd, best, xi=0.01):
    z = (best - mu - xi) / sd                 # minimization
    cdf = 0.5 * (1 + np.vectorize(erf)(z / sqrt(2)))
    pdf = np.exp(-0.5 * z ** 2) / sqrt(2 * pi)
    return (best - mu - xi) * cdf + sd * pdf

f = lambda x: np.sin(3 * x) + 0.5 * x         # stand-in for validation loss
grid = np.linspace(0, 2, 401)
X = np.array([0.1, 1.0, 1.9]); y = f(X)
for step in range(6):
    mu, sd = gp_posterior(X, y - y.mean(), grid)
    ei = expected_improvement(mu + y.mean(), sd, y.min())
    x_next = grid[np.argmax(ei)]
    X, y = np.append(X, x_next), np.append(y, f(x_next))
print("best x = %.3f, best f = %.3f" % (X[y.argmin()], y.min()))
# best x = 1.525, best f = -0.228   (true minimum near x = 1.515)

Nine evaluations land within 0.01 of the true minimum. Random search would need many more.

Hyperband and successive halving

Most bad configs look bad early. So stop them early and give their budget to the promising ones.

Successive halving (SH). Start n configs with budget r each, like r epochs. Keep the top 1/η by validation loss. Multiply their budget by η. Repeat until one remains. With η = 3, 81 configs at 1 epoch become 27 at 3, 9 at 9, 3 at 27, and 1 at 81.

The catch. SH assumes early rankings predict final rankings. That fails for configs that start slow but finish strong, like a low learning rate. Choosing n versus r is a bet on how reliable early signals are.

Hyperband. It hedges that bet. It runs several SH brackets, from "many configs, tiny budget" to "few configs, full budget". The last bracket is plain random search. Hyperband is never much worse than the best bracket, and you do not have to guess.

Why it matters in practice

Interview check

Recap

← T3 — Probability and Information Theory T5 — Linear Algebra and Matrix Calculus →