You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up to #8264 (tracked there in the review discussion, agreed to be handled separately).
To keep ZeRO-3 data-parallel ranks in lockstep during rollout, HybridEngineRollout.generate currently passes eos_token_id=None to the underlying generate call and restores EOS/padding semantics after the fact via _pad_after_eos. This fixes the deadlock, but as a consequence every rank always decodes the full max_new_tokens, even when every sequence in the global batch has already produced its EOS. The wasted compute is significant when typical responses are much shorter than the max response length.
Proposal
All ranks should collectively detect the early-stop condition — every sequence on every rank's batch has produced EOS — and stop the decode loop together, while preserving the ZeRO-3 invariant that all ranks execute the same number of parameter-gather collectives.
Concretely, the stop decision must be global, not local:
Periodically (every decode step, or every K steps) all-reduce a local "unfinished sequences remain" flag across data-parallel ranks.
All ranks stop only when the aggregated flag says no rank has unfinished sequences. Any rank exiting the loop based on local knowledge alone would reintroduce the deadlock Fix ZeRO-3 synchronization during OPSD rollout #8264 fixed.
This can be implemented either as a custom decode loop with an explicit sync point, or as a StoppingCriteria that aggregates the decision globally before returning True on all ranks.
Main 8-GPU OPSD run: micro_batch_size_per_gpu=1, gradient_accumulation_steps=1, n_samples_per_prompt=1 → 8 prompts / 8 rollouts per training iteration across 8 DP ranks.
Verification runs use max response length 64; full reproduction uses 1024. Responses are typically far shorter than the max, so decoding to max_new_tokens on every rank wastes a large fraction of rollout compute.
Design consideration
With micro_batch_size_per_gpu=1 there is exactly one sequence per GPU, so per-slot work reclamation (continuous batching) has nothing to reclaim locally — synchronized early stopping is the whole win for this configuration. Continuous batching becomes interesting for larger per-rank batches.
Please implement the stop-check as a reusable synchronized control-flow primitive (e.g. a periodic "global work remaining" rendezvous) rather than a one-off stop hack: continuous batching generalizes the same rendezvous from a "stop/continue" boolean into a "rebuild the batch composition" decision, so an early-stopping fix designed with that shape becomes a stepping stone instead of rework.
@LiRunGuo — you kindly offered to own this follow-up in #8264. GitHub won't let me assign you until you've commented on this issue (non-collaborator limitation), so please drop a comment here and I'll assign it to you.
Description
Follow-up to #8264 (tracked there in the review discussion, agreed to be handled separately).
To keep ZeRO-3 data-parallel ranks in lockstep during rollout,
HybridEngineRollout.generatecurrently passeseos_token_id=Noneto the underlying generate call and restores EOS/padding semantics after the fact via_pad_after_eos. This fixes the deadlock, but as a consequence every rank always decodes the fullmax_new_tokens, even when every sequence in the global batch has already produced its EOS. The wasted compute is significant when typical responses are much shorter than the max response length.Proposal
All ranks should collectively detect the early-stop condition — every sequence on every rank's batch has produced EOS — and stop the decode loop together, while preserving the ZeRO-3 invariant that all ranks execute the same number of parameter-gather collectives.
Concretely, the stop decision must be global, not local:
This can be implemented either as a custom decode loop with an explicit sync point, or as a
StoppingCriteriathat aggregates the decision globally before returningTrueon all ranks.Workload context (from #8264)
micro_batch_size_per_gpu=1,gradient_accumulation_steps=1,n_samples_per_prompt=1→ 8 prompts / 8 rollouts per training iteration across 8 DP ranks.max_new_tokenson every rank wastes a large fraction of rollout compute.Design consideration
With
micro_batch_size_per_gpu=1there is exactly one sequence per GPU, so per-slot work reclamation (continuous batching) has nothing to reclaim locally — synchronized early stopping is the whole win for this configuration. Continuous batching becomes interesting for larger per-rank batches.Please implement the stop-check as a reusable synchronized control-flow primitive (e.g. a periodic "global work remaining" rendezvous) rather than a one-off stop hack: continuous batching generalizes the same rendezvous from a "stop/continue" boolean into a "rebuild the batch composition" decision, so an early-stopping fix designed with that shape becomes a stepping stone instead of rework.
@LiRunGuo — you kindly offered to own this follow-up in #8264. GitHub won't let me assign you until you've commented on this issue (non-collaborator limitation), so please drop a comment here and I'll assign it to you.