[PyTorch] Add ScaledTanhSReLU and wire it into the fused grouped MLP - #3463
Open
wanyingw wants to merge 1 commit into
Open
[PyTorch] Add ScaledTanhSReLU and wire it into the fused grouped MLP#3463wanyingw wants to merge 1 commit into
wanyingw wants to merge 1 commit into
Conversation
Collaborator
|
/te-ci pytorch |
wanyingw
marked this pull request as ready for review
September 2, 2026 17:43
Contributor
Greptile SummaryAdds the
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[GroupedLinear] --> B[ScaledTanhSReLU]
B --> C[GroupedLinear]
B --> D{Both cuDNN wrappers accept tanh_clamp_scale?}
D -->|Yes| E[Fused grouped GEMM forward and backward]
D -->|No| F[Unfused PyTorch activation path]
Reviews (4): Last reviewed commit: "[PyTorch] Add ScaledTanhSReLU and wire i..." | Re-trigger Greptile |
timmoon10
approved these changes
Sep 2, 2026
| ) | ||
|
|
||
|
|
||
| def fuse_srelu_ops( |
Member
There was a problem hiding this comment.
Nit: Beyond the scope of this PR, but we're seeing that the SReLU naming scheme was short-sighted. The underlying kernel should be able to support any unary activation (normal ReLU, sigmoid, whatever), and SReLU just happened to be the first one. At some point we should change to something like fuse_grouped_mlp_ops_with_unary_activation.
Collaborator
|
LGTM |
wanyingw
force-pushed
the
srelu-tanh-clamp
branch
2 times, most recently
from
September 2, 2026 20:30
9247701 to
effdfe8
Compare
Adds a tanh soft-clamped squared ReLU activation alongside ScaledSReLU:
y = (s * tanh(relu(x) / s))^2 * scales
ScaledTanhSReLU is a sibling of ScaledSReLU under _ScaledUnary, not a
subclass, matching how ScaledSiTUGLU sits beside the other gated ops.
That choice costs explicit handling at each place the fused grouped MLP
tests for the SReLU family, so all six were audited:
extended, because a sibling would otherwise misbehave:
* _cudnn_frontend_supports_single_group_runtime_offsets -- the srelu and
dsrelu wrappers take no use_single_group_runtime_offsets argument, so
the whole family must be excluded or the single-group (shared expert)
path passes an unexpected kwarg.
* validate_grouped_mlp_dims -- otherwise falls through to the GLU branch
and raises TypeError on a valid configuration.
* the NVFP4 fc2 alpha in fuser_backward -- dsrelu applies alpha once and
needs the full product; the gated kernels need sqrt(product). A sibling
would silently take the sqrt branch and scale the gradient wrong.
* fuse_srelu_ops' activation_op_types, gated on the cuDNN feature check.
deliberately left as ScaledSReLU only, with the reasoning in comments:
* the NVFP4 RHT hadamard gate -- the kernel it selects is the GLU hadamard
wrapper, which has no soft-clamp support, so routing tanh-SReLU through
it would compute an unclamped activation. The cost is that NVFP4 RHT
gives up hadamard fusion here; the generic quantize path handles it.
* activation recomputation -- falls back to saving fc2_x, which costs
memory but stays correct.
The unfused path is implemented in torch: the scaled-unary CUDA kernels are
parameterless for SReLU, and this activation has no fused kernel yet. It
only serves non-SM100 and unfused configurations; the fused path goes
straight to the cuDNN epilogue. A CUDA functor pair can follow.
Feature detection is by wrapper signature rather than version so this can be
developed against an editable cuDNN frontend; both the forward and backward
wrappers must accept tanh_clamp_scale, since a frontend with only the forward
clamp would train against an unclamped backward. If the check fails the fuser
declines and construction raises -- the clamp is never silently dropped.
Signed-off-by: Wanying Wang <wanyingw@nvidia.com>
wanyingw
force-pushed
the
srelu-tanh-clamp
branch
from
September 2, 2026 20:34
effdfe8 to
e28c0cc
Compare
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
Adds a new activation op
ScaledTanhSReLU— a tanh soft-clamped squared ReLU withper-row post-scaling — and wires it into the fused grouped MLP
(
GroupedLinear + activation + GroupedLinear→ cuDNN grouped GEMM):ScaledSReLUis thes → ∞limit and is left completely untouched.Motivation: this activation is rolling out in Megatron-Core MoE models, where it currently runs as a standalone elementwise kernel between the two grouped GEMMs. The cuDNN frontend srelu/dsrelu grouped GEMM kernels now accept a
tanh_clamp_scaleparameter (cuDNN frontend PR: NVIDIA/cudnn-frontend#858); this PR exposes it through TE.Dependencies: cuDNN frontend with
tanh_clamp_scaleingrouped_gemm_srelu_wrapper_sm100/grouped_gemm_dsrelu_wrapper_sm100(cuDNN FE PR: NVIDIA/cudnn-frontend#858). Feature detection is by wrapper signature, not version, so this PR is safe to merge before the frontend release: without clamp support the fuser simply declinesScaledTanhSReLUand construction raises, the clamp is never silently dropped. A min-version gate constant will follow once the frontend release ships. Follows the SiTU-GLU integration pattern (#3402).Type of change
Changes
ops/basic/activation.py: newScaledTanhSReLU(clamp_scale=...)— a sibling ofScaledSReLUunder_ScaledUnary(not a subclass), mirroring howScaledSiTUGLUsits beside the other gated ops. The unfused path is implemented in torch: the scaled-unary CUDA kernels are parameterless for SReLU, and this path only serves non-SM100 / unfused configurations. A CUDA functor pair can follow.ops/fused/grouped_mlp.py: passtanh_clamp_scaleto the cuDNN srelu (forward) and dsrelu (backward) wrappers when the activation isScaledTanhSReLU. The feature check requires both wrappers to accept the parameter — a frontend with only the forward clamp would train against an unclamped backward.validate_grouped_mlp_dims, the single-group-runtime-offsets exclusion, the NVFP4 fc2 alpha infuser_backward(dsrelu applies alpha once — a sibling falling into the gated-kernel sqrt branch would scale the gradient wrong), andfuse_srelu_ops'activation_op_types(gated on the feature check).ScaledSReLU-only, with reasoning in comments: the NVFP4 RHT hadamard gate (its kernel has no clamp support; the generic quantize path handles it) and activation recomputation (falls back to saving fc2_x — costs memory, stays correct).test_grouped_mlp.pyandtest_fusible_ops.py; existingScaledSReLUtests pass unmodified.Checklist
Testing
On GB300 (sm_103): released cuDNN-frontend wheel with the frontend branch's Python overlaid (the srelu/dsrelu kernels are CuTe DSL, JIT-compiled at runtime, so no frontend rebuild is needed), and the prebuilt TE wheel with this branch's
pytorch/ops/overlaid (this change is pure Python).pytest tests/pytorch/test_fusible_ops.py tests/pytorch/test_grouped_mlp.py -k "tanh_srelu or scaled_srelu": 49 passed / 66 skipped / 0 failed, including:ScaledSReLUcases passing unmodified.Fixes # (issue)
Type of change