Newton Step#
Gradient descent uses a first-order Taylor expansion: . The model is linear in ; the step direction is , independent of curvature.
Newton's method uses a second-order Taylor expansion:
Minimising this quadratic model in (setting derivative to zero) gives the Newton step:
The Newton step is the solution to an linear system — it incorporates both the gradient direction and the local curvature (Hessian). When , the step is guaranteed to be a descent direction.
Worked 1D example. with . The Newton step from solves , i.e., , giving . Hence — the exact minimiser in one step. For quadratic functions with , Newton converges in one iteration from any starting point.
Worked 2D example. . The Hessian is . The condition number is .
Starting from , the gradient is and GD with takes many iterations. Newton: , , so — exact in one step. Newton is scale-invariant: the Hessian automatically corrects for differing curvatures along each coordinate.
Quadratic Convergence Intuition#
Newton exhibits quadratic convergence near a minimiser: there exists a constant such that
The error squares at each iteration. If , the next iterate has error , then , and so on — doubling the number of correct digits per step. Gradient descent, by contrast, is linear: with , gaining a fixed number of digits per step.
Requirements for quadratic convergence:
- is Lipschitz continuous near
- (the optimum is non-degenerate)
- The initial point is "close enough" to
The last condition is the catch. Far from the optimum, the Hessian may be indefinite or poorly conditioned, and the pure Newton step can increase the objective. This is why damping and line search are essential in practice.
Damping and Line Search#
Damped Newton modifies the pure step with a line search:
where is chosen via backtracking to satisfy the Armijo condition:
with . When , , so the directional derivative is negative — a descent direction exists, and backtracking finds a stepsize. When close to , is accepted (full Newton step), and the quadratic convergence kicks in.
When the Hessian is not PD. If has negative or zero eigenvalues, the Newton direction may point uphill. Practical Newton solvers modify the Hessian:
- Add a multiple of identity: (Levenberg–Marquardt).
- Use a modified Cholesky that perturbs negative eigenvalues to positive.
- Fall back to gradient descent when the Newton decrement is too large.
BFGS and L-BFGS#
The Hessian is expensive: storing entries and solving an linear system costs per iteration. Quasi-Newton methods avoid the Hessian entirely, building an approximation from gradient changes observed during optimisation.
BFGSBroyden–Fletcher–Goldfarb–Shanno (quasi-Newton) update. Given (step) and (gradient change), the BFGS formula updates the inverse Hessian approximation :
This is a rank-2 update — computationally cheap (). The direction is . BFGS preserves positive definiteness of when (the curvature condition), which holds under convexity or with a suitable line search.
L-BFGS (Limited-memory BFGS). Storing the matrix is still too expensive for large . L-BFGS stores only the last pairs (typically –), and computes implicitly via a two-loop recursion in time and memory. For (a large deep net), pairs cost doubles (~800 MB) — manageable; is not.
vs Adam#
| Property | Newton / L-BFGS | AdamAdaptive Moment Estimation (optimizer) | |---|---|---| | Uses curvature | Full or approximated Hessian | Diagonal (element-wise) second-moment estimate | | Per-iteration cost | (BFGS) or (L-BFGS) | | | Convergence near optimum | Quadratic (Newton) or superlinear (BFGS) | Linear (no acceleration without momentum tuning) | | Works well when | (Newton) or (L-BFGS), accurate gradients | is huge, gradients are stochastic, nonconvex | | Sensitive to | Ill-conditioning, nondifferentiability | Learning rate, |
In practice, L-BFGS is competitive with Adam for moderate-scale problems where gradients are computed accurately (full batch or large minibatch). Deep nets with stochastic gradients and still favour AdamAdaptive Moment Estimation (optimizer) or SGDStochastic Gradient Descent with momentum because L-BFGS's curvature approximation degrades under gradient noise. However, for scientific computing, logistic regression, and moderate-scale ML, L-BFGS is often the faster and more reliable choice.
For $f(x) = \tfrac{1}{2}a x^2$ with $a > 0$, one Newton step from $x_0 = b$ gives $x_1 = ____$.
The Newton step solves the linear system $ abla^2 f(x) , Delta x = - abla f(x)$. When $ abla^2 f(x) succ 0$, the direction is guaranteed to be a ____ direction.
Browser lab#
Compare Newton's method vs gradient descent on a well-conditioned quadratic () and an ill-conditioned one (). Count iterations to reach a tolerance.
import numpy as np
import matplotlib.pyplot as plt
def newton_quadratic(Q, x0, tol=1e-8, max_iter=50):
"""Newton on f(x) = 0.5 * x^T Q x."""
x = x0.copy().astype(float)
path = [x.copy()]
for _ in range(max_iter):
g = Q @ x
if np.linalg.norm(g) < tol:
break
dx = np.linalg.solve(Q, -g)
x = x + dx
path.append(x.copy())
return np.array(path)
def gd_quadratic(Q, x0, eta, tol=1e-8, max_iter=500):
"""Gradient descent on f(x) = 0.5 * x^T Q x."""
x = x0.copy().astype(float)
path = [x.copy()]
for _ in range(max_iter):
g = Q @ x
if np.linalg.norm(g) < tol:
break
x = x - eta * g
path.append(x.copy())
return np.array(path)
# Well-conditioned: Q1 = diag(1, 1)
Q1 = np.diag([1.0, 1.0])
# Ill-conditioned: Q2 = diag(1, 100)
Q2 = np.diag([1.0, 100.0])
x0 = np.array([10.0, 1.0])
# Newton
path_n1 = newton_quadratic(Q1, x0)
path_n2 = newton_quadratic(Q2, x0)
# GD with optimal step size for quadratics
eta1 = 2.0 / (1.0 + 1.0) # 2/(L+mu)
eta2 = 2.0 / (1.0 + 100.0)
path_g1 = gd_quadratic(Q1, x0, eta1)
path_g2 = gd_quadratic(Q2, x0, eta2)
print(f"Well-conditioned: Newton {len(path_n1)-1} iters, GD {len(path_g1)-1} iters")
print(f"Ill-conditioned: Newton {len(path_n2)-1} iters, GD {len(path_g2)-1} iters")
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
def plot_path(ax, paths, labels, colors, title):
for path, lbl, clr in zip(paths, labels, colors):
ax.plot(path[:, 0], path[:, 1], f"{clr}o-", markersize=3, linewidth=1, label=lbl)
ax.plot(0, 0, "kx", markersize=10)
ax.set_xlabel("x1")
ax.set_ylabel("x2")
ax.set_title(title)
ax.legend()
ax.set_aspect("equal")
plot_path(ax1, [path_n1, path_g1], [f"Newton ({len(path_n1)-1})", f"GD ({len(path_g1)-1})"],
["b", "r"], "Well-conditioned: $Q = \mathrm{diag}(1,1)$")
plot_path(ax2, [path_n2, path_g2], [f"Newton ({len(path_n2)-1})", f"GD ({len(path_g2)-1})"],
["b", "r"], "Ill-conditioned: $Q = \mathrm{diag}(1,100)$")
plt.tight_layout()
plt.show()