Skip to content

← JAX Autodiff step 8 of 25

Medium Primitives

HVP via grad-of-grad

Jump to the task

How a gradient changes

A gradient measures how a scalar loss changes with its inputs. The Hessian measures how that gradient changes. For d inputs it is a d by d matrix of second derivatives.

Often we only need its product with a vector, H @ v: the rate at which the gradient changes along x + epsilon*v. This avoids constructing a dense Hessian with d*d entries. It does not guarantee total memory use of O(d), since the differentiated computation can store other arrays.

Make a scalar before differentiating again

jax.grad needs a scalar output. If x is a vector, jax.grad(f)(x) is also a vector, so calling jax.grad(jax.grad(f))(x) raises an error. It does not return a Hessian. jax.hessian(f)(x) would construct the full matrix, but that is unnecessary for a single product.

Instead, take the dot product of the gradient with a fixed v, then differentiate that scalar:

import jax
import jax.numpy as jnp

A = jnp.array([[2.0, 1.0], [1.0, 3.0]])
x = jnp.array([1.0, 2.0])
v = jnp.array([2.0, -1.0])

def f(x):
    return 0.5 * x @ A @ x

grad_f = jax.grad(f)
hvp = jax.grad(lambda z: jnp.vdot(grad_f(z), v))(x)
# hvp = [3.0, -1.0]

Differentiating this dot product gives H.T @ v. For a twice continuously differentiable real scalar function, the Hessian is symmetric, so this equals H @ v. Here A is symmetric and the loss is quadratic: its gradient is A @ x and its Hessian is A. Thus A @ v = [2*2 - 1, 1*2 - 3] = [3, -1].

For these real vectors, jnp.vdot is the usual dot product. Keep v fixed during differentiation. Capturing it in the outer scope, as above, is one way to do that. This construction uses reverse-mode differentiation through another reverse-mode derivative.

Problem

Implement hvp_grad_of_grad(x, A, v) using the nested-gradient method for f(x) = 0.5 * x @ A @ x.

All inputs are real floating-point JAX arrays. x and v have shape (d,), and A has shape (d, d) and is symmetric. Hold A and v fixed. Return a JAX array with shape (d,), containing H @ v.

For this quadratic the answer is A @ v and does not depend on x. Use that fact to check your answer while practicing nested gradients. Numerical tests alone cannot enforce which method you use.