Repository navigation
(fsdp2 dev.) Add training.shard_frozen_tables: frozen target tables in the root FSDP group - #3
Closed
yushengsu-thu wants to merge 1 commit into
Closed
yushengsu-thu wants to merge 1 commit into
yushengsu-thu wants to merge 1 commit into
Conversation
With shard_frozen_tables the FSDP2 backend keeps the frozen target lm_head and embed_tokens in the root FSDP group instead of listing them as ignored, replicated parameters. They are sharded at rest and all-gathered once per accumulation window with the root parameters, so the DFlash fused head still sees ordinary unsharded tensors inside forward. Peak memory is unchanged because the tables must be resident for the vocabulary objective; memory at rest drops by (1 - 1/world_size) of the tables. FSDP1 rejects the option. Stacks directly on sgl-project#915; the BackendOptions scaffolding is shared verbatim with the other FSDP2 option PRs so they can land in any order.
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.
Increment-only view of sgl-project#924 (base
codex/fsdp2-backend= sgl-project#915).Conclusion
backend.py+54 shared scaffolding,fsdp2.py+15,launch.py+8,assembly.py+7,trainer.py+5,schema.py+4,disaggregated.py+4); tests +193, docs +2.shard_frozen_tables: speed — no change: DFlash2 −1 ms/step (995 → 994 ms), DSpark +3 ms (726 → 729 ms). Memory — peak slightly larger: +595 MB (DFlash2, 37652 → 38247 MB) and +593 MB (DSpark, 25058 → 25651 MB); memory at rest smaller, −1782 MB per rank (allocated after wrap 4049 → 2267 MB at DP=4, grows with world size).shard_frozen_tables: DFlash2 — speed no change (1058 → 1060 ms compute per step, +2 ms, +0.2%); memory no change (56082 → 57996 MB nvidia-smi max, +1914 MB, within the granularity of reserved memory). DSpark — not run online for this option.Motivation
The DFlash-family wrappers carry the frozen target
lm_headandembed_tokens(two 151936 × 4096 bf16 tables ≈ 1.24 GB each for Qwen3-8B) and both backends replicate them on every rank as ignored parameters. Under FSDP2 they can instead live in the rootfully_shardgroup: sharded at rest, all-gathered once per accumulation window together with the root parameters, which keeps the DFlash fused head working (it readslm_head.weightas an ordinary tensor inside forward). This PR adds the opt-in and measures the trade.Stacks directly on sgl-project#915 (base branch
codex/fsdp2-backend). TheBackendOptionsscaffolding is shared verbatim with the other FSDP2 option PRs so they can land in any order.Modifications
training/fsdp2.py: withshard_frozen_tables, the frozen tables are not listed inignored_params, so they join the root FSDP2 group; everything else in_shard_modelis unchanged.training/backend.py:BackendOptions/ hooks (shared scaffolding). FSDP1 rejects the option.config/schema.py:training.shard_frozen_tables(requiresbackend: fsdp2); plumbing.training/disaggregated.py+assembly._backend_options(): the disaggregated runtime did not forwardbackend_optionsto its trainers, so the option was silently off in every online run until the online e2e of this series caught it; both call sites now forward it, with tests.tests/test_runtime/test_fsdp2_shard_frozen_tables.py: rejection/config tests, 2-GPU parity of sharded vs replicated tables (losses equal to 5 places, tables are DTensors, full state dict still carries them).End-to-end comparison — offline (
Trainer.fit)Offline e2e =
build_offline_runtime→Trainer.fit(): offline reader,FeatureDataLoaderwith 4 workers,TrainerControlleracks and logging, final checkpoint; 256 synthetic samples × 6 epochs = 48 optimizer steps, seq 2048, batch 2 × accum 4, DP=4 on 4 × B300 (torch 2.13.0+cu130); steady state = last 24 steps from the controller's log callbacks. Step-level = the realTrainerCorestep on a resident batch, batch 2 × accum 8, seq 4096. Production-shaped Qwen3-8B drafts with random weights and synthetic features; deltas are per rank.fsdp→fsdp2step timefsdp2→+shard_frozen_tablesstep timeEnd-to-end comparison — online (disaggregated)
Online e2e = the disaggregated path exactly as
specforge trainruns it (managed-local): one SGLang 0.5.18 capture server with the spec-capture patch on GPU 0 (Qwen3-8B,mem_fraction_static 0.5), Mooncake store, producers feeding real ShareGPT prompts (6000 conversations,max_length 2048, qwen chat template), and a DP=3 trainer on GPUs 1–3; batch 2 × accum 4, 40 optimizer steps,num_anchors 512; steady state = the controller'sperf/*counters (averaged over the ranks that logged them) over the last 24 optimizer steps.samples/s= 24 samples per optimizer step (batch 2 × accum 4 × 3 trainer GPUs) divided by the mean step time of that window;train computeanddata waitare per optimizer step. GPU memory is the nvidia-smi maximum over the run for the trainer GPUs.DFlash2
fsdp2fsdp2fsdp(FSDP1)fsdp2fsdp2+shard_frozen_tablesDSpark
fsdp2fsdp2fsdp(FSDP1)fsdp2fsdp2+shard_frozen_tablesDSpark was not run online for this option (its tables and trade-off are identical to DFlash2).
The first online matrix of this series ran with the options silently ignored: the disaggregated launch path did not forward them (fixed in this PR); the tables above are from the runs after the fix. Online memory is nvidia-smi
usedon the trainer GPUs, i.e. what the caching allocator reserved, a coarse measure; the precise peak-allocated numbers are in the offline table.Notes: the "memory at rest −1782 MB" figure is the allocated memory right after wrapping (step-level harness, DP=4); everything else above is e2e. On the EAGLE3 offline e2e row: the option changes nothing in the EAGLE3 model (the frozen
embed_tokenslives insidedraft_model, not on the composite, and is already handled by FSDP2's frozen-parameter path); the slower run was the last of a long sequence of runs on the node and reads 67 MB of features per sample, so it needs a re-run before being attributed to anything but loader/page-cache contention.