7  High-Dimensional Non-Convexity: Why Gradient Descent Works Anyway

Every chapter so far has stayed in a handful of dimensions — few enough to draw a contour, watch a path cross it, point at a vector by hand. Real machine learning happens in hundreds to billions of dimensions, and low-dimensional intuition about “non-convex” actively misleads there: a 2D non-convex surface conjures bumpy egg-carton pictures full of bad local minima to get trapped in (Chapter 4’s Rastrigin). That picture turns out to be close to backwards at scale. This is the flagship module the whole repo has been building toward — optimlab.highdim.nets wraps a small neural network’s weights into an ordinary optimlab.core.Problem, so every solver from Chapters 1–4 (no new optimizer, unmodified) can train a real model with hundreds of parameters, and everything below runs on it directly.

7.1 Saddle points dominate, not bad local minima

A critical point’s local shape — minimum, maximum, or saddle — is set by its Hessian’s eigenvalue signs: all positive is a minimum, all negative a maximum, mixed is a saddle. Model “a random critical point’s Hessian” the simplest possible way, a random symmetric (GOE) matrix with no special structure assumed, and ask how likely an all-one-sign spectrum is as dimension grows (Dauphin et al. 2014; Choromanska et al. 2015):

Code
import numpy as np
from optimlab.highdim import critical_point_index_stats
from optimlab.viz import saddle_point_figure

stats = critical_point_index_stats(dims=[1, 2, 3, 4, 5, 6, 8, 10], n_samples=20000, seed=0)
for d, p_min, p_saddle in zip(stats.dims, stats.p_local_min, stats.p_saddle):
    print(f"dim={d:3d}  P(local min)={p_min:.5f}  P(saddle)={p_saddle:.5f}")

saddle_point_figure(stats).show()
dim=  1  P(local min)=0.49800  P(saddle)=0.00000
dim=  2  P(local min)=0.14930  P(saddle)=0.70055
dim=  3  P(local min)=0.02375  P(saddle)=0.95135
dim=  4  P(local min)=0.00290  P(saddle)=0.99440
dim=  5  P(local min)=0.00010  P(saddle)=0.99980
dim=  6  P(local min)=0.00000  P(saddle)=1.00000
dim=  8  P(local min)=0.00000  P(saddle)=1.00000
dim= 10  P(local min)=0.00000  P(saddle)=1.00000
Figure 7.1: P(local minimum) collapses from a coin flip at dimension 1 to indistinguishable from zero by dimension 6 (0 out of 20,000 samples). P(saddle) does the opposite. Eigenvalues of a random symmetric matrix repel each other – pinning all of them to the same sign gets exponentially unlikely as there are more of them to pin.

This is the actual reassurance behind “gradient descent works in high dimensions anyway”: the failure mode to worry about was never going to be a deep local minimum — almost every critical point a high-dimensional optimizer could get stuck at is a saddle, and a saddle has at least one downhill direction gradient descent (with enough noise or enough iterations) eventually finds.

7.2 Why high-dimensional space is geometrically weird

Two direct measurements, no citation needed for either:

Code
from optimlab.highdim import pairwise_cosine_similarities
from optimlab.viz import cosine_similarity_figure

similarities = {d: pairwise_cosine_similarities(d, n_vectors=300, seed=0) for d in [3, 20, 200]}
cosine_similarity_figure(similarities).show()
Figure 7.2: Pairwise cosine similarity of 300 random directions, three dimensions overlaid. Low dimensions spread widely toward -1/+1; by dimension 200 nearly every pair of random directions is close to exactly orthogonal – not a special construction, just that there are vastly more ways to be roughly perpendicular than roughly parallel once there are many axes to spread across.
Code
from optimlab.highdim import ball_shell_volume_fraction

for dim in [2, 3, 10, 100, 1000]:
    frac = ball_shell_volume_fraction(dim, shell_thickness=0.1)
    print(f"dim={dim:5d}  fraction of a unit ball's volume in the outer 10% shell = {frac:.4f}")
dim=    2  fraction of a unit ball's volume in the outer 10% shell = 0.1900
dim=    3  fraction of a unit ball's volume in the outer 10% shell = 0.2710
dim=   10  fraction of a unit ball's volume in the outer 10% shell = 0.6513
dim=  100  fraction of a unit ball's volume in the outer 10% shell = 1.0000
dim= 1000  fraction of a unit ball's volume in the outer 10% shell = 1.0000

By dimension 100, essentially the entire volume of a ball lives within 10% of its surface — a high-dimensional ball is nothing like the solid disk low-dimensional intuition pictures; it’s almost entirely a thin shell. Both facts are the same underlying phenomenon (a dim-ball’s volume scales as r^dim, so it concentrates wherever r is largest) and both matter for the same reason: random initializations, random projections, and random perturbations in high dimensions don’t behave the way two or three dimensions trained your intuition to expect.

