§ Gradients · Interactive Graduate Primer
Tensor by Tensor · expanded

Finite differences

Learn how changing several inputs changes one output. Begin with partial derivatives, then explore gradient descent, backpropagation, and optimizers. The later sections include proofs and deeper mathematical detail.
A first reading path

Start with sections 2–4, then section 7. Return to the directional-derivative proof after you understand a gradient-descent update. An optimizer is a rule for updating the model’s adjustable numbers.

For L(a, b) = a² + 2b², the gradient at (1, 2) is [2, 8]. The first entry measures change along a while b stays fixed. The second measures change along b while a stays fixed. With step size 0.1, subtract [0.2, 0.8] to reach (0.8, 1.2). The loss falls from 9 to 3.52.

Check: why subtract the gradient?

The gradient points toward the steepest local increase under the usual Euclidean length measure. Subtracting it moves toward a local decrease when the step is small enough. A large step can still overshoot and increase the loss.

8. Numerical Gradient Checking

Introduction

A backward pass can silently return a wrong gradient even when the loss decreases. At parameters 3 and negative 1, centered finite differences reproduce analytic gradients 4 and 8 to high precision.

Learning goal

Check an analytic gradient numerically with centered differences and interpret both absolute and relative disagreement.

Before you start

Derivatives, function evaluation, subtraction, small decimal values, and Python arrays.

Lesson plan

  1. Perturb one parameter upward and downward while holding the others fixed.
  2. Form a centered difference and compare it with the analytic derivative.
  3. Use relative error and suitable step sizes to diagnose a broken implementation.

Gradient checking asks whether two independent calculations agree: backpropagation and a small finite difference. Use it as a correctness test on a tiny deterministic case. Do not use the finite difference as the training algorithm.

Always verify analytic gradients numerically before training. The centred-difference formula has $O(\varepsilon^2)$ truncation error:

$$\frac{\partial L}{\partial \theta_i} \approx \frac{L(\theta+\varepsilon e_i)-L(\theta-\varepsilon e_i)}{2\varepsilon}.$$

With $\varepsilon=10^{-5}$ and double precision, relative error should be $\sim 10^{-9}$. Anything above $10^{-5}$ is a bug.

import numpy as np
def L(w, b): return (w-1)**2 + 4*(b+2)**2
def analytic(w, b): return np.array([2*(w-1), 8*(b+2)])
def numerical(w, b, eps=1e-5):
    dw = (L(w+eps, b) - L(w-eps, b)) / (2*eps)
    db = (L(w, b+eps) - L(w, b-eps)) / (2*eps)
    return np.array([dw, db])
a, n = analytic(3, -1), numerical(3, -1)
print(np.abs(a - n) / (np.abs(a) + 1e-12))   # ~1e-11