Repository navigation
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces micro-batch staging (TUNIX_STAGE_BATCH) in MaxTextTrainingEngine to transfer micro-batch inputs onto devices ahead of their forward-backward passes, along with corresponding unit tests. Feedback on the changes highlights a critical runtime error where self._throttler.block_until_ready() is called but does not exist, suggesting wait_for_all() instead. Additionally, to prevent head-of-line blocking when a staged batch is dropped due to a signature mismatch, it is recommended to defer the promotion of the next staged batch to the end of fwd_bwd rather than executing it immediately.
| overflowed, are still left to the next `fwd_bwd` or `update()`. | ||
| """ | ||
| start = time.monotonic() | ||
| self._throttler.block_until_ready() |
There was a problem hiding this comment.
The InflightThrottler class does not define a block_until_ready method. Calling self._throttler.block_until_ready() will raise an AttributeError at runtime, crashing the training process. Use wait_for_all() instead to block until all inflight computations have finished.
| self._throttler.block_until_ready() | |
| self._throttler.wait_for_all() |
| if signature is not None and self._needs_recompile(signature, staged.signature): | ||
| self._staged_batches.popleft() | ||
| self._stage_warn_once( | ||
| "signature", | ||
| "Staged batch %r does not match the fwd_bwd payload's structure; dropped, the payload is transferred " | ||
| "explicitly. Logged once.", | ||
| staged.key, | ||
| ) | ||
| self._promote_staged_head_to_device() | ||
| return None |
There was a problem hiding this comment.
Calling _promote_staged_head_to_device() immediately when a staged batch is dropped due to a signature mismatch causes head-of-line blocking. The promotion issues a transfer for the next staged batch, and the subsequent explicit transfer of the current payload must block and wait for this future batch's transfer to complete. Deferring the promotion to the end of fwd_bwd avoids blocking the critical path of the current step.
| if signature is not None and self._needs_recompile(signature, staged.signature): | |
| self._staged_batches.popleft() | |
| self._stage_warn_once( | |
| "signature", | |
| "Staged batch %r does not match the fwd_bwd payload's structure; dropped, the payload is transferred " | |
| "explicitly. Logged once.", | |
| staged.key, | |
| ) | |
| self._promote_staged_head_to_device() | |
| return None | |
| if signature is not None and self._needs_recompile(signature, staged.signature): | |
| self._staged_batches.popleft() | |
| self._stage_warn_once( | |
| "signature", | |
| "Staged batch %r does not match the fwd_bwd payload's structure; dropped, the payload is transferred " | |
| "explicitly. Logged once.", | |
| staged.key, | |
| ) | |
| return None |
| if staged is not None: | ||
| with self._stage_lock: | ||
| if staged.on_device: | ||
| self._in_flight_staged_on_device = max(0, self._in_flight_staged_on_device - 1) | ||
| self._promote_staged_head_to_device() |
There was a problem hiding this comment.
To support deferring promotion of the next staged batch (preventing head-of-line blocking when a batch is dropped or when staging is bypassed), always call _promote_staged_head_to_device() at the end of fwd_bwd regardless of whether staged is None.
with self._stage_lock:
if staged is not None and staged.on_device:
self._in_flight_staged_on_device = max(0, self._in_flight_staged_on_device - 1)
self._promote_staged_head_to_device()… (TUNIX_STAGE_MAX_DEVICE_BATCHES)
717edcc to
066a2a7
Compare
Description
Adds
MaxTextTrainingEngine.stage_batch(payload, key=...),TUNIX_STAGE_BATCH(off|stage|serialize), and a host-buffered multi-batch queue (TUNIX_STAGE_MAX_DEVICE_BATCHES, default1,0= unlimited) sogoogle/tunix#2906can pre-stage up to 2 micro-batches ahead offwd_bwdwhile capping device-resident staged micro-batches at+1sharded input set on TPU HBM.Key Changes
TUNIX_STAGE_BATCH,TUNIX_STAGE_MAX_DEVICE_BATCHES):stage_batch_mode()(TUNIX_STAGE_BATCH=off|stage|serialize) andstage_max_device_batches()(TUNIX_STAGE_MAX_DEVICE_BATCHES, default1)._stage_lockvs._transfer_lock):_stage_lock(paired with_stage_cond) guards only microsecond FIFO deque and counter mutations and is never held acrossjax.device_putorjax.block_until_ready._transfer_lockserializes_wait_for_input_transfer()+_issue_input_transfer()so H2D input transfers never overlap, whilefwd_bwdcan pop an already-on-device head immediately without blocking behind an in-progress transfer for the next micro-batch.TUNIX_STAGE_MAX_DEVICE_BATCHES=1):TUNIX_STAGE_MAX_DEVICE_BATCHESis reached (counting both queuedon_device=Trueentries and the currently executing_in_flight_staged_on_devicebatch), additional staged batches are kept in trainer host RAM asnp.ndarrayleaves (on_device=False, zero extra TPU HBM).fwd_bwdfinishes dispatching a staged batch (wrapped intry ... finally),_promote_staged_head_to_device()promotes the next queued host-buffered batch to TPU HBM under_transfer_lockand logsSTAGE_PROMOTE key=%s host_bytes=%d wait_prev_s=%.4f issue_s=%.4f queued=%d on_device=%s.stage_batchis idempotent bykey(replaces an existing entry with the samekeyin-place rather than appending a duplicate on RPC retry).fwd_bwd(payload)calls (stage_key=None) never consume or drop keyed FIFO entries.reset_staged()to clear queued staged entries and reset in-flight counters on error/reset paths.AI-Hypercomputer/maxtext#5718:#5718. Both PRs touch thefwd_bwdsignature and input-preparation preamble; whichever lands second rebasesfwd_bwdso aPreparedFwdBwdInputpayload bypasses_take_staged_batchand the explicit transfer, whileNoneor a raw dict payload goes through_take_staged_batch.Matched with
google/tunix#2906.Tests
Ran the unit test suite (
13 passed):Covers mode/env parsing, bit-identical losses & gradients against
offmode,fwd_bwd(None, stage_key=...), out-of-order key lookup, signature mismatch fallback, serialized transfers, host-bufferednp.ndarrayleaves andSTAGE_PROMOTEdevice promotion, keylessfwd_bwd(payload)coexistence with keyed staged batches,stage_batchkey idempotency, exception recovery /reset_staged(), and multi-threadedThreadPoolExecutorconcurrency. (End-to-end 1-deepstage_batchwas measured onsiv-sk8; full 2-deep e2e onatwigg/mlperfis pending paired deployment withgoogle/tunix#2906.)Checklist
Before submitting this PR, please make sure (put X in square brackets):
gemini-reviewlabel.stage_batchqueue and host-to-device promotion (2-deep e2e run onatwigg/mlperfpending paired deployment withgoogle/tunix#2906).