AI-310 · Lesson 4 of 12 · 31 min

Newton, quasi-Newton and second-order methods

Gradient descent uses only the slope of the objective, so on ill-conditioned problems it zigzags and needs thousands of steps (Lesson 1). Second-order methods also use curvature, the Hessian or an approximation to it, to take steps scaled to the shape of the objective. Newton's method converges in a handful of iterations near a solution; quasi-Newton methods such as BFGS and L-BFGS approach that speed using only gradients; Gauss-Newton and Levenberg-Marquardt exploit the structure of least-squares problems; and for large models, Hessian-vector products and structured approximations such as K-FAC and Shampoo bring curvature information within reach. This lesson explains these methods, why they are fast, what they cost, and where each is used in machine learning.

Newton's method

Newton's method minimizes the local quadratic model of \(f\) at each step:

\[f(x + p) \approx f(x) + \nabla f(x)^T p + \tfrac{1}{2} p^T \nabla^2 f(x)\, p \quad\Longrightarrow\quad p = -\left[\nabla^2 f(x)\right]^{-1}\nabla f(x)\]

On a quadratic it reaches the minimum in one step, whatever the conditioning, because the Hessian exactly undoes the different curvatures in different directions. On a general smooth, strongly convex function, it converges quadratically once close to the solution: the number of correct digits roughly doubles each iteration.

Newton's method and gradient descent on a badly scaled logistic regression: Newton reaches machine precision in seven steps, with the error squaring near the end; gradient descent needs thousands.
import numpy as np

rng = np.random.default_rng(2)
n, d = 1000, 20
X = rng.normal(size=(n, d)) * np.linspace(0.3, 3.0, d)       # badly scaled features
w_true = rng.normal(size=d)
y = (rng.random(n) < 1 / (1 + np.exp(-X @ w_true))).astype(float)
lam = 1e-3

def loss_grad_hess(w):
    z = X @ w
    p = 1 / (1 + np.exp(-z))
    loss = np.mean(np.logaddexp(0, z) - y * z) + lam / 2 * w @ w
    grad = X.T @ (p - y) / n + lam * w
    hess = (X.T * (p * (1 - p))) @ X / n + lam * np.eye(d)
    return loss, grad, hess

# Reference optimum from many Newton steps
w_star = np.zeros(d)
for _ in range(50):
    _, g, H = loss_grad_hess(w_star)
    w_star -= np.linalg.solve(H, g)
f_star = loss_grad_hess(w_star)[0]

# Newton method
w = np.zeros(d)
print("Newton")
for k in range(1, 8):
    _, g, H = loss_grad_hess(w)
    w = w - np.linalg.solve(H, g)
    print(f"  step {k}: f - f* = {loss_grad_hess(w)[0] - f_star:.2e}")

# Gradient descent with step 1/L
L = np.linalg.eigvalsh(X.T @ X / n).max() / 4 + lam
w = np.zeros(d)
for k in range(1, 5001):
    w -= loss_grad_hess(w)[1] / L
    if k in (10, 100, 1000, 5000):
        print(f"gradient descent step {k:5d}: f - f* = {loss_grad_hess(w)[0] - f_star:.2e}")
Output
Newton
  step 1: f - f* = 1.69e-01
  step 2: f - f* = 6.94e-02
  step 3: f - f* = 2.28e-02
  step 4: f - f* = 4.36e-03
  step 5: f - f* = 2.58e-04
  step 6: f - f* = 1.23e-06
  step 7: f - f* = 3.15e-11
gradient descent step    10: f - f* = 8.86e-02
gradient descent step   100: f - f* = 8.81e-03
gradient descent step  1000: f - f* = 8.51e-06
gradient descent step  5000: f - f* = 3.09e-14

The output shows the two phases of Newton's method: a few damped-looking steps far from the solution, then quadratic convergence, with the error falling from \(10^{-4}\) to \(10^{-6}\) to \(10^{-11}\). Gradient descent makes steady linear progress, at a rate set by the condition number.

Making Newton robust

Pure Newton steps can fail far from a solution: if the Hessian is not positive definite (non-convex regions), the step may point uphill; if the quadratic model is poor, the step may overshoot. Practical implementations add:

  • A line search on the Newton direction (damped Newton), accepting a step size \(t \le 1\) that decreases \(f\) sufficiently.
  • Hessian modification: adding \(\lambda I\) to make it positive definite, or using a trust region that limits the step to where the model is trusted.

The cost

Each Newton step needs the Hessian (\(d^2\) entries) and a linear solve (about \(d^3/3\) operations by Cholesky factorization). For a logistic regression with a few thousand features this is cheap; for a neural network with \(10^9\) parameters, the Hessian alone would need \(10^{18}\) entries. Second-order methods for large problems must avoid forming the Hessian.

Worked problem

Is Newton worth it?

A problem has d = 2,000 parameters and n = 100,000 examples. A gradient costs about \(nd = 2 \times 10^8\) operations; forming the Hessian costs about \(nd^2 = 4 \times 10^{11}\) and solving costs \(d^3/3 = 2.7 \times 10^9\). If Newton needs 8 iterations and gradient descent 3,000, which is cheaper?

Show solution
  1. Newton: \(8 \times (4 \times 10^{11} + 2.7 \times 10^9 + 2 \times 10^8) \approx 3.2 \times 10^{12}\).
  2. Gradient descent: \(3{,}000 \times 2 \times 10^8 = 6 \times 10^{11}\).

Answer: Gradient descent is about five times cheaper here, despite needing 375 times more iterations, because forming the Hessian dominates. Quasi-Newton methods, which avoid the Hessian, combine the strengths of both.

Quasi-Newton methods: BFGS and L-BFGS

Quasi-Newton methods build an approximation to the inverse Hessian from the gradients they have already computed. After each step \(s_k = x_{k+1} - x_k\) with gradient change \(y_k = \nabla f_{k+1} - \nabla f_k\), they update the approximation \(H_k\) so that it satisfies the secant condition \(H_{k+1}y_k = s_k\): it maps the observed change in gradient to the observed step, as the true inverse Hessian would for a quadratic. The BFGS update (Broyden, Fletcher, Goldfarb, Shanno) does this while keeping \(H\) symmetric and positive definite:

\[H_{k+1} = (I - \rho_k s_k y_k^T)\,H_k\,(I - \rho_k y_k s_k^T) + \rho_k s_k s_k^T, \qquad \rho_k = \frac{1}{y_k^T s_k}\]

BFGS converges superlinearly near a solution, needing only gradients, but stores a dense \(d \times d\) matrix. Limited-memory BFGS (L-BFGS) stores only the last \(m\) pairs \((s_k, y_k)\), typically 5 to 20, and applies the approximate inverse Hessian with a two-loop recursion in \(O(md)\) operations. L-BFGS is the standard choice for smooth, deterministic problems of moderate to large size: logistic regression with many features, conditional random fields, physics-informed fitting, and the final refinement of some scientific models.

Conjugate gradient, L-BFGS and BFGS on the 50-dimensional Rosenbrock function, and Levenberg-Marquardt fitting a decaying exponential in a few function evaluations.
import numpy as np
from scipy.optimize import minimize, least_squares

# Quasi-Newton: L-BFGS needs only gradients, and few of them, on the Rosenbrock function
def rosen(x):
    return np.sum(100 * (x[1:] - x[:-1] ** 2) ** 2 + (1 - x[:-1]) ** 2)

def rosen_grad(x):
    g = np.zeros_like(x)
    g[:-1] = -400 * x[:-1] * (x[1:] - x[:-1] ** 2) - 2 * (1 - x[:-1])
    g[1:] += 200 * (x[1:] - x[:-1] ** 2)
    return g

