Uh oh!
There was an error while loading. Please reload this page.
[PyTorch] Fix Test's Reference Implementation of Clamped Swiglu - #3424
Conversation
Signed-off-by: Varun Thumbe <vthumbe@nvidia.com>
vthumbe1503
commented
Aug 25, 2026
/te-ci pytorch |
Greptile SummaryUpdates two PyTorch test reference implementations for clamped SwiGLU to express upper and lower clamping with explicit
Confidence Score: 5/5The PR appears safe to merge because the updated test references preserve the production clamped SwiGLU semantics. The explicit conditional clamps preserve forward values and pass gradients through at the exact limits, matching the production kernel behavior in both changed test paths. Important Files Changed
Reviews (1): Last reviewed commit: "fix clamped swiglu test" | Re-trigger Greptile |
There was a problem hiding this comment.
Do we know why this error started appearing?
I'm suspicious of #3402, which touched the logic for GLU backwards. However, the existing logic also preserved gradients at boundaries. Also, the CI passed for that PR.
#3359 landed exactly when the CI pipelines started failing, but it doesn't seem relevant and it passed CI.
I see that the errors are caused by a recent change in PyTorch. This is a reasonable fix.
Uh oh!
There was an error while loading. Please reload this page.
vthumbe1503
commented
Aug 25, 2026
Errors are pre-existing in main |
Uh oh!
There was an error while loading. Please reload this page.
The grouped kernel is the fused recompute counterpart of ScaledSwiGLU and ScaledClampedQGeGLU, but nothing checked that the two compute the same function. The Python tests covered only shapes and rejections, and the C++ suite compares against its own CPU reference, so both sides could be internally correct while disagreeing with each other. Reuses the reference from test_fusible_ops.py verbatim, including the torch.where formulation from NVIDIA#3424, so this tracks that definition rather than restating it. Per expert the reference comes from that expert's own rows and is quantized with the quantizer the kernel used, so a wrong per-group offset cannot average away. Being at the Python level it also covers the bindings, quantizer flags, grouped split and scale layout that the C++ test skips. The comparison is resolution-level rather than bit-exact, mainly because SiLU goes through tanh.approx.f32, so the two sides already differ before either is quantized. Asserts that e8m0 scales agree to within one step and that dequantized values sit within two MXFP8 code steps of their own 32-row block. Two steps rather than one covers a block whose e8m0 exponents straddle a boundary; measured on GB200 the worst deviation is 0.889 steps, so the kernel stays inside a single step everywhere. Also switches the tests added here to the public te.DType. Signed-off-by: Cael Ling <caell@nvidia.com>
* [Common/PyTorch] Grouped weighted-SwiGLU MXFP8 kernel Add nvte_group_swiglu_quantize, which fuses the weighted SwiGLU activation with columnwise MXFP8 quantization over grouped (MoE) tensors. Signed-off-by: Cael Ling <caell@nvidia.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * [PyTorch] Require contiguous, colocated operands in group_swiglu_quantize Signed-off-by: Cael Ling <caell@nvidia.com> * [PyTorch] Require grouped metadata tensors on the current CUDA device Signed-off-by: Cael Ling <caell@nvidia.com> * [PyTorch] Scope the grouped metadata device check to group_swiglu_quantize Signed-off-by: Cael Ling <caell@nvidia.com> * [Common/PyTorch] Rename to group_scaled_swiglu and speed up the kernel lines up with TE's existing ScaledSwiGLU op, so nvte_group_swiglu_quantize becomes nvte_group_scaled_swiglu, and the kernel header, dispatch, bindings and tests follow. Also makes the kernel actually faster than the unfused path it replaces. Per-token scales are staged through shared memory once per chunk, the output buffer is single-buffered to raise occupancy, and SiLU uses an approximate exp and divide. The activation is quantized to MXFP8 immediately, so the approximation stays far below one FP8 ULP. Signed-off-by: Cael Ling <caell@nvidia.com> * [PyTorch] Add a benchmark for group_scaled_swiglu Times the fused kernel against the unfused path it replaces, with the activation half computed three ways: eager PyTorch, torch.compile, and TE's existing ScaledSwiGLU op. Signed-off-by: Cael Ling <caell@nvidia.com> * [Common/PyTorch] Halve the silu MUFU cost and add clamped scaled SwiGLU Signed-off-by: Cael Ling <caell@nvidia.com> * [Common] Cut the clamped scaled SwiGLU ALU cost Signed-off-by: Cael Ling <caell@nvidia.com> * [PyTorch] Benchmark the clamped kernel against a clamped baseline Signed-off-by: Cael Ling <caell@nvidia.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update transformer_engine/pytorch/csrc/extensions/cast.cpp Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Signed-off-by: vthumbe1503 <vthumbe@nvidia.com> * [Common][PyTorch] Promote the approximate SwiGLU operators to math.h Signed-off-by: Cael Ling <caell@nvidia.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * [PyTorch] Check the grouped scaled SwiGLU against TE's SwiGLU reference The grouped kernel is the fused recompute counterpart of ScaledSwiGLU and ScaledClampedQGeGLU, but nothing checked that the two compute the same function. The Python tests covered only shapes and rejections, and the C++ suite compares against its own CPU reference, so both sides could be internally correct while disagreeing with each other. Reuses the reference from test_fusible_ops.py verbatim, including the torch.where formulation from #3424, so this tracks that definition rather than restating it. Per expert the reference comes from that expert's own rows and is quantized with the quantizer the kernel used, so a wrong per-group offset cannot average away. Being at the Python level it also covers the bindings, quantizer flags, grouped split and scale layout that the C++ test skips. The comparison is resolution-level rather than bit-exact, mainly because SiLU goes through tanh.approx.f32, so the two sides already differ before either is quantized. Asserts that e8m0 scales agree to within one step and that dequantized values sit within two MXFP8 code steps of their own 32-row block. Two steps rather than one covers a block whose e8m0 exponents straddle a boundary; measured on GB200 the worst deviation is 0.889 steps, so the kernel stays inside a single step everywhere. Also switches the tests added here to the public te.DType. Signed-off-by: Cael Ling <caell@nvidia.com> --------- Signed-off-by: Cael Ling <caell@nvidia.com> Signed-off-by: vthumbe1503 <vthumbe@nvidia.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: vthumbe1503 <vthumbe@nvidia.com> Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: Oleg Goncharov <64355998+Oleg-Goncharov@users.noreply.github.com>
Description
Pytorch recently changed their clamp function's autograd behavior in this PR: https://github.com/pytorch/pytorch/pull/191142/changes#diff-e1a04c95c2809af34915952d3c7cc6210fadd2a277af1cfdb4924c74a5795295R121
torch.clamp method's original behavior was derivative = 1 at the clamp boundary. Now they changed it to be 0 instead.(I think one of the reasons is consistency of relu operation which has also produces zero derivative at boundary=0)
This PR changes the reference implementation of clamped swiglu in pytorch to use torch.where() to explicitly define the boundary gradient
Fixes # (issue)
Type of change
Changes
Please list the changes introduced in this PR:
Checklist: