Numerical gradient by central differences
Easy10 min11 hidden tests
A search team wrote a custom ranking loss and wants to see its slopes before they trust any backprop code. Write numerical_gradient(f, x, h) that estimates the gradient of a scalar function f at the point x. For each coordinate, nudge only that coordinate up by h and down by h, and divide the change in f by 2 * h. This is the central difference.
Drag the point, change h
slope ≈ (f(x+h) − f(x−h)) / 2hTrue slope 3x² = 3. Central difference 3.01, off by 0.01. One-sided 3.31, off by 0.31. Halve h and the central error drops about 4 times; the one-sided error only about halves.
x 1, h 0.1. True slope 3, central 3.01, one-sided 3.31.
Examples
The slopes of x0 squared plus 3 x1 at (2, 1) are 4 and 3
numerical_gradient(lambda v: v[0] ** 2 + 3 * v[1], [2.0, 1.0], 1e-5)
returns [4, 3]
With a large h, a cubic's estimate is off by h squared: 3.01 and 12.01
numerical_gradient(lambda v: np.sum(v ** 3), [1.0, -2.0], 0.1)
returns [3.01, 12.01]
Requirements
ftakes a 1-D float array and returns a float.xis a list or 1-D array of n numbers, andhis a small positive float with a default of 1e-5.- Return a 1-D NumPy float array of length n. Entry i is
(f(x + h * e_i) - f(x - h * e_i)) / (2 * h), wheree_iis 1 at position i and 0 everywhere else. - Move one coordinate at a time, and leave the caller's
xunchanged.
The idea behind it
A gradient is a list of slopes: entry i says how fast a function grows when input i grows a little and every other input stays put. Backpropagation computes it exactly, but it is easy to get wrong when you write it by hand. A finite difference estimates the same slope from the function alone. The forward difference (f(x + h) - f(x)) / h has an error that shrinks in step with h. The central difference (f(x + h) - f(x - h)) / (2h) looks on both sides, and its error shrinks with h squared, so it is far more accurate for the same h. On a quadratic it is exact. It costs two calls to f per input, which is too slow for training a large model and just right for checking one. Frameworks ship it for this reason: PyTorch's gradcheck compares backprop against these estimates.
Worked solution
Give it a real try first. Then read the solution and why each line is there.