Create your own
Lesson illustration

Finite-Difference Gradients and Descent Directions

Welcome back. In the previous lesson, a dot product turned feature values and weights into a single score. Here, we use that same operation in a new role: it explains why the gradient tells us which small parameter change will increase or decrease a function most quickly.

You will treat a two-variable function as a local landscape, estimate its slopes numerically without differentiating it symbolically, combine those estimates into a gradient vector, and choose a step that lowers the function. This is the core calculation behind gradient descent, which you will implement more fully later in Month 1.


Partial derivatives: change one coordinate, hold the other fixed

Suppose a function depends on two inputs:

At a particular point , the partial derivative with respect to asks:

If changes slightly while stays fixed, how quickly does change?

Likewise, the partial derivative with respect to changes only , holding fixed.

For a loss function in machine learning, you can interpret and as two model parameters. Each partial derivative measures how sensitive the loss is to one parameter, assuming the other is temporarily unchanged.

For example, let

and evaluate it at:

The function value there is:

Rather than using calculus to obtain an exact derivative, we will estimate each slope by probing nearby points.


Finite differences: estimate a slope from nearby function values

A finite difference replaces an infinitesimal change with a small, concrete step . In one dimension, it approximates a tangent slope by a secant slope.

For the partial derivative with respect to , keep constant and move only in the direction.

Forward difference

This compares the current point with one point “forward” in the direction.

Backward difference

This uses the point behind the current position.

Central difference

Central difference samples on both sides of the target point. For smooth functions, it is usually the preferred numerical estimate because its approximation error decreases more rapidly as becomes smaller.

The same pattern applies to :

Three graphs compare forward, backward, and central secant slopes to a curve’s tangent slope at \(x_j\). For partial derivatives, apply the same idea while moving along one coordinate axis at a time.

For a concise visual derivation of why central differences are typically more accurate than one-sided estimates, watch this segment.

Numerical Differentiation with Finite Difference Derivatives

Numerical Differentiation with Finite Difference Derivatives by Steve Brunton derives forward, backward, and central difference estimates and explains why the symmetric central estimate cancels more error.

Watch central differences. Focus on the symmetry of evaluating the function at both t+h and t-h, and on the conclusion that central-difference error is proportional to h^2, rather than h.

A note on choosing

Choosing involves a practical trade-off:

  • If is too large, the secant line spans too much curvature and is a poor local approximation.
  • If is extremely small, floating-point rounding can dominate the subtraction of nearly equal values.

For the small, well-scaled examples in this course, values such as 1e-4 or 1e-5 are sensible starting points. Numerical gradients are especially useful for checking an implementation; later, analytic gradients will usually be faster for actual model training.


Estimating two partial derivatives at one point

Return to:

at . Let .

To estimate the -partial derivative, change while keeping :

The two function values are:

Therefore:

So a small positive move in decreases : the local -slope is negative.

Now vary while keeping :

Here, increasing increases , so the -slope is positive.

These two values are the components of the gradient.


Assemble the gradient and reverse it to descend

For a two-variable function, the gradient is:

At , our finite-difference estimates give:

The gradient points in the local direction of steepest increase. Therefore, its negative points in the local direction of steepest decrease:

This tells us to increase and decrease .

The connection to the prior dot-product lesson is precise. For a small position change ,

If we choose:

where is a small step size, then:

This is negative whenever the gradient is nonzero. Thus, for a sufficiently small , the function should decrease locally.

Using :

The loss falls from:

to:

The direction was right; the step successfully moved downhill.

A zero gradient is a special case: it means there is no first-order uphill or downhill direction at that exact point. It may be a minimum, a maximum, or a saddle point, so zero gradient alone does not prove that a function is minimized.


Numerical gradients in NumPy

The CS231n notes provide a general pattern for numerical gradients: alter one coordinate, evaluate the function, restore the original coordinate, then repeat for each coordinate.

CS231n Deep Learning for Computer Vision

Read the numerical-gradient pattern and its connection to negative-gradient updates. The code is written for arbitrary arrays, but the underlying process is exactly the two-coordinate calculation from this lesson.

In the “Computing the gradient” section, read the finite difference explanation. Notice that one array entry is perturbed at a time, so every output entry of grad is one partial derivative. Then continue to the next discussion, beginning the negative gradient update. Focus on why the update subtracts the gradient and why a larger step size can increase loss rather than decrease it.

In practice, use .copy() when making perturbed versions of a parameter vector. This avoids accidentally changing the original evaluation point and corrupting later estimates.


Concept-Level Micro-Challenge: central-difference gradient and one descent step

Type and run this 15-line NumPy program. It estimates both partial derivatives using central differences, then takes one negative-gradient step.

import numpy as np
def loss(p):
    x, y = p
    return (x - 3)**2 + 2 * (y + 1)**2
p = np.array([0.0, 2.0]); h = 1e-4
grad = np.zeros_like(p)
for j in range(p.size):
    plus = p.copy()
    minus = p.copy()
    plus[j] += h; minus[j] -= h
    grad[j] = (loss(plus) - loss(minus)) / (2 * h)
p_new = p - 0.1 * grad
print("gradient:", grad, "old/new loss:", loss(p), loss(p_new))
assert np.allclose(grad, [-6.0, 12.0], atol=1e-6)
assert loss(p_new) < loss(p)

Your expected gradient is approximately:

Read the loop carefully:

  • At j = 0, only the first coordinate changes, so the code estimates .
  • At j = 1, only the second coordinate changes, so it estimates .
  • p - 0.1 * grad moves in the negative-gradient direction.

As a brief self-check, change the final update to p + 0.1 * grad. The assertion that the loss decreases should fail, because this update deliberately moves uphill.


Common mistakes to catch early

  1. Changing both variables for one partial derivative.
    To estimate , alter only p[0]; keep p[1] fixed. Changing both coordinates estimates movement along a diagonal, not a partial derivative.

  2. Forgetting the denominator in central difference.
    The two samples are apart, not apart.

  3. Using the gradient as a descent direction.
    The gradient points uphill. Use -grad or subtract learning_rate * grad.

  4. Taking a step that is too large.
    A gradient is local information. A direction can be correct while an oversized step overshoots into a higher-loss region.

  5. Mutating the base point accidentally.
    Use plus = p.copy() and minus = p.copy(). If the base point changes inside the loop, the partial derivatives no longer refer to the same location.


Takeaways

A partial derivative measures local change along one coordinate while all other coordinates remain fixed. Finite differences approximate that derivative using nearby function values; central difference is usually the strongest default:

For a two-variable function, assemble both estimates into the gradient:

The gradient points toward local steepest increase. Its negative gives a local descent direction, and a small update of the form

should reduce the function when the step size is appropriate.

Next, you will switch from optimization math to probability, calculating conditional probabilities and applying Bayes’ rule in a compact diagnostic example.

Can't find a good explanation? Sign up and we'll make it for you

Sign up