x0 = np.full(50, -1.2)
for method in ("CG", "L-BFGS-B", "BFGS"):
    r = minimize(rosen, x0, jac=rosen_grad, method=method, options={"maxiter": 20000, "gtol": 1e-8})
    print(f"{method:9s}: iterations {r.nit:5d}, gradient evaluations {r.njev:5d}, f = {r.fun:.1e}")

# Gauss-Newton / Levenberg-Marquardt for nonlinear least squares: fit y = a exp(-b t) + c
rng = np.random.default_rng(4)
t = np.linspace(0, 10, 60)
y = 4.0 * np.exp(-0.7 * t) + 0.5 + rng.normal(0, 0.05, t.size)
def residuals(p):
    a, b, c = p
    return a * np.exp(-b * t) + c - y
fit = least_squares(residuals, x0=[1.0, 0.1, 0.0], method="lm")
print(f"Levenberg-Marquardt: a, b, c = {np.round(fit.x, 3)} after {fit.nfev} function evaluations")
Output
CG       : iterations   374, gradient evaluations   625, f = 8.9e-17
L-BFGS-B : iterations   267, gradient evaluations   320, f = 9.6e-10
BFGS     : iterations   336, gradient evaluations   383, f = 1.3e-19
Levenberg-Marquardt: a, b, c = [4.004 0.7   0.495] after 8 function evaluations

Quasi-Newton methods need accurate gradients. With the noisy minibatch gradients of deep learning, the secant pairs are dominated by noise and the curvature estimates become unreliable, which is one reason deep networks are trained with first-order methods such as Adam (Lesson 5) rather than L-BFGS, although full-batch L-BFGS works well for small networks and for fine-tuning in some scientific applications.

Nonlinear least squares: Gauss-Newton and Levenberg-Marquardt

Many fitting problems minimize a sum of squared residuals \(f(x) = \frac{1}{2}\sum_i r_i(x)^2 = \frac{1}{2}\|r(x)\|^2\). The Hessian is \(J^TJ + \sum_i r_i\nabla^2 r_i\), where \(J\) is the Jacobian of the residuals. Near a good fit the residuals are small, so the second term can be dropped, giving the Gauss-Newton step:

\[(J^TJ)\,p = -J^T r\]

which needs only first derivatives of the residuals. Levenberg-Marquardt adds a damping term, \((J^TJ + \lambda I)p = -J^Tr\), increasing \(\lambda\) when a step fails (moving toward gradient descent) and decreasing it when steps succeed (moving toward Gauss-Newton). It is the standard method for curve fitting, camera calibration, bundle adjustment in computer vision (AI-350), and parameter estimation in engineering models.

Worked problem

One Gauss-Newton step

Fit \(y = e^{bt}\) to two points \((t, y) = (1, 2)\) and \((2, 4)\), starting from \(b = 0.5\). Compute one Gauss-Newton step.

Show solution
  1. Residuals \(r_i = e^{bt_i} - y_i\): \(e^{0.5} - 2 = -0.351\), \(e^{1} - 4 = -1.282\).
  2. Jacobian \(J_i = t_i e^{bt_i}\): \(1.649\), \(5.437\).
  3. \(J^TJ = 1.649^2 + 5.437^2 = 32.28\); \(J^Tr = 1.649(-0.351) + 5.437(-1.282) = -7.549\).
  4. Step: \(p = 7.549/32.28 = 0.234\); new \(b = 0.734\).

Answer: b moves from 0.5 to 0.734; the exact least-squares answer is close to \(\ln 2 = 0.693\), and a second step lands within about 0.003 of it. Each step needed only the residuals and their first derivatives.

Curvature without the Hessian

For large models, Newton-type methods work with Hessian-vector products \(\nabla^2 f(x)\,v\), which cost about as much as one or two gradient evaluations: by automatic differentiation (Lesson 6, the "Pearlmutter trick"), or by finite differences of gradients. With them:

  • Newton-CG (truncated Newton) solves the Newton system approximately with the conjugate gradient method, using only Hessian-vector products, and stops early.
  • Power iteration or the Lanczos method estimates the largest Hessian eigenvalues, used to monitor sharpness during training (Lesson 9).
A Newton step for a 300-parameter logistic regression computed by conjugate gradient using only finite-difference Hessian-vector products, matching the exact step, and the impossible memory cost of a full Hessian at the scale of large models.
import numpy as np

# Newton-CG: solve H p = -g using only Hessian-vector products, never forming H
rng = np.random.default_rng(5)
n, d = 2000, 300
X = rng.normal(size=(n, d)) / np.sqrt(d)
y = (rng.random(n) < 0.5).astype(float)
lam = 1e-2
w = rng.normal(size=d) * 0.1

def grad(w):
    p = 1 / (1 + np.exp(-X @ w))
    return X.T @ (p - y) / n + lam * w

def hvp(w, v, eps=1e-5):
    # finite-difference Hessian-vector product: two gradient evaluations
    return (grad(w + eps * v) - grad(w - eps * v)) / (2 * eps)

def conjugate_gradient(Av, b, iters=50, tol=1e-10):
    x = np.zeros_like(b); r = b.copy(); p = r.copy(); rs = r @ r
    for k in range(iters):
        Ap = Av(p)
        alpha = rs / (p @ Ap)
        x += alpha * p; r -= alpha * Ap
        rs_new = r @ r
        if np.sqrt(rs_new) < tol:
            return x, k + 1
        p = r + rs_new / rs * p; rs = rs_new
    return x, iters

g = grad(w)
step, k = conjugate_gradient(lambda v: hvp(w, v), -g)
p = 1 / (1 + np.exp(-X @ w))
H = (X.T * (p * (1 - p))) @ X / n + lam * np.eye(d)
exact = np.linalg.solve(H, -g)
print(f"CG used {k} Hessian-vector products; relative difference from exact Newton step {np.linalg.norm(step - exact) / np.linalg.norm(exact):.1e}")
print(f"full Hessian for d = {d}: {d * d * 8 / 1e6:.2f} MB; for d = 1e9 parameters it would need {1e18 * 2 / 1e18:.0f} EB at 16-bit")
Output
CG used 6 Hessian-vector products; relative difference from exact Newton step 7.0e-09
full Hessian for d = 300: 0.72 MB; for d = 1e9 parameters it would need 2 EB at 16-bit

Structured approximations for deep learning

Several methods approximate curvature with structures that are cheap to store and invert:

  • Diagonal approximations: Adam and RMSProp (Lesson 5) can be viewed as using a diagonal preconditioner built from squared gradients.
  • Natural gradient methods precondition with the Fisher information matrix, which for many losses equals the Gauss-Newton matrix; they make steps invariant to how the model is parameterized.
  • K-FAC (Kronecker-factored approximate curvature) approximates each layer's Fisher block as a Kronecker product of two small matrices, one from the layer's inputs and one from its output gradients, which can be inverted cheaply.
  • Shampoo and its successors keep a preconditioner for each dimension of each weight matrix (left and right factors) and apply their inverse roots. Variants have won optimizer benchmarks for training neural networks, with a modest extra cost per step that is repaid by fewer steps.

These methods occupy a middle ground: more expensive per step than Adam, far cheaper than Newton, and often faster in wall-clock time for large models when implemented efficiently and distributed across devices.

Worked problem

K-FAC memory

A fully connected layer has 4,096 inputs and 4,096 outputs. Compare the memory of its full curvature block with the K-FAC factors, in 32-bit numbers.

Show solution
  1. Parameters: \(4{,}096^2 = 1.68 \times 10^{7}\).
  2. Full block: \((1.68 \times 10^{7})^2 = 2.8 \times 10^{14}\) entries, about 1.1 PB.
  3. K-FAC: two \(4{,}096 \times 4{,}096\) factors, \(2 \times 1.68 \times 10^{7} = 3.4 \times 10^{7}\) entries, about 134 MB.

