[Common] row-scaled nvfp4 path: fuse row/col amax into a single TMA-tiled kernel - #3454
Open
cael-ling wants to merge 3 commits into
Open
[Common] row-scaled nvfp4 path: fuse row/col amax into a single TMA-tiled kernel#3454cael-ling wants to merge 3 commits into
cael-ling wants to merge 3 commits into
Conversation
The row-scaled path ran two amax kernels; the columnwise one read global memory column-major (uncoalesced) and dominated runtime. Compute both directions in one kernel that streams 128x128 chunks through shared memory via TMA and reduces columns from SMEM. Gated by fused_amax_supported (BF16, 128-aligned dims); other cases keep the two-kernel path. Set NVTE_NVFP4_FUSED_AMAX=0 to force fallback. Signed-off-by: Cael Ling <caell@nvidia.com>
for more information, see https://pre-commit.ci
Contributor
Greptile SummaryThe PR optimizes row-scaled NVFP4 quantization by replacing separate rowwise and columnwise amax passes with a fused TMA-tiled kernel when the input and output satisfy the supported BF16 and alignment constraints.
Confidence Score: 5/5The PR appears safe to merge, with no outstanding findings or newly introduced issues since the previous review. The previous no-op metadata-preservation finding is resolved, and no code has changed since that review; the fused path now leaves both amax buffers untouched when the no-op flag is set. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Row-scaled NVFP4 quantization] --> B{Columnwise output requested?}
B -- No --> E[Standalone rowwise amax]
B -- Yes --> C{Fused path supported and enabled?}
C -- Yes --> D[Fused TMA row and column amax]
C -- No --> F[Standalone rowwise and columnwise amax]
D --> G[NVFP4 cast and transpose]
E --> G
F --> G
Reviews (3): Last reviewed commit: "[Common] Preserve NVFP4 fused amax buffe..." | Re-trigger Greptile |
13 tasks
The fused wrapper zeroed both amax buffers with an unconditional memset while the kernel returns early on noop[0]==1, so a skipped (graph-replay) call cleared the previously published amax. Replace the memset with a noop-aware zero kernel that returns early on the same flag, matching the standalone kernels' contract. Signed-off-by: Cael Ling <caell@nvidia.com>
cael-ling
marked this pull request as draft
September 7, 2026 06:43
cael-ling
marked this pull request as ready for review
September 7, 2026 07:03
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.
Description
The NVFP4 row-scaled path that was originally proposed in #2931 computes per-row and per-column amax with two separate kernels. This PR fuses both directions into a single kernel that streams 128x128 chunks through shared memory via TMA (coalesced loads) and does the column reduction from SMEM. Amax is an exact max reduction, so results are byte-identical to the two-kernel path. The fused path is used only when the quantize call needs both directions (rowwise + columnwise amax) on a BF16 input with 128-aligned dims; the kernel then produces both amaxes in one pass. Any other case keeps the original two kernels.
NVTE_NVFP4_FUSED_AMAX=0forces the fallback at runtime.Type of change
Changes
compute_fused_amax_kernel(rowwise + columnwise) and its host wrappersfused_amax_supported/compute_fused_amaxinquantize_transpose_nvfp4.cuh.dispatch/quantize.cuh(fwd and bwd) when supported, else fall back to the standalone amax kernels.NVTE_NVFP4_FUSED_AMAXkill switch (default on).Performance
Full-quantize median latency, fused (fused amax + cast) vs (row-wise & columnwise amax + cast), the cast kernel is byte-identical so the delta is the amax step:
Reproduce
Single Blackwell (SM100) GPU.
pytest tests/pytorch/nvfp4/test_nvfp4_quantize_exact.py -k "row_scaled and both_directions"passes; rowwise/columnwise amax and
qx/qx_tmatch the reference exactly.NVTE_NVFP4_FUSED_AMAXenv var (default enabled): set to0to disable the fused path at runtime and fall back to the two standalone amax kernels, no rebuild needed.Checklist: