Repository navigation
Conversation
…ne plans AffineWeightSync plans each parameter once with plan_transfer, from the trainer's storage maps into a tensor-parallel layout held by every inference replica, and runs every sync as one execute_transfers batch, so no rank gathers a whole parameter. WeightArena keeps a rank's shards in one buffer that is never reallocated, so CUDA graphs captured on it stay valid across syncs. Signed-off-by: RunguoLi <li19107254665@gmail.com>
|
Hi, @LiRunGuo A couple of questions, mostly to learn: In _LocalFirstLeastLoaded, the inline load increment in call is later overwritten by settle(), so it only balances multiple multi-holder regions within a single parameter. Is that the intended scope, and did you consider balancing across parameters during planning too? |
|
Thanks @LiRunGuo, this is a clean first step, and it follows the RFC closely: the sync is declared entirely in maps, planned by I ran it on CPU (gloo, 4 ranks), merged with current master: 17 passed and 1 skipped (the CUDA-graph test), and flake8 is clean. Turning off the local-first branch of the selector makes 3 of the tests fail, so the load tests do pin the policy. A few thoughts, none blocking for a draft:
On "What it does not do": the two-layout constructor from #9026 would let a surviving TP shard and the trainer's partitions go through this same path when the split is along rows. I can open it as a small separate PR that this one can use, if that suits you and @0z5a. The RTX 4090 table is a nice result: 7–8× faster than gathering for Qwen3-8B at TP4, with the peak set by the staging budget rather than the largest parameter. |
… global rank with any group; AutoTP source untested Test that a custom group keeps the maps keyed by global rank. Signed-off-by: RunguoLi <li19107254665@gmail.com>
|
Thanks @nathon-lee and @Achyuthan-S. I pushed two commits for the points below: 70831cb (docstrings, docs and one test, no behavior change), and 48a3575, which moves the planning onto #8936 now that it has merged (after merging current master).
Thanks for running it, and for the selector check.
#8936. The two-layout constructor. Yes, a separate PR suits me, row case first, as @0z5a agreed on #9026; thanks for opening #9052. The sync declares its sources only through maps, so it can take a surviving TP shard plus the trainer's partitions as soon as #9052 lands, and I'll add that case to this PR's tests then. Tests on 48a3575 (on current master, dfa7d34), 4× RTX 3090:
yapf and flake8 (the versions pinned in pre-commit) pass on the changed files. |
|
Thanks @LiRunGuo, that addresses everything. I read 48a3575 merged with current master: the sync now plans with one
|
|
Thanks @Achyuthan-S.
|
Status: draft, part of RFC #9026. The RFC has not been accepted by maintainers yet. This PR stays a draft until it is, so that the design can be discussed on code.
plan_transfer.What it is. A building block for rollout engines that keep their own tensor-parallel copy of a ZeRO model. No rollout engine is wired to it in this PR. It is validated on synthetic modules in the unit tests and on Qwen3 checkpoints in the benchmark below. Wiring it into an engine (for example as the sync of #9023's
AutoTPRollout) is a follow-up.What it adds. A new module,
deepspeed/runtime/rollout/affine_weight_sync.py, and a section indocs/code-docs/source/affine-transfer.rst. No existing source file changes.AffineWeightSync(source_maps, target_maps, dtype, group=None, budget=StagingBudget(), limits=None):plan_transfer, without communication;sync(source_buffers, target_buffers)then runs the copies of all parameters as oneexecute_transfersbatch ([checkpoint] Execute affine transfer plans with bounded peer staging #8809), so no rank gathers a whole parameter;preflight_error, so every rank refuses the batch before any data moves, rather than one rank raising while the others wait.local_first_least_loaded, local copies do not count as load, and single-holder regions do.plan_transferconsults a selector only for regions with several holders, so the single-holder load of a parameter is counted once that parameter is planned.plan_transferswith its policy once it lands.zero_param_shaped_storage_map(param):zero_param_storage_affine_mapnested into the parameter's own shape, asautotp_storage_affine_mapsdoes for AutoTP models. A tensor-parallel layout describes a parameter in its own shape, and both sides of a plan must describe the same tensor.replicated_layout_map(layout, replicas): one replica's tensor-parallel layout, keyed by TP rank (an AutoTP layout map, orcontiguous_split_map), held by every replica and keyed by global rank. It is built withnest_affine_mapsandzero_storage_affine_map, astest_zero_affine.py's_one_holder_eachbuilds one holder per layout shard.WeightArena: a rank's shards as views of one buffer that is never reallocated.Why not a duplicate
AutoTPRollout) refreshes its inference copy by gathering each full fp32 master weight withsafe_get_full_fp32_paramand cutting out the local shard. That moves every parameter to every rank. This PR moves each element only to the ranks that need it.What it does not do (yet)
plan_transferrefuses replicas with different boundaries.relay_map([RFC] Two-stage relay for cross-node weight sync, priced by a calibrated cost model #9026 §1).Tests (
tests/unit/runtime/rollout/test_affine_weight_sync.py)layout.extractof the gathered parameter after two optimizer steps.AffineTransferExecutionErrorand no target changes.replicated_layout_mapgives each replica its layout shard and refuses replicas that do not fit.Results: 4× RTX A6000 (driver 595.58.03), torch 2.13.0+cu130, CUDA 13.0, Python 3.12. Commands run from
tests/:pre-commit passes on the changed files.
Measurements
stage3_param_persistence_threshold: 0, no optimizer). Each number is the median of 5 syncs after one warm-up.GatheredParameterson each parameter, then a copy of this rank's slice into an arena. That is feat(rollout): add AutoTP rollout engine with in-memory weight sync #9023's approach, but on the bf16 parameter rather than the fp32 master, so it moves half the bytes it would there.max_memory_allocatedincrease on any rank during a sync.To reproduce, run the script below with
torchrun --nproc_per_node 4 pr_weight_sync_bench.py --model <Qwen3-1.7B or Qwen3-8B> --layouts 0-3:2 0-3:4 0-3:1 2-3:2 --out <dir>. It needs transformers. Layouts are<ranks>:<tp>, so0-3:2is two TP=2 replicas on ranks 0–3; Qwen3-8B was run with0-3:4only, since two copies at TP1 or TP2 do not fit in 24 GB.pr_weight_sync_bench.py
Compatibility
autotp_storage_affine_mapsas the source maps);AI assistance: AI assistance was used. The code, tests and this description were drafted with an AI coding agent (Claude Code). The submitter reviewed every changed line and ran the tests above.
Maintenance contact: @LiRunGuo. cc @Achyuthan-S @0z5a @jinyouzhi