Answer: About 1.1 PB against 134 MB: the Kronecker structure reduces memory by a factor of millions, at the cost of an approximation that assumes inputs and output gradients are independent.

Choosing a method

  • Small or medium smooth problems with exact gradients: Newton (with line search) or L-BFGS.
  • Nonlinear least squares: Levenberg-Marquardt or trust-region Gauss-Newton.
  • Large convex problems with structure (sparsity, constraints): proximal and first-order methods (Lesson 7), possibly with L-BFGS for smooth parts.
  • Deep networks with minibatch gradients: Adam-family methods (Lesson 5) by default; structured second-order methods such as Shampoo when the infrastructure supports them.

Common mistakes

  • MistakeTaking full Newton steps far from the solution.

    InsteadUse a line search or trust region, and modify an indefinite Hessian.

  • MistakeForming and inverting the Hessian for large problems.

    InsteadUse L-BFGS, Hessian-vector products with CG, or structured approximations.

  • MistakeRunning L-BFGS on noisy minibatch gradients.

    InsteadUse full or large batches with L-BFGS, or first-order stochastic methods.

  • MistakeUsing general-purpose methods for least-squares fitting.

    InsteadExploit the structure with Gauss-Newton or Levenberg-Marquardt.

  • MistakeJudging methods by iteration count alone.

    InsteadCompare total cost: iterations times cost per iteration.

Summary and key terms

  • Newton's method minimizes the local quadratic model and converges quadratically near a solution.
  • Line searches, Hessian modification and trust regions make Newton robust.
  • BFGS and L-BFGS approximate the inverse Hessian from gradient differences; L-BFGS scales to large d.
  • Gauss-Newton and Levenberg-Marquardt exploit least-squares structure using only Jacobians.
  • Hessian-vector products enable Newton-CG and curvature estimates without forming H.
  • Natural gradient, K-FAC and Shampoo use structured curvature for deep networks.
Newton's method
Steps p = −H⁻¹g using the Hessian H.
Quadratic convergence
Error roughly squared at each iteration near the solution.
Trust region
A region within which the quadratic model is trusted.
Secant condition
H_{k+1} y_k = s_k for quasi-Newton updates.
BFGS
A quasi-Newton update keeping a positive definite inverse-Hessian approximation.
L-BFGS
Limited-memory BFGS storing only recent step and gradient pairs.
Gauss-Newton
A least-squares method approximating the Hessian by JᵀJ.
Levenberg-Marquardt
Gauss-Newton with adaptive damping.
Hessian-vector product
The product of the Hessian with a vector, computed without forming H.
K-FAC
Kronecker-factored approximate curvature for neural networks.

Practice problems

Work each problem on paper first, then reveal the answer to check.

  1. How many Newton steps minimize a strictly convex quadratic?

    Show answer

    One.

  2. Errors 10⁻², 10⁻⁴, 10⁻⁸ suggest which convergence?

    Show answer

    Quadratic.

  3. Newton step for f(x) = x² − 4x from x = 0?

    Show answer

    p = −(−4)/2 = 2, reaching x = 2.

  4. Memory of a dense BFGS matrix for d = 100,000 in 64-bit?

    Show answer

    80 GB.

  5. Memory of L-BFGS with m = 10 for d = 100,000?

    Show answer

    2 × 10 × 100,000 × 8 B = 16 MB.

  6. What does the secant condition require?

    Show answer

    H_{k+1} y_k = s_k.

  7. Why is L-BFGS rarely used with minibatches?

    Show answer

    Noisy gradients corrupt curvature pairs.

  8. What does Levenberg-Marquardt do when a step fails?

    Show answer

    Increases damping λ, moving toward gradient descent.

  9. Cost of a Hessian-vector product compared with a gradient?

    Show answer

    About one or two gradient evaluations.

  10. K-FAC factors for a 1,000 × 1,000 layer in 32-bit?

    Show answer

    2 × 10⁶ entries, 8 MB.

Lesson quiz · 5 questions

Score 60% or more to complete this lesson.

Take the quiz