Activation stashing and rematerialization
Treat saved forward state as identity-bearing data and account for recomputation, randomness, and side effects.
On this page
The question for today
What you’ll understand
- Count bytes from overlapping activation lifetimes rather than batch count alone.
- Explain what checkpoint inputs preserve and what backward recomputes.
- Test RNG and mutable-state behavior when rematerializing forward work.
Backward needs information from the corresponding forward computation. A pipeline can retain that state or retain enough inputs to reconstruct selected intermediates later. Rematerialization trades memory for compute, but it is correct only when the replayed computation has the required mathematical and state behavior. This lesson connects GPipe’s activation recomputation with PyTorch 2.8 checkpoint semantics, including the distinction between reentrant and nonreentrant execution.
A saved tensor belongs to one forward execution
Index saved state by stage, microbatch, and relevant parameter version. Even equal-shaped tensors are not interchangeable when they arose from different data or weights. A reusable buffer must remain owned until its backward and any communication readers finish. Pipeline scheduling changes how many bundles overlap; checkpointing changes what each bundle contains. These are separate optimization dimensions. A lower theoretical bundle count does not prove an actual memory reduction if the implementation keeps duplicate references or additional communication storage alive.
Estimate the saved-state peak from a lifetime trace rather than summing every tensor ever allocated. Include metadata and any live checkpoint inputs, then distinguish those bytes from weights, optimizer state, temporary workspace, and allocator reserve. A checkpointed region can still retain its input and outputs needed elsewhere, so its storage is not generally zero. Select regions according to the actual graph and backward requirements. Tensors needed by noncheckpointed branches can remain live even if the region itself does not save their intermediates.
Replay must preserve the required computation
Recomputing a forward region during backward must reproduce the state needed for the intended gradient. Dropout requires appropriate random-state handling; mutable counters, batch-normalization running statistics, external logging, and other side effects can execute differently or twice. A global variable changed between forward and recomputation can silently alter the function. Holding the correct parameter version is also necessary. Do not assume that using the same input shape or calling a checkpoint API proves numeric equivalence to the original execution.
PyTorch 2.8 recommends explicitly selecting the checkpoint implementation. Its nonreentrant variant can stop recomputation once needed values are rebuilt, while the reentrant variant reruns the whole function. Default RNG preservation covers CPU and a selected device type under documented rules; moving tensors to a new device inside the function can defeat the assumed coverage. The default nonreentrant determinism check compares metadata such as shapes, dtypes, and devices rather than proving equality of tensor values. Verify gradients and mutable state separately.
Measure both the storage and the extra work
Compare checkpointed and uncheckpointed runs at the same model, data, precision, update boundary, and intended random behavior. Report retained-state bytes and observed peak allocation with their definitions, plus recomputation work and end-to-end time. A memory saving can enable a larger feasible microbatch and thereby improve throughput despite extra arithmetic. Conversely, a region with little saved state and expensive replay can be a poor choice. The decision depends on which constraint limits the complete training configuration.
The cache lab demonstrates only working-set capacity. Reset, set capacity to 4 and stride to 4, predict hits after seventeen requests, then Step once: thirteen hits. Compare a fresh Reset with both capacity at 2 and stride at 4 before Step: zero hits. The exact toy LRU stream starts empty with sixteen requests already counted. It does not rematerialize activations, preserve RNG state, trace autograd, or represent the lifetimes of saved tensors in a real pipeline.
Work it through
Trade bundle bytes for declared replay work
A stage retains three outstanding microbatches. Full saved state costs 48 MiB per bundle, while a checkpoint policy retains 12 MiB per bundle. Across an iteration of six microbatches, assume replay adds two milliseconds of stage computation per microbatch. Ignore other memory and timing effects.
Full retention costs 3 × 48 = 144 MiB at the stated peak. Checkpoint retention costs 3 × 12 = 36 MiB.
The retained-state saving is 108 MiB, or 75% of this specific memory component. Other live storage and allocator reserve are outside that percentage.
Added stage computation is 6 × 2 = 12 milliseconds. That is extra work, not necessarily twelve additional milliseconds of iteration time; the full dependency schedule determines exposure.
The checkpoint policy has a precise storage benefit and an explicit compute cost, subject to replay correctness and the chosen lifetime model.
The living notebook
Explore the model
Interactive lab · cache
Capacity pressure without an autograd simulation
Reset, set C = 4 and s = 4, predict seventeen-request hits, then Step once: thirteen. Compare a fresh Reset with both C = 2 and s = 4 before Step: zero. This fixed sixteen-address LRU stream does not model saved activations, checkpoint replay, RNG, or gradient correctness.
- Hits / requests
- 0 / 16
- Hit rate
- 0%
- Address-stream period
- 16 addresses
A fully associative LRU cache starts empty and requests address (i·s) mod 16. Hits move an address to the newest position; misses evict the oldest when full. Playback starts with 16 requests and adds two per second, capped at 4096 explicitly simulated requests. This toy stream is not a processor-cache benchmark. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forCapacity and reuse interact, but activation storage must be derived from actual forward/backward lifetimes.
Pause & reason
Check your understanding
Your turn
Try it yourself
Four bundles each shrink from 40 MiB to 10 MiB under a declared checkpoint policy. Replay adds half a millisecond for each of four microbatches. Calculate retained-state savings and extra compute work, then identify one correctness check.
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Compare the same four overlapping bundles; do not convert added work directly into wall-clock time.
Compare with the solution
Retention falls from 160 MiB to 40 MiB, saving 120 MiB. Extra stage compute work is 4 × 0.5 = two milliseconds. Check gradients and required mutable-state behavior against the noncheckpointed reference, including randomness and parameter versions. The replay work may have a different effect on iteration time depending on critical paths, and the saved-state reduction does not include every process allocation.
Keep the idea
Take it with you
- Scheduling determines overlapping lifetimes, while checkpoint policy determines bytes retained per lifetime.
- Recomputed values and side effects must satisfy the intended forward/backward semantics.
- Storage savings and added compute work need separate measurements and definitions.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.