Checkpointing and Reverse-Mode AD

Here is the surprise ending of this course: the most abstract idea in it — Bennett's pebble game, the space–time bargain for undoing a computation — turns out to run the modern world. Every time a neural network learns, it plays Bennett's pebble game. The machinery is called reverse-mode automatic differentiation, better known as backpropagation, and its central problem is exactly the reversible-computing problem: to go backward through a computation, you need the states you passed through on the way forward.

Why going backward needs the forward states

Reverse-mode AD computes the gradient of an output with respect to every input by traversing the computation graph backwards, from output to input, applying the chain rule at each step. But the derivative of each step depends on the values that flowed through it on the forward pass. So you have two choices, and they are precisely Bennett's two choices:

In deep learning this second option is called gradient checkpointing, and it is standard practice for fitting large models into limited GPU memory.

The √n sweet spot

How many checkpoints should you keep? Suppose the forward pass has n steps and you place c evenly spaced checkpoints. Then:

The total cost c + n/c is minimised when the two terms are equal, c = n/c, i.e.

c = \sqrt{n}, \qquad \text{giving memory } O(\sqrt{n}) \text{ at about } 2\times \text{ the compute}.

This is the celebrated square-root rule: with one level of checkpointing you cut memory from O(n) to O(\sqrt{n}) for roughly a doubling of forward work. Nest the trick recursively and you reach Bennett's logarithmic regime — the adjoint-solver community calls the optimal recursive schedule REVOLVE (Griewank and Walther), and it long predates deep learning: PDE, climate and seismic adjoint methods used exactly these binomial checkpoint schedules decades earlier to differentiate through enormous time-stepped simulations.

Invertible networks: skip the storage entirely

There is a third option that is pure reversible computing: make the network invertible by design, so no forward states need storing at all — you recover them by running the layer backward. The trick is a coupling layer. Split the input into two halves x_1, x_2 and compute

y_1 = x_1 + f(x_2), \qquad y_2 = x_2 + g(y_1).

This is algebraically invertible no matter what the functions f and g are, because you can peel it apart in reverse order:

x_2 = y_2 - g(y_1), \qquad x_1 = y_1 - f(x_2).

Given the outputs you reconstruct the inputs exactly — a bijection built from arbitrary neural networks. RevNets and normalizing-flow models are built from stacks of these. Because every layer is reversible, the backward pass reconstructs each activation on the fly instead of reading it from memory: reversible computing has quietly become an architecture choice that trains huge models on modest hardware. Compare this with a standard network's training loop, which must cache every activation.

// A reversible coupling layer. f and g are arbitrary neural nets. function forward(x1: number[], x2: number[]): [number[], number[]] { const y1 = add(x1, f(x2)); const y2 = add(x2, g(y1)); return [y1, y2]; } // Its exact inverse — no stored activations needed. function inverse(y1: number[], y2: number[]): [number[], number[]] { const x2 = sub(y2, g(y1)); // undo the second line first const x1 = sub(y1, f(x2)); // then the first return [x1, x2]; }

The through-line

Everything in this lesson is the pebble game cashed out in engineering. The abstract question "how much scratch memory must I keep to be able to run this computation backward?" is answered every day by machine-learning frameworks, climate models and seismic imaging codes. Reverse-mode AD is the pebble game monetised.

Long before anyone trained a neural network, computational scientists faced the identical problem in adjoint methods: to compute how a climate or seismic-wave simulation depends on its inputs, you must run the time-stepping backward, which needs the states from the forward run — over thousands of time steps that will not fit in memory. Griewank's REVOLVE algorithm (1992) gave the provably optimal checkpoint schedule, a binomial spacing that achieves O(\log n) memory. Deep learning rediscovered a corner of this decades later and called it gradient checkpointing. The pebble game is older, and wider, than the field that made it famous.

A reversible coupling layer stores no activations, which sounds like something for nothing. It is not. You have traded memory for compute: on the backward pass you must re-evaluate f and g to reconstruct the activations you didn't store. That is the pebble game all over again — you never escape the space–time trade, you only move along its curve. Invertible networks pick the extreme "store almost nothing, recompute as needed" end; naive backprop picks the "store everything" end; gradient checkpointing sits in between. Same curve, different operating point.