[Common] Fix NVFP4 stochastic rounding on architectures without cvt.rs - #3281
Open
davidkny22 wants to merge 1 commit into
Open
[Common] Fix NVFP4 stochastic rounding on architectures without cvt.rs#3281davidkny22 wants to merge 1 commit into
davidkny22 wants to merge 1 commit into
Conversation
The four e2m1 stochastic rounding helpers gate on ARCH_HAS_STOCHASTIC_ROUNDING, which is sm_100 and sm_103, where the cvt.rs instruction exists. The other branch is NVTE_DEVICE_ERROR, which is printf plus assert(0), and release builds define NDEBUG, so on sm_120 and sm_121 the quantize returns all-zero FP4 data while printing once per thread. Replace that branch with a software e2m1 stochastic rounder that takes 8 random bits per element, the same as the instruction's rbits operand, and follows cvt.satfinite at the edges. Architectures with cvt.rs keep the asm path. Signed-off-by: David Kogan <davidkny22@gmail.com>
Contributor
Greptile SummaryAdds a software E2M1 stochastic-rounding fallback for architectures without Confidence Score: 5/5The PR appears safe to merge, with no concrete correctness or security defects identified in the changed fallback paths or tests. The software path matches the E2M1 grid and satfinite edge behavior, preserves per-element random-bit allocation and scale mapping, and packs values in the same logical order as the existing hardware conversion paths. Important Files Changed
Reviews (1): Last reviewed commit: "Fix NVFP4 stochastic rounding on archite..." | Re-trigger Greptile |
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
NVFP4 quantization with stochastic rounding returns all-zero data on sm_120 and sm_121.
The four e2m1 stochastic rounding helpers gate on
ARCH_HAS_STOCHASTIC_ROUNDING, which isArchSpecific<100>andArchSpecific<103>, matching where thecvt.rsinstruction exists. The other branch isNVTE_DEVICE_ERROR, which isprintfplusassert(0). Release builds defineNDEBUG, so the assert is compiled out, the helper returns its zero-initialized output, and each thread prints:NVFP4BlockScalingsetsstochastic_roundingon gradient quantization by default and_compute_nvfp4_support()reports NVFP4 for every device at compute capability 10.0 or above, so on these parts the default recipe trains on zeroed gradients while the NVFP4 GEMMs themselves work. The message is also not actionable here: the build already usedNVTE_CUDA_ARCHS=121a, andcvt.rsdoes not exist at any feature level on this family.This replaces that branch with a software e2m1 stochastic rounder. It takes 8 random bits per element, which is what
cvt.rs.satfinite.e2m1x4.f32takes from itsrbitsoperand, addsu * stepwherestepis the grid step at that magnitude, and truncates onto the grid, so a value rounds up with probability equal to its fractional position between its two neighbours. Theif constexpris unchanged, so architectures withcvt.rskeep the asm path and nothing else in the helpers moves.The edges follow the PTX ISA text for
.satfinite, undercvt, Floating Point Notes: for.e2m1x4destinations, "NaN results are converted to positive MAX_NORM", and an input above MAX_NORM in absolute value gives "sign-preserved MAX_NORM of the destination format". So NaN gives +6 and overflow gives ±6.A fallback rather than refusing stochastic rounding on these architectures:
_compute_nvfp4_support()already advertises NVFP4 here and the default recipe turns SR on, so a capability gate would replace a silent wrong answer with a hard failure of the default recipe on hardware that otherwise runs it. The fallback keeps recipe parity.The fallback is not bit identical to
cvt.rsand cannot be.cvt.rsaddsrbitsto the mantissa bits the conversion discards and rounds on the carry out; this adds a scaled uniform to the value and truncates. Both are stochastic rounding at the same per-element entropy, and their round-up probabilities agree to the 1/256 that 8 bits resolve. There is nocvt.rsbehaviour on sm_120 or sm_121 to differ from, and stochastic rounding is not reproducible across architectures in any case.Type of change
Changes
transformer_engine/common/util/ptx.cuh: addstochastic_round_fp4_e2m1and use it in the non-cvt.rsbranch ofmul_cvt_bf16_to_fp4_4x_with_stochastic_rounding,mul_cvt_fp32_to_fp4_4x_with_stochastic_roundingandmul_cvt_bf16_to_fp4_8x_stochastic_rounding.transformer_engine/common/transpose/quantize_transpose_vector_blockwise_fp4.cu: the same incvt_fp32_to_fp4_4x_with_stochastic_rounding.tests/pytorch/nvfp4/test_nvfp4_sr_quantize.py: test that every stochastically rounded value sits on one of the two E2M1 grid values that bracket the exact one, and that two draws differ.Checklist:
No documentation changes needed. On the last box, see below.
Testing done
GB10 (DGX Spark), sm_121a, CUDA 13.1, driver 580.95.05, main @ 0ee1320, built with
NVTE_CUDA_ARCHS=121a. clang-format 18.1.6, cpplint 1.6.0 and black 24.4.2 are clean on the changed files, and there are no compiler warnings in the build.The new test is not gated on architecture, so it exercises
cvt.rswhere the instruction exists and this branch here. All four parametrizations fail without the patch and pass with it, on separate unpatched and patched builds of the same tree, twice each. Together they reach three of the four helpers:cvt_fp32_to_fp4_4x_with_stochastic_roundingfor FP32 input,mul_cvt_bf16_to_fp4_8x_stochastic_roundingfor BF16 with 1D scaling, andmul_cvt_bf16_to_fp4_4x_with_stochastic_roundingfor BF16 with 2D. I could not reachmul_cvt_fp32_to_fp4_4x_with_stochastic_roundingfrom any NVFP4 entry point on this hardware; it is the FP32 twin of the same columnwise loop and is fixed the same way.tests/pytorch/nvfp4/test_nvfp4_sr_quantize.pyis 6 failed, 22 passed, 4 skipped with the patch, in 37 seconds. Without it the same file does not finish: I stopped it at 61 minutes, since the error path prints once per thread and this file quantizes 8192x8192 tensors 50 times per case.The 6 that fail are
test_group_stochastic_rounding_quantization_versus_referencewithuse_tex_split_quantize=True, and they are not this path. They fail atgroup_row_cast_col_hadamard_transform_cast_fusion.cu:1276 in function group_row_col_rht_gemm_ntt_w_sfc: CUDA Error: invalid argument, which is the grouped RHT dispatch reported in #3219.tex.split_quantizewith RHT-enabled NVFP4 quantizers raises the same error on an unpatched build of this tree.On one 256x256 BF16 tensor, dequantized cosine against the input is 0.000000 before and 0.990767 after, against 0.995495 for round to nearest on the same tensor. Stochastic rounding sitting slightly below round to nearest on a single draw is the expected direction.
If there is anything else you want checked on sm_121, I can run it.
cc @Oleg-Goncharov @ptrendx