Type at least 2 letters. Enter opens the first result, Esc closes.

    Calculus for ML · Lesson 8 · Second-order and implicit derivatives

    Hessian-vector products, Gauss-Newton and trace estimation

    Advanced 70 min 4 interactive figures 2 videos Colab notebook

    Before this lesson: lesson 03 (Jacobian, Hessian, symmetry of second derivatives), lesson 05 (JVP, VJP, forward and reverse mode, dual numbers), lesson 06 (softmax cross-entropy) and lesson 07 (step size of finite differences). From linear algebra: lesson 06 (eigenvalues of symmetric matrices, Rayleigh quotient), lesson 07 (positive semidefinite matrices) and lesson 14 (power iteration, Lanczos, conjugate gradient). Time: about 70 minutes, plus the notebook.


    Why this matters #

    A network with n=107n = 10^7 parameters has a Hessian with n2=1014n^2 = 10^{14} entries: 800 TB in float64. You can never form it. Yet many tools need curvature:

    • Sharpness. The largest Hessian eigenvalue λmax⁡\lambda_{\max} limits the stable learning rate of gradient descent. Power iteration finds it with Hessian-vector products only.
    • Second-order training. Newton-CG and Hessian-free optimization (Martens 2010) solve Hd=−gHd = -g or Gd=−gGd = -g with conjugate gradient. CG needs only products with the matrix.
    • Influence functions and implicit gradients need H−1gH^{-1}g, again solved with products (lesson 09).
    • Laplace approximations (lesson 11) use the Gauss-Newton matrix as the posterior precision.
    • Trace estimation. Continuous normalizing flows need tr⁡(∂f/∂z)\operatorname{tr}(\partial f/\partial z); a physics-informed loss with a Laplacian needs tr⁡∇2u\operatorname{tr}\nabla^2 u. Hutchinson's estimator gives both from a few products.

    All of these work with the matrix only through products. This lesson shows how to compute the products.

    1. Predict first #

    2. The picture #

    Curvature is the rate of change of the gradient #

    In lesson 05 you met the two products that automatic differentiation gives for a map FF with Jacobian JJ: the JVP v↦Jvv \mapsto Jv (forward mode) and the VJP u↦J⊤uu \mapsto J^\top u (reverse mode). Each costs a small constant times one evaluation of FF, and neither forms JJ. This lesson applies them to one special map: the gradient.

    Start in one variable. The second derivative tells how fast the slope changes:

    f′′(x) v=ddtf′(x+tv)∣t=0.f''(x)\, v = \frac{d}{dt} f'(x + tv) \Big|_{t=0}.

    In nn variables, the gradient g(x)=∇f(x)g(x) = \nabla f(x) is itself a map from Rn\R^n to Rn\R^n. Its Jacobian is the Hessian H=∇2f(x)H = \nabla^2 f(x) (lesson 03). So walk along the line x+tvx + tv and watch the gradient arrow. The velocity of its tip at t=0t = 0 is

    Hv=ddt ∇f(x+tv)∣t=0.\htmlClass{c6}{Hv} = \frac{d}{dt}\, \htmlClass{c1}{\nabla f(x + tv)} \Big|_{t=0}.

    This is the Hessian-vector product (HVP): one column of information about HH, in the direction you choose. A central difference of two gradients approximates it: (∇f(x+ηv)−∇f(x−ηv))/(2η)\big(\nabla f(x + \eta v) - \nabla f(x - \eta v)\big)/(2\eta).

    Interactive figure: loading…

    Drag the violet point xx and the violet direction handle vv. Left: the contour lines of ff, the dashed line x+tvx + tv and the gradient arrows along it. Right: the path of the gradient's tip as tt moves. Its tangent at t=0t = 0 is the exact HvHv; the secant through the two points at t=±ηt = \pm\eta is the finite-difference estimate. Move the η\eta slider and watch the error chart: large η\eta gives truncation error, tiny η\eta gives rounding error. For the cubic preset the gradient is quadratic in tt, so the secant is exact up to rounding.

    Two ways to differentiate a gradient #

    Automatic differentiation can differentiate any program, and the gradient computation is a program. So you can run a second pass of automatic differentiation over the first one:

    • Forward-over-reverse. Run the gradient program (a forward pass and a backward pass) with dual numbers, that is, with a tangent attached to every value. The tangent of the output ∇f\nabla f is HvHv. This is a JVP of the gradient.
    • Reverse-over-reverse. Form the scalar h(x)=∇f(x)⊤vh(x) = \nabla f(x)^\top v and take its gradient with a second reverse pass. Then ∇h=Hv\nabla h = Hv. This is a VJP of the gradient.

    The figure in section 3.1 runs both on a small example, row by row.

    Gauss-Newton: keep the curvature of the loss, drop the curvature of the model #

    Many losses have the form L(θ)=ℓ(r(θ))L(\theta) = \ell(r(\theta)): a model or residual map rr followed by a simple loss ℓ\ell, for example L=12∥r(θ)∥2L = \frac12\|r(\theta)\|^2 in least squares. Replace rr by its linear approximation r(θ)+Jδr(\theta) + J\delta, where JJ is the Jacobian of rr. The model 12∥r+Jδ∥2\frac12\|r + J\delta\|^2 is a convex quadratic in the step δ\delta, with Hessian J⊤JJ^\top J. This is the Gauss-Newton matrix. The true Hessian of LL has one more term, which comes from the curvature of rr and is weighted by the residuals. That extra term can be negative. The Gauss-Newton matrix cannot.

    Interactive figure: loading…

    Move the slider θ\theta. A one-parameter model sin⁡(θt)\sin(\theta t) is fitted to 12 points. Top: the loss L(θ)L(\theta) with two quadratic models at θ\theta: the Newton model (uses the true second derivative L′′L'') and the Gauss-Newton model (uses GG). Bottom: L′′L'' == GG ++ residual term. Notice that G≥0G \ge 0 everywhere, while L′′L'' is negative between the valleys. There the Newton model opens downward and its step goes uphill. Set the noise to 0: at the best fit the residuals vanish and L′′=GL'' = G.

    A trace from random signs #

    Take a random vector zz with independent entries +1+1 or −1-1 (each with probability ½). Then

    z⊤Az=∑iAiizi2+∑i≠jAijzizj=tr⁡A+∑i≠jAijzizj,z^\top A z = \sum_i A_{ii} z_i^2 + \sum_{i \ne j} A_{ij} z_i z_j = \operatorname{tr} A + \sum_{i \ne j} A_{ij} z_i z_j ,

    because zi2=1z_i^2 = 1. Each cross term zizjz_i z_j is +1+1 or −1-1 with equal chance, so it has mean 0. The average of z⊤Azz^\top A z over many probes is therefore tr⁡A\operatorname{tr} A. Each probe needs only one product AzAz; for A=HA = H that is one HVP.

    Quick check

    f(x)=12x⊤Ax−b⊤xf(x) = \frac12 x^\top A x - b^\top x with a symmetric matrix AA. You compute the central difference (∇f(x+ηv)−∇f(x−ηv))/(2η)\big(\nabla f(x + \eta v) - \nabla f(x - \eta v)\big)/(2\eta) in exact arithmetic. How large is its error compared with HvHv?

    3. Definitions and main results #

    Notation. f:Rn→Rf: \R^n \to \R is twice continuously differentiable (C2C^2). Its gradient is the column g(x)=∇f(x)∈Rng(x) = \nabla f(x) \in \R^n and its Hessian is H=∇2f(x)∈Rn×nH = \nabla^2 f(x) \in \R^{n\times n}, with Hij=∂2f/∂xi∂xjH_{ij} = \partial^2 f/\partial x_i \partial x_j. The vector v∈Rnv \in \R^n is fixed: it does not depend on xx.

    3.1 Hessian-vector products #

    Proposition 1 (two exact HVPs). (a) ddt g(x+tv)∣t=0=Hv\displaystyle \frac{d}{dt}\, g(x + tv)\Big|_{t=0} = Hv (forward-over-reverse: a JVP of gg). (b) With h(x)=g(x)⊤vh(x) = g(x)^\top v, ∇h(x)=Hv\nabla h(x) = Hv (reverse-over-reverse: a VJP of gg).

    Proof.

    1. The Jacobian of gg is the Hessian: [Dg(x)]ij=∂jgi=∂j∂if=Hij[Dg(x)]_{ij} = \partial_j g_i = \partial_j \partial_i f = H_{ij}.
    2. (a) The derivative of t↦g(x+tv)t \mapsto g(x + tv) at t=0t = 0 is Dg(x) vDg(x)\, v (chain rule, lesson 04). By step 1 this is HvHv.
    3. (b) h(x)=v⊤g(x)h(x) = v^\top g(x) with vv constant, so ∇h(x)=Dg(x)⊤v=H⊤v\nabla h(x) = Dg(x)^\top v = H^\top v.
    4. ff is C2C^2, so HH is symmetric (Schwarz's theorem, lesson 03) and H⊤v=HvH^\top v = Hv. ■\blacksquare

    Step 4 is where the Hessian is special. For a map gg that is not a gradient, the JVP gives Dg vDg\,v and the VJP gives Dg⊤vDg^\top v, and the two differ.

    There are four ways to nest the two modes (Blondel and Roulet, §9.1):

    Method What it computes Time Memory
    forward-over-reverse JVP of the gradient program small constant × one gradient like one gradient, plus the tangents
    reverse-over-reverse gradient of h=g⊤vh = g^\top v small constant × one gradient more: it also stores the first backward pass
    reverse-over-forward gradient of x↦Df(x) vx \mapsto Df(x)\,v (the same hh) small constant × one gradient like forward-over-reverse
    forward-over-forward second-order JVPs, one per basis direction nn passes for one HvHv small

    Forward-over-reverse is the usual default (for example jax.jvp(jax.grad(f), ...)). Reverse-over-reverse is the "double backward" of PyTorch: it is available whenever the backward pass is itself differentiable.

    Interactive figure: loading…

    Step through the trace of f(x)=x13+x1x22f(x) = x_1^3 + x_1 x_2^2 at x=(1,2)x = (1, 2). Rows 1–6 are the forward pass, rows 7–12 the backward pass that computes ∇f=(xˉ1,xˉ2)\nabla f = (\bar x_1, \bar x_2). In forward-over-reverse, every row also carries a tangent (the dot). The tangents of xˉ1,xˉ2\bar x_1, \bar x_2 are HvHv. In reverse-over-reverse, a third sweep goes back up through all 12 rows and fills the second adjoints; the values at x1,x2x_1, x_2 are HvHv. Notice that this third sweep needs all 12 rows stored. Choose v=e1v = e_1 to get the first column of HH.

    Why one HVP costs a small constant times one gradient.

    1. Reverse mode gives ∇f\nabla f for a small constant times the cost of ff, independent of nn. This is the cheap gradient principle (lesson 05).
    2. The gradient computation is itself a program gg made of elementary operations. Its cost is c⋅cost⁡(f)c \cdot \operatorname{cost}(f) for a small constant cc.
    3. Forward mode on any program costs a constant factor times that program: each elementary operation gets one extra derivative operation.
    4. So the JVP of gg costs a constant times cost⁡(g)\operatorname{cost}(g): a small multiple of one gradient. In practice this is about 2 to 4 gradients. No factor nn appears.
    5. Reverse-over-reverse: h=g⊤vh = g^\top v costs cost⁡(g)+n\operatorname{cost}(g) + n, and reverse mode on hh costs a constant times that. The time is of the same order. But the second reverse sweep must also store the intermediate values of the first backward pass, so it needs more memory than forward-over-reverse.

    The finite-difference HVP. The central difference (g(x+ηv)−g(x−ηv))/(2η)\big(g(x + \eta v) - g(x - \eta v)\big)/(2\eta) costs two gradients, but it is not exact. Its truncation error is O(η2)O(\eta^2) (from third derivatives of ff) and its rounding error is O(ε/η)O(\varepsilon/\eta), where ε≈2.2×10−16\varepsilon \approx 2.2\times10^{-16} is float64 machine epsilon. As in lesson 07, the best step is about ε1/3≈6×10−6\varepsilon^{1/3} \approx 6\times10^{-6} (for a well-scaled problem) and the best relative error is about ε2/3≈4×10−11\varepsilon^{2/3} \approx 4\times10^{-11}. In float32 (ε≈1.2×10−7\varepsilon \approx 1.2\times10^{-7}) the best is only about 2×10−52\times10^{-5}.

    The full Hessian costs nn HVPs, with v=e1,…,env = e_1, \dots, e_n: the HVP with eje_j is column jj of HH. This is fine for n=103n = 10^3 and impossible for n=107n = 10^7.

    Quick check

    A model has n=106n = 10^6 parameters, and one gradient takes 1 second. About how long does it take to compute the full Hessian with exact HVPs (forward-over-reverse, about 3 gradients each)?

    3.2 The Gauss-Newton matrix #

    Let L(θ)=ℓ(r(θ))L(\theta) = \ell(r(\theta)) with a model or residual map r:Rn→Rmr: \R^n \to \R^m, its Jacobian J=Dr(θ)∈Rm×nJ = Dr(\theta) \in \R^{m\times n}, and a C2C^2 loss ℓ:Rm→R\ell: \R^m \to \R. Write rir_i for the ii-th output of rr and ∂iℓ\partial_i \ell for ∂ℓ/∂ri\partial \ell/\partial r_i.

    Proposition 2 (Hessian of a composition).

    ∇2L=J⊤ ∇2ℓ(r) J⏟Gauss-Newton term  +  ∑i=1m∂iℓ(r) ∇2ri⏟residual term.\nabla^2 L = \underbrace{J^\top\, \nabla^2 \ell(r)\, J}_{\text{Gauss-Newton term}} \;+\; \underbrace{\sum_{i=1}^m \partial_i \ell(r)\, \nabla^2 r_i}_{\text{residual term}} .

    Proof.

    1. Chain rule: ∇L=J⊤∇ℓ(r)\nabla L = J^\top \nabla \ell(r). In coordinates, ∂aL=∑i∂iℓ  ∂ari\partial_a L = \sum_i \partial_i \ell\; \partial_a r_i.
    2. Differentiate with respect to θb\theta_b with the product rule. The first factor ∂iℓ\partial_i\ell depends on θ\theta through rr, so ∂b(∂iℓ)=∑j∂ijℓ  ∂brj\partial_b(\partial_i \ell) = \sum_j \partial_{ij}\ell\; \partial_b r_j:
    ∂b∂aL=∑i,j∂ari  ∂ijℓ  ∂brj+∑i∂iℓ  ∂abri.\partial_b \partial_a L = \sum_{i,j} \partial_a r_i\; \partial_{ij} \ell\; \partial_b r_j + \sum_i \partial_i \ell\; \partial_{ab} r_i .
    1. The first sum is entry (a,b)(a, b) of J⊤∇2ℓ JJ^\top \nabla^2 \ell\, J. The second is entry (a,b)(a, b) of ∑i∂iℓ ∇2ri\sum_i \partial_i\ell\, \nabla^2 r_i. ■\blacksquare

    Definition. The (generalized) Gauss-Newton matrix is G=J⊤∇2ℓ(r) J∈Rn×nG = J^\top \nabla^2\ell(r)\, J \in \R^{n\times n}. For ℓ=12∥r∥2\ell = \frac12\|r\|^2 we have ∇2ℓ=I\nabla^2 \ell = I and G=J⊤JG = J^\top J.

    Three properties.

    1. GG is positive semidefinite when ℓ\ell is convex. For any vv, v⊤Gv=(Jv)⊤ ∇2ℓ (Jv)≥0v^\top G v = (Jv)^\top\, \nabla^2 \ell\, (Jv) \ge 0, because ∇2ℓ⪰0\nabla^2\ell \succeq 0. This holds even where ∇2L\nabla^2 L is indefinite.
    2. G=∇2LG = \nabla^2 L when the residual term vanishes: when rr is linear in θ\theta (∇2ri=0\nabla^2 r_i = 0), or when ∇ℓ(r)=0\nabla \ell(r) = 0 (for least squares: a perfect fit, r=0r = 0). Near a good fit, G≈∇2LG \approx \nabla^2 L.
    3. Matrix-free product. To compute GvGv: (i) u=Jvu = Jv, one JVP of rr; (ii) w=∇2ℓ  uw = \nabla^2 \ell\; u, which is cheap: for ℓ=12∥r∥2\ell = \frac12\|r\|^2, w=uw = u; for softmax cross-entropy with probabilities pp, w=p⊙u−p (p⊤u)w = p \odot u - p\,(p^\top u); (iii) Gv=J⊤wGv = J^\top w, one VJP of rr.

    For softmax cross-entropy, ∇z2ℓ=diag⁡(p)−pp⊤\nabla^2_z \ell = \operatorname{diag}(p) - pp^\top with respect to the logits zz (lesson 06). It is positive semidefinite: u⊤(diag⁡(p)−pp⊤)u=∑ipiui2−(∑ipiui)2u^\top(\operatorname{diag}(p) - pp^\top)u = \sum_i p_i u_i^2 - (\sum_i p_i u_i)^2 is the variance of the numbers uiu_i under the probabilities pip_i.

    The Gauss-Newton step solves Gδ=−∇LG\delta = -\nabla L. If G≻0G \succ 0 and ∇L≠0\nabla L \ne 0, then ∇L⊤δ=−δ⊤Gδ<0\nabla L^\top \delta = -\delta^\top G \delta < 0, so the step is a descent direction. The Levenberg-Marquardt method adds damping, (G+μI)δ=−∇L(G + \mu I)\delta = -\nabla L with μ>0\mu > 0, which keeps the system positive definite and shortens the step when the linear model is poor. The optimization track covers these methods in detail (optimization).

    Gauss-Newton, Fisher information and natural gradient

    Let ℓ(r)=−log⁡p(y∣r)\ell(r) = -\log p(y \mid r) be a negative log-likelihood, where the model output rr is the natural parameter of an exponential family: the logits of a softmax, or the mean of a Gaussian with fixed variance. Then ∇r2ℓ\nabla_r^2 \ell does not depend on the label yy, and GG equals the Fisher information matrix of the model (Martens 2020; Blondel and Roulet §9.3). This connects Gauss-Newton to the natural gradient and to K-FAC (Martens and Grosse 2015), which approximates GG by Kronecker factors, one pair per layer.

    Quick check

    At some θ\theta, the Hessian ∇2L\nabla^2 L of a least-squares loss L=12∥r(θ)∥2L = \frac12\|r(\theta)\|^2 has eigenvalues 9.39.3 and −3.3-3.3. What can you say about the Gauss-Newton matrix G=J⊤JG = J^\top J at the same point?

    3.3 Hutchinson's trace estimator #

    Proposition 3. Let A∈Rn×nA \in \R^{n\times n}, and let z∈Rnz \in \R^n be random with E[zz⊤]=I\mathbb E[zz^\top] = I. Then E[z⊤Az]=tr⁡A\mathbb E[z^\top A z] = \operatorname{tr} A. If AA is symmetric and zz is Rademacher (independent entries, +1+1 or −1-1 with probability ½ each), then Var⁡(z⊤Az)=2∑i≠jAij2\operatorname{Var}(z^\top A z) = 2\sum_{i \ne j} A_{ij}^2.

    Proof.

    1. A number equals its own trace, so z⊤Az=tr⁡(z⊤Az)=tr⁡(A zz⊤)z^\top A z = \operatorname{tr}(z^\top A z) = \operatorname{tr}(A\, zz^\top) (cyclic property of the trace).
    2. Trace and expectation are both linear, so E[z⊤Az]=tr⁡(A E[zz⊤])=tr⁡(A I)=tr⁡A\mathbb E[z^\top A z] = \operatorname{tr}(A\, \mathbb E[zz^\top]) = \operatorname{tr}(A\, I) = \operatorname{tr} A.
    3. For Rademacher zz, zi2=1z_i^2 = 1. With AA symmetric, z⊤Az−tr⁡A=∑i≠jAijzizj=2∑i<jAijzizjz^\top A z - \operatorname{tr} A = \sum_{i \ne j} A_{ij} z_i z_j = 2\sum_{i<j} A_{ij} z_i z_j.
    4. Each product zizjz_i z_j (i<ji < j) has mean 0 and variance 1. Two different products are uncorrelated: for example E[z1z2⋅z1z3]=E[z2] E[z3]=0\mathbb E[z_1 z_2 \cdot z_1 z_3] = \mathbb E[z_2]\,\mathbb E[z_3] = 0.
    5. The variance of a sum of uncorrelated terms is the sum of the variances: 4∑i<jAij2=2∑i≠jAij24\sum_{i<j} A_{ij}^2 = 2\sum_{i \ne j} A_{ij}^2. ■\blacksquare

    The Hutchinson estimator averages SS independent probes: tr⁡^=1S∑s=1Szs⊤Azs\widehat{\operatorname{tr}} = \frac1S \sum_{s=1}^S z_s^\top A z_s. It needs SS products AzsAz_s (for A=HA = H: SS HVPs), and its variance is the single-probe variance divided by SS. So the standard error falls like 1/S1/\sqrt S: four times more probes halve the error.

    Variance for general probes, and why Rademacher is best

    Let the entries ziz_i be independent with mean 0, variance 1 and fourth moment κ=E[zi4]\kappa = \mathbb E[z_i^4], and let AA be symmetric.

    1. Split z⊤Az=∑iAiizi2+∑i≠jAijzizjz^\top A z = \sum_i A_{ii} z_i^2 + \sum_{i\ne j} A_{ij} z_i z_j.
    2. The diagonal part has variance ∑iAii2Var⁡(zi2)=(κ−1)∑iAii2\sum_i A_{ii}^2 \operatorname{Var}(z_i^2) = (\kappa - 1)\sum_i A_{ii}^2.
    3. The off-diagonal part has variance 2∑i≠jAij22\sum_{i \ne j} A_{ij}^2, as in the proof above.
    4. The two parts are uncorrelated: E[zi2zjzk]=0\mathbb E[z_i^2 z_j z_k] = 0 for j≠kj \ne k, because zjz_j or zkz_k appears with power 1 and has mean 0.
    5. So Var⁡(z⊤Az)=2∑i≠jAij2+(κ−1)∑iAii2\operatorname{Var}(z^\top A z) = 2\sum_{i\ne j} A_{ij}^2 + (\kappa - 1)\sum_i A_{ii}^2.

    Gaussian probes have κ=3\kappa = 3, which gives 2∥A∥F22\|A\|_F^2. Rademacher probes have κ=1\kappa = 1, the smallest possible value (since E[zi4]≥(E[zi2])2=1\mathbb E[z_i^4] \ge (\mathbb E[z_i^2])^2 = 1), and they add nothing for the diagonal. For a non-symmetric AA, use its symmetric part 12(A+A⊤)\frac12(A + A^\top): it has the same quadratic form z⊤Azz^\top A z.

    Interactive figure: loading…

    Press "New probes" a few times. The lines are running averages of z⊤Azz^\top A z for a fixed 30×3030\times30 symmetric matrix: Rademacher and Gaussian probes. The dashed curves are tr⁡A±\operatorname{tr} A \pm one standard deviation from the variance formula; they shrink like 1/S1/\sqrt S. This matrix is diagonal-heavy, so the Rademacher band is narrow and the Gaussian band is wide. Switch to the off-diagonal-heavy matrix: both bands are wide and almost equal. For the diagonal matrix, every Rademacher probe gives the exact trace.

    Quick check

    A=(1221)A = \begin{pmatrix} 1 & 2 \\ 2 & 1 \end{pmatrix}. What is the variance of one Hutchinson probe z⊤Azz^\top A z with Rademacher zz?

    3.4 Algorithms that need only HvHv #

    • Largest eigenvalue (sharpness). Power iteration v←Hv/∥Hv∥v \leftarrow Hv / \|Hv\| converges to the eigenvector of the eigenvalue with the largest absolute value (linear-algebra lesson 05). The Rayleigh quotient v⊤Hvv^\top H v then estimates that eigenvalue. Near a minimum, H⪰0H \succeq 0 and this is λmax⁡\lambda_{\max}. The Lanczos method (linear-algebra lesson 14) gets several extreme eigenvalues with fewer HVPs.
    • Newton-CG. The Newton step solves Hd=−gHd = -g. Conjugate gradient solves it with one HVP per iteration, and stopping after a few iterations gives a "truncated Newton" step. CG needs a positive definite matrix, which is one reason to use GG (or G+μIG + \mu I) instead of HH.
    • Trace and diagonal. Hutchinson's estimator gives tr⁡H\operatorname{tr} H. The same probes give an estimate of the diagonal: E[z⊙Hz]=diag⁡(H)\mathbb E[z \odot Hz] = \operatorname{diag}(H) for Rademacher zz.

    Answers to section 1. (1) About 3T3T: a small constant times one gradient (in practice 2 to 4), never nTnT, by the cost argument in section 3.1. (2) No. For a squared-error loss, v⊤Gv=∥Jv∥2≥0v^\top G v = \|Jv\|^2 \ge 0 for every vv, so GG has no negative eigenvalue. The negative curvature lives in the residual term. (3) One. For a diagonal AA, z⊤Az=∑iAiizi2=tr⁡Az^\top A z = \sum_i A_{ii} z_i^2 = \operatorname{tr} A for every Rademacher probe, so the variance 2∑i≠jAij22\sum_{i\ne j}A_{ij}^2 is 0.

    4. Worked example #

    (a) An HVP both ways. f(x)=x13+x1x22f(x) = x_1^3 + x_1 x_2^2 at x=(1,2)x = (1, 2) with v=(1,1)v = (1, 1). The gradient is g(x)=(3x12+x22,  2x1x2)g(x) = (3x_1^2 + x_2^2,\; 2x_1 x_2), so g(1,2)=(7,4)g(1, 2) = (7, 4).

    • Forward-over-reverse. Move along the line: x+tv=(1+t, 2+t)x + tv = (1 + t,\, 2 + t), so the two entries of g(x+tv)g(x + tv) are 3(1+t)2+(2+t)23(1+t)^2 + (2+t)^2 and 2(1+t)(2+t)2(1+t)(2+t). Their derivatives in tt are 6(1+t)+2(2+t)6(1+t) + 2(2+t) and 2(2+t)+2(1+t)2(2+t) + 2(1+t). At t=0t = 0 this is (6+4,  4+2)=(10,6)(6 + 4,\; 4 + 2) = (10, 6).
    • Reverse-over-reverse. h(x)=g(x)⊤v=3x12+x22+2x1x2h(x) = g(x)^\top v = 3x_1^2 + x_2^2 + 2x_1x_2. Its gradient is ∇h=(6x1+2x2,  2x2+2x1)\nabla h = (6x_1 + 2x_2,\; 2x_2 + 2x_1). At (1,2)(1, 2): (6+4,  4+2)=(10,6)(6 + 4,\; 4 + 2) = (10, 6).
    • Check with the full Hessian. H=(6x12x22x22x1)=(6442)H = \begin{pmatrix} 6x_1 & 2x_2 \\ 2x_2 & 2x_1 \end{pmatrix} = \begin{pmatrix} 6 & 4 \\ 4 & 2 \end{pmatrix} and Hv=(6+4,  4+2)=(10,6)Hv = (6 + 4,\; 4 + 2) = (10, 6). ✓
    • det⁡H=12−16=−4<0\det H = 12 - 16 = -4 < 0, so the eigenvalues have opposite signs: the point is saddle-like.
    • Finite difference. gg is quadratic in tt, so the central difference (g(x+ηv)−g(x−ηv))/(2η)\big(g(x + \eta v) - g(x - \eta v)\big)/(2\eta) equals (10,6)(10, 6) for every η\eta, up to rounding.

    (b) Gauss-Newton against the Hessian. Residuals r(θ)=(θ1θ2+2,  θ1−1)r(\theta) = (\theta_1\theta_2 + 2,\; \theta_1 - 1), loss L=12∥r∥2L = \frac12\|r\|^2, at θ=(1,2)\theta = (1, 2), with v=(1,−1)v = (1, -1).

    1. r=(1⋅2+2,  1−1)=(4,0)r = (1\cdot 2 + 2,\; 1 - 1) = (4, 0), and J=(θ2θ110)=(2110)J = \begin{pmatrix} \theta_2 & \theta_1 \\ 1 & 0 \end{pmatrix} = \begin{pmatrix} 2 & 1 \\ 1 & 0 \end{pmatrix}.
    2. Matrix-free product: u=Jv=(2−1,  1)=(1,1)u = Jv = (2 - 1,\; 1) = (1, 1), then Gv=J⊤u=(2+1,  1+0)=(3,1)Gv = J^\top u = (2 + 1,\; 1 + 0) = (3, 1).
    3. The matrix itself: G=J⊤J=(5221)G = J^\top J = \begin{pmatrix} 5 & 2 \\ 2 & 1 \end{pmatrix}. Its eigenvalues are 3±22≈5.833 \pm 2\sqrt2 \approx 5.83 and 0.170.17: positive definite.
    4. Residual term: only r1r_1 is nonzero, and ∇2r1=(0110)\nabla^2 r_1 = \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix} (the second derivatives of θ1θ2\theta_1\theta_2). So the term is 4(0110)4\begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}.
    5. ∇2L=(5661)\nabla^2 L = \begin{pmatrix} 5 & 6 \\ 6 & 1 \end{pmatrix}, with eigenvalues 3±210≈9.323 \pm 2\sqrt{10} \approx 9.32 and −3.32-3.32: indefinite. Also ∇2L v=(5−6,  6−1)=(−1,5)≠Gv\nabla^2 L\, v = (5 - 6,\; 6 - 1) = (-1, 5) \ne Gv.
    6. The steps. The gradient is ∇L=J⊤r=(8,4)\nabla L = J^\top r = (8, 4). The Gauss-Newton step solves Gδ=−(8,4)G\delta = -(8, 4): δ=(0,−4)\delta = (0, -4). It lands at θ=(1,−2)\theta = (1, -2), where r=(−2+2,  0)=(0,0)r = (-2 + 2,\; 0) = (0, 0): an exact solution in one step. The Newton step −(∇2L)−1∇L≈(−0.52,−0.90)-(\nabla^2 L)^{-1}\nabla L \approx (-0.52, -0.90) also goes downhill here, but this is not guaranteed when ∇2L\nabla^2 L is indefinite.

    The large residual r1=4r_1 = 4 makes the dropped term large, so GG and ∇2L\nabla^2 L differ a lot here.

    (c) Hutchinson by hand. A=(2113)A = \begin{pmatrix} 2 & 1 \\ 1 & 3 \end{pmatrix}, tr⁡A=5\operatorname{tr} A = 5. For a Rademacher probe, z⊤Az=2z12+3z22+2z1z2=5+2z1z2z^\top A z = 2z_1^2 + 3z_2^2 + 2z_1z_2 = 5 + 2z_1z_2. The four possible probes (±1,±1)(\pm1, \pm1) give 7,3,3,77, 3, 3, 7: mean 5 and variance 4=2(12+12)4 = 2(1^2 + 1^2). Gaussian probes would give variance 2∥A∥F2=2(4+1+1+9)=302\|A\|_F^2 = 2(4 + 1 + 1 + 9) = 30.

    5. In code #

    NumPy checks the numbers of section 4. The gradients are written by hand.

    import itertools
    import numpy as np
    
    g = lambda x: np.array([3 * x[0]**2 + x[1]**2, 2 * x[0] * x[1]])   # gradient of x1^3 + x1 x2^2
    H = lambda x: np.array([[6 * x[0], 2 * x[1]], [2 * x[1], 2 * x[0]]])
    x, v = np.array([1.0, 2.0]), np.array([1.0, 1.0])
    for eta in (1e-1, 1e-5):
        print((g(x + eta * v) - g(x - eta * v)) / (2 * eta))   # [10. 6.] both times: g is quadratic
    print(H(x) @ v)                                            # [10. 6.]
    
    # Gauss-Newton product with one JVP (J @ v) and one VJP (J.T @ u)
    r = lambda th: np.array([th[0] * th[1] + 2, th[0] - 1])
    th, v = np.array([1.0, 2.0]), np.array([1.0, -1.0])
    J = np.array([[th[1], th[0]], [1.0, 0.0]])
    HL = J.T @ J + r(th)[0] * np.array([[0.0, 1.0], [1.0, 0.0]])
    print(J.T @ (J @ v), HL @ v)                               # [3. 1.] [-1. 5.]
    print(np.linalg.eigvalsh(J.T @ J), np.linalg.eigvalsh(HL)) # [0.17 5.83] [-3.32 9.32]
    print(np.linalg.solve(J.T @ J, -J.T @ r(th)))              # [0. -4.]: lands on r = 0
    
    # Hutchinson: all four Rademacher probes
    A = np.array([[2.0, 1.0], [1.0, 3.0]])
    q = [z @ A @ z for z in map(np.array, itertools.product([-1, 1], repeat=2))]
    print(q, np.mean(q), np.var(q))                            # [7, 3, 3, 7] 5.0 4.0
    

    In PyTorch, torch.func composes the two modes directly. The eager "double backward" needs create_graph=True in the first call, so that the gradient is itself recorded in a graph:

    import torch
    from torch.func import grad, jvp, vjp
    
    torch.set_default_dtype(torch.float64)
    f = lambda x: x[0]**3 + x[0] * x[1]**2
    x, v = torch.tensor([1.0, 2.0]), torch.tensor([1.0, 1.0])
    
    print(jvp(grad(f), (x,), (v,))[1])          # forward-over-reverse: tensor([10., 6.])
    print(grad(lambda x: grad(f)(x) @ v)(x))    # reverse-over-reverse: tensor([10., 6.])
    
    xr = x.clone().requires_grad_(True)         # eager double backward
    (gx,) = torch.autograd.grad(f(xr), xr, create_graph=True)
    print(torch.autograd.grad(gx @ v, xr)[0])   # tensor([10., 6.])
    
    r = lambda th: torch.stack([th[0] * th[1] + 2, th[0] - 1])
    th, v = torch.tensor([1.0, 2.0]), torch.tensor([1.0, -1.0])
    u = jvp(r, (th,), (v,))[1]                  # u = J v      -> tensor([1., 1.])
    print(vjp(r, th)[1](u)[0])                  # G v = J^T u  -> tensor([3., 1.])
    

    In JAX the same forward-over-reverse HVP is jax.jvp(jax.grad(f), (x,), (v,))[1].

    6. Where it shows up #

    • Sharpness and the edge of stability. On a quadratic, gradient descent with step η\eta is stable only if η<2/λmax⁡\eta < 2/\lambda_{\max}. Cohen et al. (2021) observed that in full-batch training the sharpness λmax⁡(∇2L)\lambda_{\max}(\nabla^2 L) rises until it reaches about 2/η2/\eta and then stays there. Such studies measure λmax⁡\lambda_{\max} with power iteration or Lanczos on HVPs; PyHessian (Yao et al. 2020) also estimates the trace with Hutchinson and the eigenvalue density with stochastic Lanczos.
    • Second-order optimization. Hessian-free optimization (Martens 2010) runs CG on damped Gauss-Newton products (G+μI)v(G + \mu I)v. K-FAC and Shampoo approximate GG or the Fisher matrix with Kronecker factors.
    • Influence functions. The effect of one training point on a prediction needs H−1∇ℓH^{-1}\nabla \ell (Koh and Liang 2017). It is computed with CG or a truncated Neumann series on HVPs.
    • Laplace approximation (lesson 11). The common "GGN Laplace" posterior uses the covariance (G+prior precision)−1(G + \text{prior precision})^{-1}, because GG is positive semidefinite and HH may not be.
    • Trace estimation in generative models. A continuous normalizing flow (FFJORD, Grathwohl et al. 2019) needs tr⁡(∂f/∂z)\operatorname{tr}(\partial f/\partial z) in its log-density ODE. Hutchinson with one VJP per probe replaces dd backward passes by one. Sliced score matching uses the same trick (generative models).
    • ML for science. In 4D-Var data assimilation for weather prediction, the "tangent-linear model" is the JVP and the "adjoint model" is the VJP of the forecast model. Incremental 4D-Var is a Gauss-Newton method, and its inner solver uses exactly J⊤(Jv)J^\top(Jv). Full-waveform inversion in seismology uses the same Gauss-Newton and truncated-Newton products. A physics-informed loss with a Laplacian needs Δu=tr⁡∇x2u\Delta u = \operatorname{tr}\nabla_x^2 u: dd HVPs for input dimension dd, or a Hutchinson estimate when dd is large (ML for science).

    7. Common mistakes #

    • Forming the full matrix. If you need HvHv, GvGv or tr⁡H\operatorname{tr} H, do not form HH, GG or JJ. Use products.
    • Letting vv depend on xx in reverse-over-reverse. If v=v(x)v = v(x) is not detached from the graph, then ∇(g⊤v)=Hv+Dv(x)⊤g\nabla(g^\top v) = Hv + Dv(x)^\top g: an extra term appears.
    • Forgetting create_graph=True in the first backward call of a double-backward HVP. Without it the first gradient is not part of any graph, and the second call raises an error ("does not require grad").
    • Treating GG as the Hessian. GG drops ∑i∂iℓ ∇2ri\sum_i \partial_i\ell\, \nabla^2 r_i. It is positive semidefinite by construction, so it cannot show negative curvature or saddle points. Far from a good fit it can be a poor model of LL.
    • Using power iteration as if it returned λmax⁡\lambda_{\max}. It returns the eigenvalue of largest absolute value. If HH has a large negative eigenvalue, that is what you get.
    • Gaussian probes by default. They add 2∑iAii22\sum_i A_{ii}^2 to the variance. Rademacher probes do not.
    • Finite-difference HVPs in float32. With ε≈1.2×10−7\varepsilon \approx 1.2\times10^{-7} the best relative error is only about 2×10−52\times10^{-5}. Use the exact autodiff HVP.

    8. Check yourself #

    1. Reverse-over-reverse computes Dg(x)⊤vDg(x)^\top v. Why does this equal the HVP, and what goes wrong for a vector field gg that is not a gradient?
      AnswerFor g=∇fg = \nabla f with f∈C2f \in C^2, Dg=∇2fDg = \nabla^2 f is symmetric (Schwarz), so Dg⊤v=Dg v=HvDg^\top v = Dg\,v = Hv. For a general gg, DgDg is not symmetric, and the VJP Dg⊤vDg^\top v differs from the JVP Dg vDg\,v.
    2. r(θ)=θ2−2r(\theta) = \theta^2 - 2 (one residual, one parameter) and L=12r2L = \frac12 r^2. Give GG and ∇2L\nabla^2 L at θ=1\theta = 1 and at θ=0.5\theta = 0.5.
      Answerr′=2θr' = 2\theta and r′′=2r'' = 2, so G=(r′)2=4θ2G = (r')^2 = 4\theta^2 and ∇2L=4θ2+r⋅2=6θ2−4\nabla^2 L = 4\theta^2 + r \cdot 2 = 6\theta^2 - 4. At θ=1\theta = 1: G=4G = 4, ∇2L=2\nabla^2 L = 2. At θ=0.5\theta = 0.5: G=1G = 1, ∇2L=−2.5\nabla^2 L = -2.5. The true curvature is negative there; GG stays positive.
    3. A=(1221)A = \begin{pmatrix} 1 & 2 \\ 2 & 1 \end{pmatrix}. What is the single-probe variance of Hutchinson's estimator with Gaussian probes? What is the standard deviation of the mean of 100 Rademacher probes?
      AnswerGaussian: 2∥A∥F2=2(1+4+4+1)=202\|A\|_F^2 = 2(1 + 4 + 4 + 1) = 20. Rademacher: 2(22+22)=162(2^2 + 2^2) = 16 per probe, so the mean of 100 probes has standard deviation 16/100=0.4\sqrt{16/100} = 0.4, around the true trace 2.
    4. For softmax cross-entropy with probabilities pp, how do you apply ∇2ℓ\nabla^2\ell to a vector uu inside a Gauss-Newton product, and why is GG positive semidefinite?
      Answer∇z2ℓ=diag⁡(p)−pp⊤\nabla^2_z \ell = \operatorname{diag}(p) - pp^\top, so w=p⊙u−p (p⊤u)w = p\odot u - p\,(p^\top u). And u⊤(diag⁡(p)−pp⊤)u=∑ipiui2−(∑ipiui)2u^\top(\operatorname{diag}(p) - pp^\top)u = \sum_i p_i u_i^2 - (\sum_i p_i u_i)^2 is the variance of the numbers uiu_i under pp, so it is ≥0\ge 0. Hence v⊤Gv=(Jv)⊤∇2ℓ (Jv)≥0v^\top G v = (Jv)^\top \nabla^2\ell\,(Jv) \ge 0.
    5. Which HVP method needs less memory, forward-over-reverse or reverse-over-reverse, and why?
      AnswerForward-over-reverse. The tangents travel with the forward and backward passes and can be freed as the passes go. Reverse-over-reverse must also store the intermediate values of the first backward pass, because the second reverse sweep visits them.
    6. You run power iteration with HVPs and get the estimate −50-50. What does this tell you about HH?
      AnswerThe eigenvalue of largest absolute value is about −50-50: HH has strong negative curvature in some direction, so the point is not a minimum. All eigenvalues lie in about [−50,50][-50, 50], so the shifted matrix H+50IH + 50I has eigenvalues ≥0\ge 0 (about). Power iteration on it finds λmax⁡+50\lambda_{\max} + 50; one HVP of H+50IH + 50I is Hv+50vHv + 50v. Lanczos gives both ends directly.
    Recall cardsAnswer in your head first, then reveal. Add the cards to your review deck to see them again just before you would forget.
    1. Write the Hessian-vector product as the derivative of the gradient.

    2. How does reverse-over-reverse compute HvHv?

    3. Why do the JVP and the VJP of the gradient give the same vector?

    4. What does one exact HVP cost, compared with one gradient?

    5. How many HVPs do you need to form the full n×nn \times n Hessian?

    6. What is the Gauss-Newton matrix of L=ℓ(r(θ))L = \ell(r(\theta))?

    7. Why is the Gauss-Newton matrix positive semidefinite?

    8. How do you compute J⊤JvJ^\top J v without forming JJ?

    9. What is Hutchinson's estimator, and why is it unbiased?

    10. Variance of one Rademacher Hutchinson probe for A=(2113)A = \begin{pmatrix} 2 & 1 \\ 1 & 3\end{pmatrix}?

    Open the review →

    9. Interview angle #

    • "How do you get the top Hessian eigenvalue of a 1B-parameter model?" Power iteration or Lanczos on HVPs. Each HVP costs a few gradients; never form HH. Power iteration returns the eigenvalue of largest absolute value.
    • "What does an HVP cost, and how is it computed?" A small constant times a gradient. Forward-over-reverse: a JVP of the gradient function. Or double backward: the gradient of ∇f⊤v\nabla f^\top v.
    • "Why is Gauss-Newton safer than Newton on a neural network?" G=J⊤∇2ℓ J⪰0G = J^\top\nabla^2\ell\,J \succeq 0 for convex ℓ\ell, so the quadratic model is convex and the step is a descent direction. ∇2L\nabla^2 L is indefinite in general.
    • "How do you get the trace of a Jacobian in a continuous normalizing flow without forming it?" Hutchinson: z⊤(∂f/∂z) zz^\top (\partial f/\partial z)\, z with one VJP per probe, Rademacher probes.
    • "When is Gauss-Newton equal to the Hessian?" When the residual term vanishes: a linear model, or zero residuals at a perfect fit.

    10. Practice #

    The notebook for this lesson runs in Colab. It uses NumPy only: a small dual-number class (from lesson 05) gives forward-over-reverse on hand-written gradients. Five exercises, each with a check cell and a folded solution:

    1. hvp_fwd_rev and hvp_fd on a logistic-regression loss; compare with the exact X⊤SXv/B+μvX^\top S X v / B + \mu v.
    2. hessian_from_hvp: build HH column by column and check that it is symmetric.
    3. gauss_newton_vp for a small exponential curve fit; compare GG with the full Hessian near and far from the fit.
    4. hutchinson_trace with Rademacher and Gaussian probes; compare the empirical variance with the formula.
    5. top_eigenvalue: power iteration with HVPs for λmax⁡\lambda_{\max} of a small MLP loss Hessian.

    11. Watch and read #

    The Hessian as the derivative of the gradient, and second derivatives as bilinear forms.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    Reverse mode by extending the computational graph: this is why you can take the gradient of a gradient.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play