@@ -1682,15 +1682,8 @@ def train(self):
16821682 self ._fire ("on_epoch_start" )
16831683 epoch_in_progress = True
16841684
1685- # ------------------------------------------------------------------
1686- # Async batch collation (double-buffering) setup
1687- # ------------------------------------------------------------------
1688- # Two consecutive steps in the same epoch see the SAME ``tokenized``
1689- # order (it only changes at an epoch boundary reshuffle), so step N+1's
1690- # slice is knowable while step N runs. ``_slice_examples`` reproduces the
1691- # loop's deterministic wrap-around slice against the *current* order, and
1692- # ``_collate_batch`` is the producer run on the background thread (the
1693- # heavy collate releases the GIL, so it overlaps the GPU step).
1685+ # Collate step N+1 on a background thread while step N runs on GPU.
1686+ # Do not collate ahead across reshuffles; the tokenized order changes.
16941687 n_examples = len (tokenized )
16951688
16961689 def _epoch_of (step : int ) -> int :
@@ -1716,13 +1709,6 @@ def _collate_batch(step: int):
17161709 f"SFT async batch collation (double-buffering): { 'ENABLED' if collate_ahead_enabled else 'disabled' } "
17171710 )
17181711
1719- # Whether the step about to run can collate its successor ahead. The loop
1720- # reshuffles ``tokenized`` after step N iff ``_epoch_of(N) > cur_epoch``
1721- # (the same predicate the epoch-boundary block below uses). When a
1722- # reshuffle would occur, step N+1 reads a DIFFERENT order than step N, so
1723- # it must not be collated ahead against the pre-shuffle order. Mirroring the
1724- # loop's reshuffle decision via ``cur_epoch`` (the authoritative loop
1725- # state) keeps the predicate exact regardless of wrap-around alignment.
17261712 def _can_collate_ahead (step : int , cur_epoch : int ) -> bool :
17271713 if async_collator is None or step + 1 > num_steps :
17281714 return False
@@ -1737,24 +1723,14 @@ def _can_collate_ahead(step: int, cur_epoch: int) -> bool:
17371723
17381724 with Timer ("step" , all_timings ):
17391725
1740- # Data loading with wrap-around. With async batch collation
1741- # enabled this measures only the (ideally ~0) wait for the
1742- # already-running background collate; otherwise the full serial collate.
1726+ # With async enabled, this is usually just the wait for an
1727+ # already-running collate; otherwise it is the full collate.
17431728 with Timer ("data_loading" , all_timings ):
17441729 if async_collator is not None and async_collator .pending_step () == self .global_step :
1745- # Consume the batch collated ahead during the previous step.
1746- # ``get`` asserts the in-flight step matches, so a
1747- # stale/mismatched batch fails loudly.
17481730 batch = async_collator .get (self .global_step )
17491731 else :
1750- # No valid in-flight batch (first step, or the first
1751- # step after an epoch reshuffle): collate synchronously
1752- # against the live order.
17531732 batch = _collate_batch (self .global_step )
17541733
1755- # Kick off the NEXT step's collate on the background thread so
1756- # it overlaps this step's GPU work — only when the successor
1757- # is in the same epoch (no reshuffle between them).
17581734 if _can_collate_ahead (self .global_step , current_epoch ):
17591735 async_collator .submit (self .global_step + 1 )
17601736
@@ -1847,12 +1823,7 @@ def _can_collate_ahead(step: int, cur_epoch: int) -> bool:
18471823 if epoch > current_epoch :
18481824 self ._fire ("on_epoch_end" )
18491825 epoch_in_progress = False
1850- # Drain any in-flight batch BEFORE reshuffling so a background
1851- # collate can never read ``tokenized`` while it is being
1852- # shuffled, and so the next epoch's first step is collated
1853- # synchronously against the post-shuffle order. ``_can_collate_ahead``
1854- # already withholds cross-epoch submits, so this is normally a
1855- # no-op — it's defense in depth against the reshuffle/collate-ahead race.
1826+ # Drain before mutating tokenized order.
18561827 if async_collator is not None :
18571828 async_collator .clear ()
18581829 for _ in range (epoch - current_epoch ):
@@ -1865,10 +1836,6 @@ def _can_collate_ahead(step: int, cur_epoch: int) -> bool:
18651836
18661837 self .global_step += 1
18671838 finally :
1868- # Always tear down the async batch collation thread (drains any
1869- # in-flight batch and joins the worker) so neither the background
1870- # thread nor the dataset reference is leaked, even on exception.
1871- # No-op when async batch collation is disabled.
18721839 if async_collator is not None :
18731840 async_collator .shutdown ()
18741841 if self ._torch_profiler_enabled :
0 commit comments