7.3 A trainable network, wrapped as an ordinary Problem

Code
from optimlab.highdim import MLPShape, mlp_training_problem
from optimlab.optimizers import adam

rng = np.random.default_rng(0)
X = rng.uniform(-3, 3, size=(150, 1))
y = (np.sin(X) + 0.05 * rng.standard_normal(X.shape)).reshape(-1, 1)

shape = MLPShape(layer_sizes=[1, 24, 24, 1])
print(f"n_params = {shape.n_params}")

problem = mlp_training_problem(shape, X, y, seed=0)
print(f"initial loss: {problem.f(problem.x0):.4f}")

result = adam(problem, lr=0.01, max_iter=3000)
print(f"trained loss:  {result.f:.4f}  (injected noise variance: {0.05**2:.4f})")
n_params = 673
initial loss: 0.0597
trained loss:  0.0024  (injected noise variance: 0.0025)

optimlab.highdim.nets.MLPShape packs every layer’s weights and biases into one flat 673-entry vector; mlp_training_problem wraps the mean-squared error on that flat vector as an ordinary Problem. Chapter 1’s adam — unmodified, no special-casing for “this happens to be a neural network” anywhere — drives the loss down to essentially the noise floor. Every solver in this repo already handles hundreds of dimensions; nothing about them was secretly limited to two.

7.4 The Hessian’s eigenspectrum: a few outliers, a large bulk

Forming this network’s full 673 x 673 Hessian is still just barely feasible — useful for a ground-truth check, not the point. The actual technique (Sagun et al. 2016; Ghorbani et al. 2019) never forms it: a Hessian-vector product (jax.jvp of jax.grad, “forward-over-reverse” autodiff) costs about one extra gradient evaluation and needs no n x n matrix at all, feeding a from-scratch Lanczos algorithm that recovers the extreme eigenvalues from a Krylov subspace far smaller than the full parameter count.

Code
from optimlab.highdim import lanczos_eigenvalues
from optimlab.viz import hessian_spectrum_figure

lanczos_result = lanczos_eigenvalues(problem.f, result.x, n_iter=80, seed=0)
print(f"top 5 Ritz eigenvalues:    {np.sort(lanczos_result.ritz_values)[-5:]}")
print(f"bottom 5 Ritz eigenvalues: {np.sort(lanczos_result.ritz_values)[:5]}")

hessian_spectrum_figure(lanczos_result.ritz_values).show()
top 5 Ritz eigenvalues:    [ 0.44394536  1.67091486  2.09681834 14.87887098 18.89496607]
bottom 5 Ritz eigenvalues: [-1.30318022e-04 -1.18901907e-04 -1.10429471e-04 -1.01884767e-04
 -9.53938464e-05]
Figure 7.3: A scree plot – eigenvalues sorted descending against rank – of the trained network’s loss Hessian at its minimum. Two eigenvalues stand well clear of the rest; by rank 10 the spectrum has already fallen to a long near-zero bulk. Exactly the shape Sagun et al. and Ghorbani et al. report for real trained networks, recovered here from only 80 Hessian-vector products on a 673-parameter Hessian never explicitly formed.

tests/test_hessian_spectrum.py cross-checks this Lanczos implementation against a dense jax.hessian eigendecomposition directly (Ritz values matching the true extremes to 1e-6, and never exceeding the true spectrum’s range — the Rayleigh-quotient guarantee) before trusting it on cases where forming the dense Hessian wouldn’t be an option at all.

Sharp vs. flat minima

Keskar et al.’s “large-batch training finds sharp minima that generalize worse” finding is contested (Keskar et al. 2016) — a minimum’s sharpness isn’t even reparametrization-invariant, so “sharp” alone doesn’t cleanly predict generalization the way the original story suggested. What the top Hessian eigenvalue does reliably track is a training choice’s own bias toward sharper or flatter solutions — visible directly by comparing plain training against L2-regularized training on the identical problem:

Code
import jax.numpy as jnp
from optimlab.core import Problem
from optimlab.highdim import forward, init_params

X_j, y_j = jnp.asarray(X), jnp.asarray(y)

def mse(params):
    return jnp.mean((forward(params, shape, X_j) - y_j) ** 2)

def mse_with_l2(params, l2=0.01):
    return mse(params) + l2 * jnp.sum(params**2)

x0 = init_params(shape, seed=0)
plain_result = adam(Problem(f=mse, x0=x0), lr=0.01, max_iter=3000)
reg_result = adam(Problem(f=lambda p: mse_with_l2(p), x0=x0), lr=0.01, max_iter=3000)

