perf(rollout): group the synchronous trainable-subset R2R broadcast - #723
Open
karkuspeter wants to merge 1 commit into
Open
karkuspeter wants to merge 1 commit into
karkuspeter wants to merge 1 commit into
Conversation
The synchronous R2R path offers two shapes and the cheap one is neither. Its per-parameter branch sends only the trainable subset but pays one collective per tensor, each a handshake across every rollout replica, which for a model of many small parameters costs far more than the traffic. Its grouped branch (`broadcast_all_params=true`) pays one collective but walks the whole state dict, shipping frozen parameters on every sync. Group the per-parameter loop and both savings apply, with `broadcast_all_params` left meaning only what its name says. Measured on a 3.30 GiB trainable subset across 321 parameters broadcast to twelve rollout replicas: 0.34 s per-parameter, 0.16 s grouped over the whole 7.88 GiB state dict, 0.05 s grouped over the subset. It costs no memory, since a contiguous parameter is still broadcast in place. A non-contiguous parameter's receive buffer only holds its data once the group closes, so those copies back are deferred to after `group_end`, the same way `do_nccl_broadcast_grouped` already handles them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The synchronous R2R path offers two shapes and the cheap one is neither of them:
tensor — each a handshake across every rollout replica;
broadcast_all_params=true) pays one collective, but walks the wholestate dict and so ships the frozen parameters on every sync.
This groups the per-parameter loop, so both savings apply at once and
broadcast_all_paramsmeans only what its name says: whether frozen parameters travel too.
Measurements
From an RL run with twelve single-rank rollout replicas on two nodes, 3.30 GiB of trainable
parameters across 321 tensors:
At equal bytes grouping is worth about 7x here, and it costs no memory: a contiguous
parameter is still broadcast in place, and model VRAM measured identical at 7.5 GiB per rank
across all three shapes.
Implementation notes
A non-contiguous parameter's receive buffer only holds its data once the group closes, so those
copies back are deferred to after
nccl_group_end— the same waydo_nccl_broadcast_groupedalready handles them.
The obvious alternative, giving
do_nccl_broadcast_groupedatrainable_onlyflag and callingit from this branch, would change what gets sent: that function iterates
_buffer_state_dictora raw
state_dict(), whereas this branch iteratesrollout.model_param_map(weight_mapper),which is HF-name-mapped and includes
get_quantized_tensors. Names and membership both differ,and
trainable_paramsis keyed to the latter. Grouping in place keeps the set of tensors andtheir order exactly as they were.
Testing
tests/test_r2r_broadcast_grouping.py, CPU-only, with the transport stubbed by a fake thatrecords the call order and, like a real group, only fills a receive buffer at group end. Both
the grouping and the deferred copy-back fail against the pre-change code, so they are real
regression checks rather than restatements. Added to the pytest line in
tests/run_test.sh.Validation
python -m pytest -q tests/test_r2r_broadcast_grouping.py tests/test_weight_sync.py tests/test_ranked_rollout_end_and_wst_fence.py— 49 passeduvx ruff@0.12.7 format --checkanduvx ruff@0.12.7 checkon the changed files — clean