Recursive halving splits a chain of blocks in half, keeps the midpoint, and solves each half the same way. Count a call as one block evaluation during the backward phase, including recomputations; the original forward pass is not counted. For a power of two, the schedule obeys
(a) Solve the two recurrences and show that and .
(b) Storing everything makes calls in slots. Derive the work ratio and the memory ratio .
(c) Show that approaches , and compute and at , and , to two decimal places.
(d) Say which two sections this makes precise, and name the assumption about a block that the schedule needs for the gradient to stay correct.
This tier asks for a derivation, so there is no automatic checker. Write your answer, then open the worked solution and compare.
Worked solution
(a) For the call count, the claim is . At the right side is , which matches the base case. Assume the claim at . Then The first term uses , and the second cancels the that the induction step adds. For the slot count, the claim is . At it gives 1, matching the base case. Assuming it at gives .
(b) Divide the call count by the store-all call count: Divide the store-all slot count by the recursive-halving slot count:
(c) Write . Then so the ratio is above by a term that shrinks as grows. The values are:
| | | | | | | |---|---|---|---|---|---| | 8 | 12 | 3 | 7 | 1.71 | 2.67 | | 64 | 192 | 6 | 63 | 3.05 | 10.67 | | 1024 | 5120 | 10 | 1023 | 5.00 | 102.4 |
At the schedule does 12 calls in 3 slots against 7 calls in 8 slots. At it does 5120 calls in 10 slots against 1023 calls in 1024 slots. The work ratio grows like half the logarithm of the depth, while the memory ratio grows like the depth divided by its logarithm.
(d) Section 18.4 establishes that a trace needs one slot per node the backward sweep will read, which prices storing everything at slots. Section 18.5 introduces the schedule and the recomputation that buy the memory back. The recurrence assumes that a block is deterministic: a recomputed block must return the value it returned the first time. A block that draws a fresh random mask or increments a global counter breaks that condition, and the gradient becomes wrong with no diagnostic. The count also assumes that blocks cost the same, so it measures calls rather than seconds. Both assumptions belong to the code, not to the mathematics.