# sharpness compared on the *same* (unregularized) loss for both, an apples-to-apples surface
top_eig_plain = lanczos_eigenvalues(mse, plain_result.x, n_iter=60, seed=0).ritz_values.max()
top_eig_reg = lanczos_eigenvalues(mse, reg_result.x, n_iter=60, seed=0).ritz_values.max()

print(f"plain:        mse={float(mse(plain_result.x)):.4f}  ||params||={np.linalg.norm(plain_result.x):.2f}  top eigenvalue={top_eig_plain:.2f}")
print(f"L2-regularized: mse={float(mse(reg_result.x)):.4f}  ||params||={np.linalg.norm(reg_result.x):.2f}  top eigenvalue={top_eig_reg:.2f}")
plain:        mse=0.0024  ||params||=9.13  top eigenvalue=18.89
L2-regularized: mse=0.0103  ||params||=2.35  top eigenvalue=16.23

The regularized minimum lands flatter (a smaller top eigenvalue) at a real cost in fit quality (a several-times-larger MSE here) — the honest shape of the tradeoff, not a claim that flatter always means better, and not always as dramatic a sharpness gap as this specific l2 happens to produce.

7.5 Loss-landscape visualization at scale

The network’s weight space has 673 dimensions — nothing to contour-plot directly. Slice it: pick two random directions, and look at the loss on the 2D plane they span through the trained minimum (Li et al. 2018). The one subtlety is which random directions — a naive one puts most of its “step size” wherever one layer’s weights happen to be largest, making the same numeric step look sharp in one network and flat in another for reasons that have nothing to do with the loss surface. Filter normalization fixes this by rescaling each layer’s slice of the direction to match that layer’s own weight norm:

Code
from optimlab.highdim import loss_landscape_slice
from optimlab.viz import loss_landscape_figure

loss_slice = loss_landscape_slice(problem.f, result.x, shape, span=1.0, resolution=40, seed=0)
loss_landscape_figure(loss_slice).show()
Figure 7.4: Loss on a filter-normalized 2D slice through the trained minimum (star, at the origin by construction). A clean, roughly convex-looking bowl around this particular minimum – log-scaled color since the loss climbs several orders of magnitude away from the minimum, the same compression fig-contour uses back in Chapter 1.

A cheaper diagnostic than a full 2D slice — just the loss along the straight line between two points (Goodfellow et al. 2015) — is often enough on its own to see whether two points share a basin or are separated by a real barrier, and is exactly what the next section needs.

7.6 Mode connectivity: minima joined by a path, not isolated

Train the identical architecture on the identical data from a second, independent random initialization. Two different runs, two different final parameter vectors — but do they land in the same basin, or genuinely different ones?

Code
from optimlab.highdim import bezier_curve_problem, evaluate_curve_loss, linear_interpolation_loss
from optimlab.optimizers import bfgs
from optimlab.viz import curve_comparison_figure

problem_b = mlp_training_problem(shape, X, y, seed=1)
result_b = adam(problem_b, lr=0.01, max_iter=3000)
print(f"theta_a loss: {result.f:.4f}   theta_b loss: {result_b.f:.4f}")

alphas, straight_losses = linear_interpolation_loss(problem.f, result.x, result_b.x, n_points=21)
print(f"straight-line max loss: {straight_losses.max():.4f}")

curve_problem = bezier_curve_problem(problem.f, result.x, result_b.x, n_samples=8)
curve_result = bfgs(curve_problem, max_iter=300)
ts, curve_losses = evaluate_curve_loss(problem.f, result.x, curve_result.x, result_b.x, n_points=21)
print(f"optimized-curve max loss: {curve_losses.max():.4f}")

curve_comparison_figure(
    {"straight line": (alphas, straight_losses), "optimized curve": (ts, curve_losses)},
    title="Mode connectivity: straight line vs. optimized curve",
).show()
theta_a loss: 0.0024   theta_b loss: 0.0024
straight-line max loss: 0.1239
optimized-curve max loss: 0.0027
Figure 7.5: Straight-line interpolation between two independently trained minima crosses a real loss barrier – about 50x either endpoint’s own loss at its peak. A curve chosen to minimize the average loss along it (its one free control point found by the exact same bfgs used everywhere else in this repo) instead stays close to both endpoints’ loss the entire way: no real barrier, once curves are allowed to bend around it (Garipov et al. 2018).

Both endpoints are genuine minima of the identical loss surface, found completely independently — and yet a path between them exists with almost no loss increase anywhere along it. “Two different local minima” turns out to be a much weaker separation than it sounds: they can sit on the same, gently connected low-loss manifold rather than being isolated pockets an optimizer had to get lucky to find.

7.7 Overparameterization makes training easier, not harder

