Repository navigation
[PyTorch] Quantize distributed BF16 weights in the fused grouped MLP - #3695
Closed
xrennvidia wants to merge 2 commits into
Closed
xrennvidia wants to merge 2 commits into
xrennvidia wants to merge 2 commits into
Conversation
Contributor
[Medium impact] The PR appears safe to merge; no new blocking issues were found. SummaryThe fused grouped MLP now gathers distributed BF16 weights before quantizing them with each expert’s quantizer. Already-quantized weights pass through unchanged.
The three earlier, unnumbered findings are addressed: regression tests were added, CI runs both files, and both saved-input test layers set Diagram%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[Distributed weight shards] --> B[Gather full weights]
B --> C{Already quantized?}
C -->|Yes| E[Use weights unchanged]
C -->|No| D[Quantize with per-expert quantizers]
D --> F[Run grouped GEMM]
E --> F
G[Quantizers saved in forward] --> D
Reviews (12) · Last reviewed commit: "[PyTorch] Drop NVFP4 rowwise input copie..." · Reviewed by Greptile |
xrennvidia
force-pushed
the
xren/fused_grouped_mlp_gtp_bf16_weight_requant
branch
2 times, most recently
from
October 17, 2026 08:59
b0d0f7d to
a11d19c
Compare
xrennvidia
force-pushed
the
xren/fused_grouped_mlp_gtp_bf16_weight_requant
branch
3 times, most recently
from
October 17, 2026 09:25
70020d5 to
b4ae3f7
Compare
xrennvidia
force-pushed
the
xren/fused_grouped_mlp_gtp_bf16_weight_requant
branch
2 times, most recently
from
October 18, 2026 06:34
5ea48b1 to
c159f66
Compare
A distributed (e.g. GTP) weight whose shards are not natively quantized is re-gathered as BF16. The fused grouped-MLP op assumed gathered weights were already quantized: forward quantized the shards before the gather, and backward read _columnwise_data / the NVFP4 amax straight off the gathered tensor, which fails for a module whose per-module recipe (e.g. MXFP8 experts under a global NVFP4 recipe) does not create native-quantized params. Gather first, then quantize whatever is still unquantized with the op's per-expert weight quantizers, mirroring module/linear.py's handling of a re-gathered BF16 distributed weight. Native-quantized shards gather as quantized tensors and pass through unchanged. The FC2 backward re-gather moves ahead of the NVFP4 amax / global-scale computation so that path no longer reads un-gathered shards. The per-expert weight quantizer lists are built once in forward and saved on the FC1/FC2 contexts; backward quantizes the re-gathered weights with those rather than reading the live op. A later forward on the same module under a different recipe, or with quantization disabled, resets the ops' quantizers before the earlier backward runs (pipelined microbatches, or a module shared across recipe scopes), which would otherwise hit None or quantize in the wrong format. Regression tests: a fake routed-expert DistributedWeight group whose materialize hooks return BF16 tensors (or MXFP8 tensors for the native-quantized case) drives the CuTeDSL fused grouped MLP under per-module MXFP8, optionally inside a global NVFP4 autocast. Distinct power-of-two scales in the forward/backward hooks make the gathered weights observable: output, dgrad and the main_grad wgrads must match a plain reference bit-exactly up to those scales. A unit check confirms already-quantized gathered weights pass through the helper unchanged. A further case runs a second forward under no recipe or NVFP4 between an MXFP8 forward and its backward and requires bit-exact agreement with a reference. Fails on the unpatched op with AttributeError on _columnwise_data in backward; passes with the fix. Co-Authored-By: Claude Fable 5.1 <[email protected]> Signed-off-by: Xiaowei Ren <[email protected]>
…saved state Every wgrad path reads only the columnwise tiles of the saved FC1/FC2 inputs: the cuDNN grouped wgrad kernel, the single-group dense GEMM (general_gemm with the NT layout unwraps both operands columnwise) and the generic grouped-GEMM fallback (NVFP4 forces a TN layout by taking the columnwise data for a non-transposed A and a transposed B, which is the wgrad case). The save path already pruned the rowwise data and scales for MXFP8 but kept them for NVFP4, citing the generic fallback, so each quantized NVFP4 input was held (and, under activation offloading, copied to host and back) twice. Prune them for NVFP4 as well, unconditionally. The amax tensors are untouched. Per decoder expert layer of a Nemotron hybrid proxy (83k tokens, hidden 3072) this removes a 121 MiB data and a 15 MiB scale tensor from the ~1.9 GiB saved set, with unchanged numerics on both the cuDNN kernel and the forced generic fallback (NVTE_DISABLE_CUTEDSL_WGRAD_FUSED_GROUPED_MLP=1). Adds a saved_tensors_hooks test asserting exactly one FP4 data and one scale tensor is saved per quantized input on the fused NVFP4 path, for group sizes 1 and 4, with token counts chosen so the inputs cannot be confused with weights in the count, and registers it in the L0 unit-test runner. Grouped storage is saved as raw buffers; the single-group dense path (cuDNN frontend >= 1.27) saves a GroupedTensor wrapper whole, so the test inspects the wrapper's buffers directly and requires its rowwise data and scales to be None. Co-Authored-By: Claude Fable 5.1 <[email protected]> Signed-off-by: Xiaowei Ren <[email protected]>
xrennvidia
force-pushed
the
xren/fused_grouped_mlp_gtp_bf16_weight_requant
branch
from
October 18, 2026 09:01
c159f66 to
cb1ffc4
Compare
Collaborator
Author
|
Close because the changes have been cherry-picked into PR3545. |
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.
A distributed (e.g. GTP) weight whose shards are not natively quantized is re-gathered as BF16. The fused grouped-MLP op assumed gathered weights were already quantized: forward quantized the shards before the gather, and backward read _columnwise_data / the NVFP4 amax straight off the gathered tensor, which fails for a module whose per-module recipe (e.g. MXFP8 experts under a global NVFP4 recipe) does not create native-quantized params.
Gather first, then quantize whatever is still unquantized with the op's per-expert weight quantizers, mirroring module/linear.py's handling of a re-gathered BF16 distributed weight. Native-quantized shards gather as quantized tensors and pass through unchanged. The FC2 backward re-gather moves ahead of the NVFP4 global-scale computation so that path no longer reads un-gathered shards.
Description
Please include a brief summary of the changes, relevant motivation and context.
Fixes # (issue)
Type of change
Changes
Please list the changes introduced in this PR:
Checklist: