Skip to main content
© 2026 ePowerAI — instrumented learning, no login required.
CoursesContact
ePOWERAI
CoursesContact
Week 9: Variance Reduction
Adv. Optimization
01Week 1: Optimality Conditions Revisited
02Week 2: Lagrangian Duality in Depth
03Week 3: KKT and Sensitivity
04Week 4: LP, QP, and Conic Form
05Week 5: Semidefinite Programming
06Week 6: Interior-Point Methods
07Week 7: Proximal Methods and ADMM
08Week 8: Newton and Quasi-Newton
09Week 9: Variance Reduction
10Week 10: Large-Batch and Distributed Training
11Week 11: Automatic Differentiation
12Week 12: Sharpness and SAM
13Week 13: Landscapes and Implicit Bias
14Week 14: Capstone — Structure Meets Scale
Week 09· Adv. Optimization· Second-order & scale6 min read

Week 9: Variance Reduction

Learning Outcomes
  • Write the finite-sum objective f(x)=1n∑i=1nfi(x)f(x) = \frac{1}{n}\sum_{i=1}^n f_i(x)f(x)=n1​∑i=1n​fi​(x) and its full gradient
  • Explain gradient variance as the obstacle that forces SGDStochastic Gradient Descent to decay its learning rate
  • Describe SVRGStochastic Variance Reduced Gradient's snapshot gradient control variate and why it reduces variance
  • State when variance-reduced methods beat minibatch SGD
Prerequisites

Background: Week 8 (convergence rates, Newton vs first-order trade-offs). Intermediate Optim Weeks 6–7 (SGDStochastic Gradient Descent, momentum, learning rate schedules). The concept that SGD's noise comes from sampling a random fif_ifi​ at each step.

Later weeks: Variance reduction is the conceptual foundation for Week 10 (large-batch training, where variance scales inversely with batch size) and explains why large-batch training can increase variance if not paired with learning rate adjustments.

  • Also see: Optimization Week 6: Stochastic Gradient Descent — the variance story that motivates control variates.

Finite-Sum Structure#

The ERMEmpirical Risk Minimization objective has a special structure explicitly exploited by variance reduction:

f(x)=1n∑i=1nfi(x)f(x) = \frac{1}{n}\sum_{i=1}^n f_i(x)f(x)=n1​∑i=1n​fi​(x)

Each fif_ifi​ is the loss on a single training example (or a minibatch, for batched VR methods). The gradient is:

∇f(x)=1n∑i=1n∇fi(x)\nabla f(x) = \frac{1}{n}\sum_{i=1}^n \nabla f_i(x)∇f(x)=n1​∑i=1n​∇fi​(x)

Computing the full gradient costs O(n)O(n)O(n) per iteration — cheap for n=104n = 10^4n=104, expensive for n=107n = 10^7n=107. SGD samples one index iii uniformly and uses ∇fi(x)\nabla f_i(x)∇fi​(x) as a stochastic gradient:

Ei[∇fi(x)]=∇f(x)\mathbb{E}_i[\nabla f_i(x)] = \nabla f(x)Ei​[∇fi​(x)]=∇f(x)

The estimator is unbiased, but its variance is the root problem.

Variance of SGD#

Even at the optimum x∗x^*x∗ where ∇f(x∗)=0\nabla f(x^*) = 0∇f(x∗)=0, a stochastic gradient ∇fi(x∗)\nabla f_i(x^*)∇fi​(x∗) is generally nonzero — different data points pull in different directions, and only their average cancels. The gradient variance at xxx is:

σ2(x)=1n∑i=1n∥∇fi(x)−∇f(x)∥2\sigma^2(x) = \frac{1}{n}\sum_{i=1}^n \|\nabla f_i(x) - \nabla f(x)\|^2σ2(x)=n1​∑i=1n​∥∇fi​(x)−∇f(x)∥2

SGD's convergence rate under strong convexity is:

E[∥xk−x∗∥2]≤(1−ημ)k∥x0−x∗∥2+ησ2μ\mathbb{E}[\|x_k - x^*\|^2] \leq (1 - \eta\mu)^k \|x_0 - x^*\|^2 + \frac{\eta \sigma^2}{\mu}E[∥xk​−x∗∥2]≤(1−ημ)k∥x0​−x∗∥2+μησ2​

where σ2\sigma^2σ2 bounds the variance. The second term is an asymptotic noise floor that does not vanish as k→∞k \to \inftyk→∞. To converge to the exact minimiser, SGD must decay the learning rate ηk→0\eta_k \to 0ηk​→0. A constant learning rate converges only to a neighbourhood of the optimum, with radius proportional to ησ2\sqrt{\eta \sigma^2}ησ2​.

The core tension: SGD is cheap per iteration (O(1)O(1)O(1) vs O(n)O(n)O(n) for full-batch) but requires decaying learning rates and many epochs for high accuracy. Variance reduction retains the O(1)O(1)O(1) per-iteration cost (amortised) while achieving linear convergence to the exact solution — no learning rate decay needed.

SVRG#

Stochastic Variance Reduced Gradient (SVRG) uses a control variate — a correlated, zero-mean correction that reduces the effective variance of the stochastic gradient.

SVRG operates in outer loops (epochs). At the start of each outer loop sss, a full gradient is computed at a snapshot x~s\tilde{x}_sx~s​:

μ~s=∇f(x~s)=1n∑i=1n∇fi(x~s)\tilde{\mu}_s = \nabla f(\tilde{x}_s) = \frac{1}{n}\sum_{i=1}^n \nabla f_i(\tilde{x}_s)μ~​s​=∇f(x~s​)=n1​∑i=1n​∇fi​(x~s​)

Then for mmm inner iterations (m≈2nm \approx 2nm≈2n in the original paper), the stochastic gradient is:

vk=∇fi(xk)−∇fi(x~s)+μ~sv_k = \nabla f_i(x_k) - \nabla f_i(\tilde{x}_s) + \tilde{\mu}_svk​=∇fi​(xk​)−∇fi​(x~s​)+μ~​s​

where iii is sampled uniformly at random. The key insight: Ei[∇fi(x~s)]=μ~s\mathbb{E}_i[\nabla f_i(\tilde{x}_s)] = \tilde{\mu}_sEi​[∇fi​(x~s​)]=μ~​s​, so the term −∇fi(x~s)+μ~s-\nabla f_i(\tilde{x}_s) + \tilde{\mu}_s−∇fi​(x~s​)+μ~​s​ has zero mean but is correlated with ∇fi(xk)\nabla f_i(x_k)∇fi​(xk​). When xk≈x~sx_k \approx \tilde{x}_sxk​≈x~s​, the two gradients are similar, and their difference is small — the variance is dramatically reduced.

After mmm inner steps, the snapshot is updated: x~s+1=xm\tilde{x}_{s+1} = x_mx~s+1​=xm​ (or a random/average of the inner iterates), and a new full gradient is computed.

Convergence. Under strong convexity and smoothness, SVRG converges linearly (geometric rate) to the exact minimiser with a constant step size — no decay needed. The amortised cost per iteration is roughly O(1+n/m)O(1 + n/m)O(1+n/m), balancing the occasional O(n)O(n)O(n) full gradient against mmm cheap O(1)O(1)O(1) inner steps.

SAGA#

SAGA is a close cousin that avoids the outer-loop structure by maintaining a table of historical gradients:

At all times, the algorithm stores ∇fi(x^i)\nabla f_i(\hat{x}_i)∇fi​(x^i​) for each iii, where x^i\hat{x}_ix^i​ is the most recent iterate at which ∇fi\nabla f_i∇fi​ was evaluated. Each iteration:

  1. Sample index iii uniformly.
  2. Form the SAGA gradient: vk=∇fi(xk)−∇fi(x^i)+1n∑j=1n∇fj(x^j)v_k = \nabla f_i(x_k) - \nabla f_i(\hat{x}_i) + \frac{1}{n}\sum_{j=1}^n \nabla f_j(\hat{x}_j)vk​=∇fi​(xk​)−∇fi​(x^i​)+n1​∑j=1n​∇fj​(x^j​)
  3. Update the table entry for iii: x^i=xk\hat{x}_i = x_kx^i​=xk​, and update the running average of stored gradients.

The running average acts as an approximation of the full gradient, updated incrementally (no full-batch pass needed). SAGA requires O(n)O(n)O(n) memory to store the gradient table (one vector per training example), which limits its use to moderate nnn. SVRG's memory is O(1)O(1)O(1) beyond storing a single snapshot gradient.

Practice Notes#

Where VR methods shine:

  • Moderate nnn (thousands to low millions of examples) where computing full gradients periodically is affordable.
  • Convex or strongly convex problems where linear convergence matters.
  • Logistic regression, SVMs, and classical ML with explicit finite-sum structure.

Where VR methods are rarely used:

  • Deep learning with n≫107n \gg 10^7n≫107: storing per-example gradients (SAGA) or computing periodic full gradients (SVRG) is impractical.
  • Nonconvex objectives: the control variate argument relies on convexity; the theory is weaker in the nonconvex case, though some extensions exist.
  • When the computational bottleneck is O(d)O(d)O(d) per gradient computation rather than the number of gradient evaluations — VR reduces the number of gradient calls, not the cost per call.

Legacy and influence. While classical SVRG/SAGA are not standard in deep learning pipelines, the control-variate idea has influenced modern methods: momentum-based variance reduction, stochastic Newton sketches, and the analysis of large-batch training all draw on the same variance decomposition.

Knowledge check#

Exercise · Fill in the blank

At the snapshot $\tilde{x}_s$, the SVRG control variate $-\nabla f_i(\tilde{x}_s) + \tilde{\mu}_s$ has expected value ____.

Question 1 of 3

The finite-sum objective $f(x) = rac{1}{n}sum_{i=1}^n f_i(x)$ appears in ERM, where each $f_i$ is the ____ on a single example.