A network’s neural tangent kernel — how much its own output would change in response to an infinitesimal parameter step, K = J @ J^T for the Jacobian J of outputs with respect to parameters — is, in the infinite-width limit, a fixed object independent of the random initialization draw (Jacot et al. 2018). That’s the technical ingredient behind “gradient descent provably converges” results for wide networks (Du et al. 2019): training becomes equivalent to kernel regression against an essentially-fixed kernel (“lazy training”), not the wildly nonlinear optimization the raw parameter count might suggest. Measured the direct way — how much do two independent random initializations’ empirical NTKs actually differ from each other, as width grows:

Code
from optimlab.highdim import ntk_concentration_experiment
from optimlab.viz import ntk_concentration_figure

X_ntk = rng.uniform(-1, 1, size=(20, 2))
ntk_result = ntk_concentration_experiment(widths=[4, 16, 64, 256, 1024], X=X_ntk, n_in=2, n_seed_pairs=10, seed=0)
for w, m in zip(ntk_result.widths, ntk_result.mean_relative_diff):
    print(f"width={w:5d}  mean relative NTK difference={m:.4f}")

ntk_concentration_figure(ntk_result).show()
width=    4  mean relative NTK difference=0.3384
width=   16  mean relative NTK difference=0.3336
width=   64  mean relative NTK difference=0.1929
width=  256  mean relative NTK difference=0.1048
width= 1024  mean relative NTK difference=0.0515
Figure 7.6: Mean relative difference between two independent random initializations’ empirical NTKs (shaded: +/-1 std across 10 seed pairs per width), log-x. Roughly 34% at the smallest width, falling to about 5% by width 1024 – concentrating toward the fixed, deterministic kernel the infinite-width theory predicts. The shaded band’s own width shrinking alongside the mean is the same concentration effect: not just the average difference falling, but the run-to-run variance in that difference falling too.

Wider isn’t harder to train because it’s less genuinely nonlinear near its own initialization, not despite having more parameters to search over — the opposite of what “more dimensions, more room to get lost in” would predict, and consistent with saddle points (not bad minima) being the actual obstacle this whole chapter has been pointing at.

7.8 What’s next

Every module in this repo so far has been building and verifying general-purpose machinery. Phase 7 turns outward: inverse problems (imaging, PDE-constrained inversion), control (LQR, nonlinear optimal control, MPC), and machine learning end to end — training a small network or toy transformer with this repo’s own from-scratch adam, the same one that trained every network in this chapter.

Choromanska, Anna, Yann LeCun, Gérard Ben Arous, et al. 2015. “The Loss Surfaces of Multilayer Networks.” Proceedings of the 18th International Conference on Artificial Intelligence and Statistics (AISTATS). https://proceedings.mlr.press/v38/choromanska15.pdf.
Dauphin, Yann N., Razvan Pascanu, Caglar Gulcehre, Kyunghyun Cho, Surya Ganguli, and Yoshua Bengio. 2014. “Identifying and Attacking the Saddle Point Problem in High-Dimensional Non-Convex Optimization.” Advances in Neural Information Processing Systems (NeurIPS). https://arxiv.org/abs/1406.2572.
Du, Simon S., Xiyu Zhai, Barnabas Poczos, and Aarti Singh. 2019. “Gradient Descent Provably Optimizes over-Parameterized Neural Networks.” International Conference on Learning Representations (ICLR).
Ghorbani, Behrooz, Shankar Krishnan, and Ying Xiao. 2019. “An Investigation into Neural Net Optimization via Hessian Eigenvalue Density.” International Conference on Machine Learning (ICML). https://proceedings.mlr.press/v97/ghorbani19b/ghorbani19b.pdf.
Goodfellow, Ian J., Oriol Vinyals, and Andrew M. Saxe. 2015. “Qualitatively Characterizing Neural Network Optimization Problems.” International Conference on Learning Representations (ICLR). https://arxiv.org/abs/1412.6544.
Jacot, Arthur, Franck Gabriel, and Clément Hongler. 2018. “Neural Tangent Kernel: Convergence and Generalization in Neural Networks.” Advances in Neural Information Processing Systems (NeurIPS).
Keskar, Nitish Shirish, Dheevatsa Mudigere, Jorge Nocedal, Mikhail Smelyanskiy, and Ping Tak Peter Tang. 2016. On Large-Batch Training for Deep Learning: Generalization Gap and Sharp Minima. https://arxiv.org/abs/1609.04836.
Li, Hao, Zheng Xu, Gavin Taylor, Christoph Studer, and Tom Goldstein. 2018. “Visualizing the Loss Landscape of Neural Nets.” Advances in Neural Information Processing Systems (NeurIPS). https://arxiv.org/abs/1712.09913.
Sagun, Levent, Léon Bottou, and Yann LeCun. 2016. Eigenvalues of the Hessian in Deep Learning: Singularity and Beyond. https://arxiv.org/abs/1611.07476.