demoAIOptimization
BFGS against gradient descent on the Rosenbrock valley
Both methods start at on Rosenbrock's function and use the same backtracking line search; they differ only in the direction they search along. BFGS is within of the minimum at after 35 iterations and has a zero gradient to after 36. Gradient descent takes 22,962 iterations to get within , and near the minimum it gains a factor of only 0.99919 per step, close to for the Hessian's condition number .
Open in the workbenchDownload .vivOutputs below are from the site build’s run; Run all runs it again in your browser.
Look inside this program
- Atlas
The program’s map: every function and which calls which.
There’s no recorded run of this program yet.
Rosenbrock's function
is a standard test for minimizers. Its minimum is at , at the end of a long, curved valley along the parabola . The floor of the valley is nearly flat and the walls are steep, so the downhill direction points mostly at the opposite wall, not along the valley toward the minimum.
Both methods here step from to for a direction . They choose the same way: try , and halve it until the step lowers by at least times what the slope at predicts (the Armijo condition, ). Gradient descent takes . BFGS takes , where is its running estimate of the inverse of the Hessian, the matrix of second derivatives.
The reference is a Python twin of the same algorithm
(posts/refs/bfgs-against-gradient-descent-on-rosenbrock.py, output beside it).
For comparison it also runs scipy.optimize.minimize(method="BFGS"), which
uses a different line search (one that enforces the Wolfe conditions); it
stops after 35 iterations at the same minimum.
Printed
Tests 1 of 1 pass
- f is 24.2 at the start and 0 at (1, 1), where the gradient is zero (passes)
Gradient descent
Gradient descent goes downhill, and on this function downhill is across the valley. Once it reaches the floor, each step overshoots a little onto the far wall, and the step that corrects it moves only slightly along the valley.
There is one exception here. For its first 30 iterations it zigzags on the floor near , where the floor is almost level and the downhill direction points almost straight along . At iteration 30 the line search accepts , and one step of length 1.85 carries it from to , on the floor near the other end. The valley bends, and the straight step cuts across the bend, through ground where is about 89; the Armijo test only compares where the step lands () with where it started (). No other step is longer than 0.23. After it, gradient descent is 0.16 from the minimum and needs 22,931 more iterations.
The cell runs it until it is within of , keeping every iterate for the figures.
Printed
Tests 2 of 2 pass
- the longest gradient-descent step is at iteration 30, t = 1/2 and 1.85 long, landing where the Python twin's does (passes)
- gradient descent needs 22,962 iterations to get within 1e-9, as the Python twin does (passes)
Why it is that slow
Near the minimum is close to a quadratic, with Hessian
. Its eigenvalues are
1001.6 and 0.399: the valley is 2508 times steeper across than along (kappa).
A step size small enough not to be thrown up the steep wall (it must stay under
) shrinks the error along the valley by only a factor of about
per step. The best any fixed step can do on this quadratic is to
shrink the error by per step, with
the ratio of the two eigenvalues: 0.99920. From to
gradient descent gains 0.99919 per step, within 2% of that rate in
the logarithm.
Printed
Tests 2 of 2 pass
- the Hessian at (1, 1) has eigenvalues 0.399 and 1001.6, condition number 2508 (numpy agrees) (passes)
- near the minimum gradient descent gains 0.99919 a step, within 2% of (kappa-1)/(kappa+1) in the log (passes)
BFGS
BFGS keeps a 2 by 2 matrix , starting from the identity, so its first step is a gradient step. After each step it knows two new vectors: the step and the change in gradient . For a quadratic with Hessian , . BFGS changes by the smallest amount (a rank-two update, the formula under the title) that makes the new satisfy , the one equation about the inverse Hessian this step has measured. It skips the update when , which would make lose positive definiteness.
As approaches the true inverse Hessian, approaches Newton's step, the line search accepts , and convergence becomes superlinear: the ratio of successive errors goes to zero instead of settling at a constant. Here it is 0.305 at iteration 31, between 0.013 and 0.033 for the next three, and at iteration 35. The last five errors match the Python twin's to the last bit.
Printed
Tests 4 of 4 pass
- BFGS is within 1e-9 of (1, 1) after 35 iterations and has |grad f| < 1e-12 after 36 (passes)
- the last errors are the Python twin's, bit for bit (passes)
- the error ratio falls from 0.3 to 1e-4 over the last iterations, so convergence is superlinear (passes)
- over those last iterations the line search takes the full step, t = 1 (passes)
The paths
The first figure draws both paths over three level curves of (at 1, 5, and 24.2, the level through the start) and the valley floor . Gradient descent's line shows its first 20 iterates, then every 200th: the long straight segment is the jump across the bend, and each later point stands for 200 small zigzags near . BFGS lands on the floor and follows the curve of the valley around to the minimum.
The second figure is the distance to against the iteration number, both on log axes. Gradient descent's line bends down only slowly, a constant factor per step. BFGS's plunges in its last few steps.