[RFC] Shard-level P2P weight sync for non-colocate training
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 8.5k
- Forks
- 1.3k
- Avg merge
- 5h 36m
- Merged PRs (30d)
- 22
Description
Summary
This RFC proposes shard-level P2P weight synchronization for slime's non-colocate training path, as an optional weight transfer mode under --update-weight-mode full.
Core idea: each training TP rank converts and sends only its local shard, using dist.send/recv to write directly into the matching SGLang TP rank, instead of gathering full weights on rank 0 and NCCL-broadcasting them.
Three-phase rollout:
| Phase | Goal | Relationship to the current path |
|---|---|---|
| Phase 1 | Land basic functionality, validate the approach, coexist with broadcast | Opt-in via --use-p2p-weight-update; automatic fallback when preconditions fail |
| Phase 2 | Broaden model support; reduce bucket / control-plane overhead | Still opt-in; expand the supported surface area |
| Phase 3 | Enable P2P by default for supported configs; broadcast becomes fallback | Change the default path; keep an escape hatch |
Motivation
Current path (UpdateWeightFromDistributed)
For non-colocate + --update-weight-mode full + --update-weight-transport nccl, weight sync roughly follows:
- all_gather each parameter across the training TP group to reconstruct full tensors
- PP source rank performs Megatron → HF conversion on full weights
- rank 0 broadcasts full chunks to SGLang engines over NCCL
- SGLang load_weights
Main issues:
| Issue | Impact |
|---|---|
| Training TP0 must all_gather and hold broadcast buffers | Higher sync latency; rank-0 memory skew |
| Non-TP0 ranks are underused during gather/broadcast | Uneven compute and memory utilization |
| Each inference TP rank receives full weights, then shards internally | High traffic; misaligned with training shard layout |
| Bucketization further amplifies rank-0 pressure | Especially visible for large models / high TP |
Expected benefits
| Dimension | P2P expectation |
|---|---|
| Traffic | Each rank sends only its shard; no full broadcast |
| Trainer memory | Less rank-0 full-tensor gather buffering |
| Sync latency | Shorter update_weights when TP sizes align |
| Correctness | Numerically aligned with broadcast (no logprob regression) |
Proposed Architecture
Single sync flow (Phase 1)
- Vocab params (embed / lm_head): small TP all_gather → strip padding → slice SGLang-aligned shards
- Other dense params: shard-level Megatron→HF conversion (no all_gather) → send in buckets
- Expert params (MoE, Phase 2+): send Megatron shards directly (Phase 1 falls back to broadcast for MoE overall)
- Per bucket: gather per-TP metadata → rank-0 HTTP notify SGLang → NCCL barrier →
dist.send/recv→ wait for SGLang load to finish
Preconditions (Phase 1)
| Requirement | Notes |
|---|---|
| Non-colocate | Colocate uses CUDA IPC; out of scope |
--update-weight-mode full |
Mutually exclusive with delta sync |
--megatron-to-hf-mode bridge |
P2P relies on Bridge weight layout |
| Megatron TP == SGLang TP | Must hold for every rollout engine |
| SGLang presharded recv support | Extend SGLang update_weights_from_distributed |
| Shard-level conversion for the model | Phase 1 target: Qwen2 / Qwen3 dense |
When any precondition fails, automatically fall back to NCCL broadcast with a clear rank-0 log line. Existing users are unaffected.
Phase 1 — Basic functionality, validation, coexistence with broadcast
Goal: land P2P with minimal intrusion; do not change default behavior.
Deliverables
- New
UpdateWeightFromDistributedP2Pclass alongsideUpdateWeightFromDistributed - CLI flag:
--use-p2p-weight-update - Startup precondition checks and automatic fallback
- Shard-level Megatron→HF conversion (
convert_shard_to_hf; Phase 1: Qwen2/Qwen3 dense) - SGLang-side patch: presharded recv, per-TP metadata dispatch, barrier sync
- User docs and smoke scripts (Qwen3-4B TP=4 as the reference config)
Acceptance criteria
- Functionality: Qwen3-4B TP=4 smoke (5 rollout steps) completes without NCCL hang or crash
- Performance: same config, broadcast vs P2P — steady-state
update_weightsfor P2P ≤ broadcast (TP-aligned, single engine) - Correctness:
train_rollout_logprob_abs_diffon par with broadcast; no meaningful regression - Coexistence: behavior unchanged when the flag is off; fallback path works end-to-end
- Observability: per-phase / per-bucket timing logs or metrics
Out of scope (Phase 1)
- Shard conversion for MoE / DeepSeek / GLM / VLM, etc.
- Megatron TP ≠ SGLang TP
- Changing the default broadcast path
- Integration with
--update-weight-mode delta - Colocate / vLLM backend
Phase 2 — Broader model support and control-plane optimizations
Goal: expand the set of models where P2P is usable, and reduce fixed per-bucket overhead so more production configs benefit after opt-in.
2.1 Model adapters (shard-level Megatron→HF)
Suggested priority:
| Priority | Models | Complexity | Notes |
|---|---|---|---|
| P0 | Llama / GLM4 dense | Low | Close to Qwen2 structure |
| P1 | Qwen3 MoE / GLM4 MoE | Medium | Dense via shard convert; experts may be sent as raw Megatron shards |
| P2 | DeepSeek V3 / Qwen3-Next / Qwen3.5 | High | MLA, linear attention, MTP, indexer reordering |
| P3 | Qwen3-VL / MiMo / GPT-OSS / MiniMax | Medium–high | Multi-tower / special naming |
Each item needs: shard-conversion unit tests + 5-step smoke + weight / logprob alignment vs broadcast.
2.2 Performance and architecture improvements
The broadcast path already uses bucketing. If P2P keeps a similar model, fixed per-bucket cost (HTTP + barrier + load_weights) remains a major residual expense:
| Improvement | Expected benefit | Notes |
|---|---|---|
Larger / adaptive update_weight_buffer_size |
Fewer buckets | Strong on small dense models; MoE must balance peak memory |
| Single HTTP request for merged per-TP metadata | Lower lock + Ray overhead | One request carrying per-TP tensor counts |
Async dist.isend + batched wait |
Less Python loop overhead | Replace per-tensor synchronous send |
| Convert / send pipelining | Overlap compute and comms | Careful barrier ordering required |
| Fewer per-bucket loads on SGLang | Less wait time | May need SGLang protocol changes |
| Multi-engine send optimization | Multi-engine setups | Avoid bucket count × engine count scaling |
2.3 Observability
- Promote timing / metrics into formal observability
- Document bucket tuning (buffer size vs TP vs engine count)
Phase 2 acceptance criteria
- At least Llama + Qwen3 MoE usable under P2P with aligned TP
- TP=4, single engine: measurable steady-state gain vs broadcast
- Multi-engine: after bucket optimizations, P2P is not materially slower than broadcast
- Documented fallback matrix (model × TP × engine × bridge/raw)
Phase 3 — P2P enabled by default
Goal: when all preconditions are met, P2P becomes the default path for --update-weight-mode full + nccl; broadcast remains fallback.
Planned changes
- Default on: non-colocate + bridge + supported model + aligned TP → P2P automatically
- Explicit opt-out: add
--no-use-p2p-weight-updateor deprecate the positive flag (TBD) - Code cleanup: factor shared bucket / lock / metrics logic between P2P and broadcast
- Upstream SGLang patch: land presharded recv in SGLang mainline
- CI: add P2P smoke to CI matrix (at least Qwen3-4B TP4)
Migration and compatibility
| User scenario | Phase 3 behavior |
|---|---|
Explicit --use-p2p-weight-update |
Unchanged |
| Flag not set, preconditions met | P2P by default |
| MoE / unsupported model / TP mismatch / raw mode | Broadcast + rank-0 log |
| delta / disk / colocate | Unchanged |
Phase 3 acceptance criteria
- Default supported config on main uses P2P
- Full fallback regression suite passes
- Docs updated from "opt-in" to "default with fallback"
- At least one production-scale MoE 50-step run: P2P vs broadcast
Open Questions
- Should Phase 3 default-on roll out via a model allowlist (Qwen/Llama first, then MoE), or switch in one step?
- Should the SGLang patch live in slime, or be contributed upstream?
- Is P2P needed for
--megatron-to-hf-mode raw, or permanent fallback? - Should Phase 2 ship an official benchmark script (similar to
delta_weight_syncexamples)? - Are breaking SGLang protocol changes acceptable for bucket optimization (e.g. one HTTP call with full metadata)?
Current Phase 1 implementation
An initial Phase 1 implementation is open for review in PR #2146: feat(p2p): add shard-level weight update with automatic broadcast fallback.
What it includes:
- Opt-in
--use-p2p-weight-update(requires--update-weight-mode full; default behavior unchanged) UpdateWeightFromDistributedP2Pwith automatic NCCL broadcast fallback and rank-0[P2P]logging- Qwen2 / Qwen3 dense shard Megatron→HF conversion
sglang_p2p.patchapplied at Docker build time (after existing SGLang patches)- Docs:
docs/en/advanced/p2p-weight-sync.md,docs/zh/advanced/p2p-weight-sync.md
Reported validation (see PR comments for details):
- Qwen3-4B TP=4 smoke on 8×A100 (
exit_code=0); steady-stateupdate_weights~0.33–0.40s - Qwen3-8B TP=4, 50 rollout steps: steady-state
perf/update_weights_time~0.48s (P2P) vs ~0.76s (NCCL broadcast), ~1.56× faster on the weight-sync phase
This PR is intended to land Phase 1 as an opt-in path; Phases 2 and 3 in this RFC remain follow-up work (broader model support, bucket/control-plane optimizations, and optional default-on behavior).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing PR #2146 and the Phase 1 scope in this RFC, then read docs/en/advanced/p2p-weight-sync.md and docs/zh/advanced/p2p-weight-sync.md. Use the Qwen3-4B TP=4 smoke configuration as the entry point; done means the listed Phase 1 acceptance criteria pass, including fallback behavior, timing, correctness, and observability.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- distributed-systems, machine-learning
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100