Browser lab#

On synthetic finite-sum least squares (n=1000n = 1000n=1000, d=20d = 20d=20), compare the gradient error norm ∥∇f(xk)∥\|\nabla f(x_k)\|∥∇f(xk​)∥ for SGD vs SVRG over epochs. The step size is taken from the SVRG stability condition η⋅max⁡i∥xi∥2<1\eta \cdot \max_i \|x_i\|^2 < 1η⋅maxi​∥xi​∥2<1 — pick it too large and the control-variate recursion diverges, which is the fastest way to make SVRG look worse than SGD. With a stable η\etaη, SVRG drives the gradient to numerical zero while SGD stagnates at the noise floor.

python · runs in browser
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)
n, d = 1000, 20
X = np.random.randn(n, d)
w_opt = np.random.randn(d)
y = X @ w_opt + 0.1 * np.random.randn(n)

def compute_gradient(w):
    return X.T @ (X @ w - y) / n

def compute_gradient_i(w, i):
    return X[i] * (X[i] @ w - y[i])

# SVRG's variance-reduced step is only stable while eta * max_i ||x_i||^2 < 1,
# where max_i ||x_i||^2 bounds the smoothness of a single f_i. We pick eta from
# that bound instead of guessing: eta = 0.05 violates it and SVRG diverges.
max_sample_smoothness = float((X ** 2).sum(axis=1).max())
eta = 0.5 / max_sample_smoothness
n_epochs = 60
print(f"max_i ||x_i||^2 = {max_sample_smoothness:.2f}  ->  stable eta < "
      f"{1/max_sample_smoothness:.4f}; using eta = {eta:.4f}")

# SGD with constant step size
w_sgd = np.zeros(d)
sgd_epochs, sgd_grad_norms = [], []
for epoch in range(1, n_epochs + 1):
    for i in np.random.permutation(n):
        w_sgd = w_sgd - eta * compute_gradient_i(w_sgd, i)
    sgd_epochs.append(epoch)
    sgd_grad_norms.append(np.linalg.norm(compute_gradient(w_sgd)))

# SVRG: one full-gradient snapshot per outer loop, m = 2n inner steps (2 epochs)
m = 2 * n
w_svrg = np.zeros(d)
svrg_epochs, svrg_grad_norms = [], []
for outer in range(n_epochs // 2):
    w_snap = w_svrg.copy()
    full_grad_snap = compute_gradient(w_snap)
    for inner in range(m):
        i = np.random.randint(n)
        g = compute_gradient_i(w_svrg, i) - compute_gradient_i(w_snap, i) + full_grad_snap
        w_svrg = w_svrg - eta * g
        if (inner + 1) % n == 0:
            # SVRG has consumed (outer*m + inner + 1) single-sample gradients = this many epochs
            svrg_epochs.append((outer * m + inner + 1) / n)
            svrg_grad_norms.append(np.linalg.norm(compute_gradient(w_svrg)))

sgd_floor = sgd_grad_norms[-1]
fig, ax = plt.subplots(figsize=(8, 5))
ax.semilogy(sgd_epochs, sgd_grad_norms, "b-", linewidth=1.2, alpha=0.8,
            label=r"SGD (constant $\eta$)")
ax.semilogy(svrg_epochs, np.maximum(svrg_grad_norms, 1e-14), "r-", linewidth=1.5,
            label="SVRG")
ax.axhline(sgd_floor, color="gray", linestyle="--", alpha=0.6, label="SGD noise floor")
ax.set_xlabel("Epochs (passes over the data)")
ax.set_ylabel(r"$\|\nabla f(w)\|$ (log scale)")
ax.set_title("Gradient norm: SGD vs SVRG on finite-sum least squares")
ax.legend()
ax.grid(True, alpha=0.3)
plt.show()

print(f"Final SGD gradient norm:  {sgd_grad_norms[-1]:.6f}")
print(f"Final SVRG gradient norm: {svrg_grad_norms[-1]:.2e}")
print("Notice: SGD bounces around the noise floor set by its constant step size, while "
      "SVRG's variance-reduced steps drive the full gradient to machine zero.")

Further Reading#

  • Rie Johnson & Tong Zhang, "Accelerating Stochastic Gradient Descent using Predictive Variance Reduction" (NeurIPS 2013) — the original SVRG.
  • Aaron Defazio, Francis Bach & Simon Lacoste-Julien, "SAGA: A Fast Incremental Gradient Method With Support for Non-Strongly Convex Composite Objectives" (NeurIPS 2014).
  • Léon Bottou, Frank E. Curtis & Jorge Nocedal, Optimization Methods for Large-Scale Machine Learning (SIAM Review, 2018) — where variance reduction sits in the wider landscape.
← Previous
Week 8: Newton and Quasi-Newton
Next →
Week 10: Large-Batch and Distributed Training
On this page
  • Finite-Sum Structure
  • Variance of SGD
  • SVRG
  • SAGA
  • Practice Notes
  • Knowledge check
  • Browser lab
  • Further Reading