feat(fsdp): per-module weight-precision control, and Qwen3.5 compute-dtype alignment - #2145
Closed
Rockdu wants to merge 5 commits into
Closed
feat(fsdp): per-module weight-precision control, and Qwen3.5 compute-dtype alignment#2145Rockdu wants to merge 5 commits into
Rockdu wants to merge 5 commits into
Conversation
Port miles_diffusion#91 onto the FSDP backend's existing precision layer: a PrecisionSpec of FQN/class-glob rules is compiled into nested fully_shard wrap units, so a model can pin the all-gather (forward) dtype of selected modules without leaving FSDP. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Guarded non-intrusive Dumper registration in the FSDP train step plus a harness that drives the actor's construction path on synthetic tokens, so the dumper-module-report skill can build a per-module dtype inventory. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…asts MixedPrecisionPolicy defaults cast_forward_inputs=True, so every wrapped decoder layer re-cast its activations to the gather dtype. Under an fp32-gather + bf16-autocast policy that pulled the residual stream back to fp32 at each layer boundary while the matmuls ran bf16. Turn the cast off exactly when a forward autocast is active. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
F.embedding is not autocast-covered, so the embedding output carries the gathered weight dtype and seeds the residual stream; Qwen3_5RMSNorm's type_as(input) then propagates it through every layer. Declare it as a PrecisionSpec rule on the GatedDeltaNet arch spec, active only when compute and gather dtypes disagree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Contributor
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
Contributor
Author
|
Closing — opened against the upstream repo by mistake. Work continues on the fork branch. |
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.
What
Ports miles_diffusion#91's per-parameter weight-precision control onto the FSDP backend, and uses it to close the Qwen3.5 train/rollout compute-dtype gap.
The FSDP backend already had a
PrecisionPolicywith run-levelparam_dtype/reduce_dtype/autocast_dtypeand a per-arch hook registry. This adds the missing axis: per-module gather dtype. A model declaresPrecisionSpecrules (FQN glob and/or class-name glob), and a compiler lowers them onto nestedfully_shardgroups — one wrap unit per module whose gather dtype differs from its parent's. Everything stays inside FSDP (DTensor params, FSDP grad reduction, DCP/offload unchanged).Three dtype axes, each with one owner:
--disable-fp32-master(run-level)param_dtype, refined per module byPrecisionSpecautocast_dtype+ arch class patchesmiles_diffusion's
input_dtype_policyis deliberately not ported: an LLM's model-boundary inputs are integerinput_ids/position_ids, so there is no float boundary cast to declare.The Qwen3.5 finding
Dumped every
nn.Module's IO dtype for Qwen3.5-4B under FSDP2 (non-intrusive Dumper + thedumper-module-reportskill), in the precision-aligned policy that Qwen3 dense's true-on-policy contract uses — fp32 master, fp32 gather, bf16 autocast.527 of 1074 dumped tensors were fp32, from two compounding causes:
MixedPrecisionPolicydefaults tocast_forward_inputs=True, so every wrapped decoder layer re-cast its activations up to the fp32 gather dtype at each layer boundary — while autocast ran the matmuls at bf16.F.embeddingis not an autocast-covered op, so the embedding output carried the gathered weight dtype and seeded the residual stream.Qwen3_5RMSNormends inoutput.type_as(x)and every residual add promotes, so that one dtype propagated through the whole activation path.Both are fixed here, and both are load-bearing — fixing either alone leaves the stream fp32. Result: 0 of 1074 fp32; all 1072 float tensors bf16, fp32 confined to master weights, int64 confined to
input_ids/position_ids.Changes
adaptations/precision.py:ModuleSel/Rule/PrecisionSpec, thecompile_precisionlowering (whole-tree coverage, minimal wrap-unit cover, zero-hit rules rejected),wrap_plandeepest-first ordering, andparse_precision_rulesfor the--fsdp-precision-rulesoperator escape hatchapply_fsdp2: wraps per compiled unit at that unit'sparam_dtype; newcast_forward_inputsparameter, which the actor sets toFalseexactly when a forward autocast is activeadaptations/specs/qwen3_5_moe.py: registers the embedding gather rule for GatedDeltaNet archs (Qwen3.5/3.6/Qwen3-Next). Self-activating — a no-op unless compute and gather dtypes disagreedebug_dump.py+tools/dump_fsdp_module_dtypes.py: guarded Dumper registration in the train step, and a harness that drives the actor's construction path on synthetic tokens to produce the dtype inventoryDefault behavior is unchanged: with no autocast the policy resolves to 0 spec rules and
cast_forward_inputs=True, and a default-policy Qwen3.5 dump is byte-for-byte the same dtype census as before this PR.Tests
tests/fast/backends/test_fsdp_precision_plan.py— 13 CPU tests for the compiler, each docstring drawing the resulting gather dtype per nodetests/fast/backends/test_fsdp_precision_wrap.py— nested wrap units under real FSDP2 on 2 gloo ranks, asserting the param dtype each module sees at forward and that master/grad stay fp32stage-a-cpu; fulltests/fast/backends/suite passes (400 tests)Pending