Finite-sum objectives#
Nearly all supervised learning objectives have the form:
where is the loss on the -th training example. This is the ERM objective from Week 1.
The full gradient is , which requires scanning all examples, one full pass through the dataset, for a single parameter update. When is large (millions or billions), this is impossibly slow.
SGD replaces the full sum with an estimate computed from a small, randomly chosen mini-batch.
Mini-batch SGD#
At iteration , sample a mini-batch of size uniformly at random (without replacement). The mini-batch gradient estimate is:
The SGD update is then .
Two key properties of :
-
Unbiased: . On average, the mini-batch gradient points in the right direction. The expectation is over the random choice of .
-
Noisy: is proportional to . A smaller batch has higher variance (noisier gradient estimate) but is cheaper to compute.
Computational cost per step:
- Full-batch GD: to compute , then to update
- Mini-batch SGD (size ): to compute , then to update
SGD makes roughly times as many updates in the time it takes GD to do one update.
Noise and variance#
The variance of the mini-batch gradient estimate is:
The term measures how different individual example gradients are from the average. When examples are "similar" (homogeneous data), is small and SGD works well even with . When examples are very different (heterogeneous data), you need larger batches to reduce variance.
The batch-size tradeoff:
- Small : cheap per iteration, many noisy updates per epoch → better exploration
- Large : expensive per iteration, fewer but more accurate updates → reliable descent
- : recovers full-batch GD (zero variance, maximum cost per step)
In practice, is typically chosen as a power of 2 (32, 64, 128, 256) to fit well with GPU memory and vectorised computation.
Step sizes under noise#
With a fixed step size , SGD does not converge to the exact optimum. It oscillates in a ball around whose radius is proportional to . To converge exactly, we must decay the step size:
The schedule is common in theory; in practice, step-decay (halve every epochs) and cosine annealing (Week 9) are more popular.
A useful heuristic: for SGD with batch size , a rule of thumb is . Doubling the batch size approximately allows doubling the learning rate (because the gradient estimate is twice as accurate).
Epoch vs step#
- Step (or iteration): one mini-batch processed, one parameter update
- Epoch: one full pass through the entire dataset ( steps)
At the end of each epoch, the data is typically shuffled (random permutation) to avoid periodicity effects and to decorrelate consecutive mini-batches. Mini-batches drawn from a shuffled epoch are not independent — within an epoch they partition the data, so they are negatively correlated, but each is an unbiased estimate of the full gradient, which is what the convergence theory needs.
Tracking loss per epoch is more meaningful than loss per step, because epoch-level loss estimates the true objective while step-level loss is computed on a single mini-batch and is noisier.
Knowledge check#
If the mini-batch size B is doubled, the variance of the gradient estimate is approximately:
The mini-batch gradient g_k is an unbiased estimate of the full gradient ∇f(w) because:
Browser lab: GD vs SGD noise tradeoff#
Compare GD, SGD(B=1), and SGD(B=16) on a finite-sum quadratic objective. Plot loss vs epoch and observe the noise–convergence tradeoff.
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng(42)
d, n = 3, 200
w_true = np.array([1.5, -0.8, 0.6])
X = rng.normal(size=(n, d))
y = X @ w_true + rng.normal(scale=0.3, size=n)
def loss(w, X, y):
return 0.5 * np.mean((X @ w - y)**2)
def run_method(X, y, w0, n_epochs, method, B=None, eta=None):
w = w0.copy()
n = len(X)
epoch_losses = []
for ep in range(n_epochs):
perm = rng.permutation(n)
for start in range(0, n, B or n):
idx = perm[start:start + (B or n)]
g = X[idx].T @ (X[idx] @ w - y[idx]) / len(idx)
w -= eta * g
epoch_losses.append(loss(w, X, y))
return epoch_losses
w0 = np.zeros(d)
n_epochs = 40
L = np.linalg.eigvalsh(X.T @ X / n).max()
eta = 1.0 / L
losses_gd = run_method(X, y, w0, n_epochs, "GD", B=n, eta=eta)
losses_sgd1 = run_method(X, y, w0, n_epochs, "SGD1", B=1, eta=eta*0.05)
losses_sgd16 = run_method(X, y, w0, n_epochs, "SGD16", B=16, eta=eta*0.5)
plt.figure(figsize=(8, 5))
plt.plot(losses_gd, label="GD (full batch)", linewidth=2)
plt.plot(losses_sgd1, alpha=0.8, label="SGD B=1 (noisy)", linewidth=1)
plt.plot(losses_sgd16, alpha=0.8, label="SGD B=16", linewidth=1.5)
plt.yscale("log")
plt.xlabel("Epoch"); plt.ylabel("Loss")
plt.title("GD vs SGD: Loss per Epoch")
plt.legend(); plt.grid(True, alpha=0.3)
plt.show()
print("Notice: full-batch GD is smooth but makes one update per epoch; SGD B=1 is noisy yet far cheaper per step.")
Key takeaways#
- SGD replaces the full gradient with a mini-batch average that is unbiased but noisy, with variance scaling as .
- Cost per update falls from to , so SGD takes roughly updates in the time full-batch GD takes one.
- A fixed step size leaves SGD oscillating in a ball of radius proportional to ; decaying is what buys convergence to the optimum.
- Batch size and learning rate trade off multiplicatively: the linear scaling rule lets you roughly double when you double .
- Epoch-level loss is the meaningful curve; step-level loss is a noisy estimate from a single batch.
- The noise structure introduced here is the input to momentum (Week 7) and Adam (Week 8).
Further reading#
- Léon Bottou, Frank E. Curtis & Jorge Nocedal, Optimization Methods for Large-Scale Machine Learning (SIAM Review, 2018). Section 5 is the standard analysis of SGD, mini-batching, and step-size schedules.
- Ian Goodfellow, Yoshua Bengio & Aaron Courville, Deep Learning (MIT Press, 2016). §8.3 covers mini-batch and stochastic gradient methods.
- Herbert Robbins & Sutton Monro, "A Stochastic Approximation Method" (Annals of Mathematical Statistics, 1951). The original stochastic-approximation result behind SGD.
Reading is free. PDF and ePub unlock with the newsletter. Join once and every lesson opens in this browser.