Repository navigation
Conversation
cdea1fb to
2192442
Compare
1dea708 to
084777f
Compare
[Medium impact] The change affects BF16 grouped MoE MLP training on a limited set of supported systems. The PR still needs to preserve supported input and routing-scale shapes before merging. FindingsSummaryAdds a BF16 fused grouped MLP path for Blackwell using cuDNN Frontend canonical layouts.
Diagram%%{init: {'theme': 'neutral'}}%%
flowchart LR
A[GroupedLinear + scaled GLU + GroupedLinear] --> B{BF16 fusion supported?}
B -->|No| C[Unfused operations]
B -->|Yes| D[FC1 + GLU]
D --> E[FC2]
E --> F[Backward: dGLU and input gradients]
F --> G[Shared weight-gradient helper]
Reviews (3) · Last reviewed commit: "Review feedback fixes" · Reviewed by Greptile |
| input_ = input_.reshape(-1, fc1_weight_shape[1]) | ||
| in_shape = list(input_.size()) | ||
| total_tokens = in_shape[0] |
There was a problem hiding this comment.
The BF16 path flattens input_ before recording in_shape. A supported input shaped [2, 256, hidden] therefore returns [512, out_features] instead of [2, 256, out_features]. Backward also returns a flat input gradient, which can fail because its shape does not match the input. The unfused GroupedLinear preserves the leading dimensions.
Save the original shape before flattening, and restore it for both the output and input gradient.
Knowledge Base Used: PyTorch tensor and operator abstractions
There was a problem hiding this comment.
Guards to input/scale tensors are added.
| if not unit_activation_scale: | ||
| grad_scales = fc2_dgrad_kernel_out["dprob_tensor"] | ||
| if grad_scales is not None: | ||
| grad_scales = grad_scales.to(dtype=dtype) |
There was a problem hiding this comment.
Routing gradients have wrong shape
The BF16 path flattens the activation’s scales and returns grad_scales without restoring their original shape. For a [512, hidden] input with trainable scales shaped [2, 256], forward succeeds but backward returns a [512] scale gradient, which autograd rejects. The unfused activation accepts this scales shape and preserves it in the gradient.
Save the scales’ original shape and reshape their gradient before returning it.
Knowledge Base Used: PyTorch tensor and operator abstractions
There was a problem hiding this comment.
Guards to input/scale tensors are added.
timmoon10
left a comment
There was a problem hiding this comment.
Overall LGTM, pending CI. It may be worth dealing with Greptile's comments by erroring out if the input tensors is not 2D and the scale tensor is not 1D.
|
/te-ci pytorch |
Signed-off-by: tingyangk <tingyangk@nvidia.com>
… and allocate the wgrad buffer directly Signed-off-by: tingyangk <tingyangk@nvidia.com>
…FC2 scale_bias Signed-off-by: tingyangk <tingyangk@nvidia.com>
Signed-off-by: tingyangk <tingyangk@nvidia.com>
fe8c024 to
3f5cf8c
Compare
Description
Adds an unquantized (BF16) fused path for the MoE grouped MLP
GroupedLinear → ScaledSwiGLU/ScaledClampedQGeGLU → GroupedLinear. Until nowNVTE_CUTEDSL_FUSED_GROUPED_MLP=1fused only MXFP8/NVFP4. Without a block-scaled recipe the MLP ran as three separate ops.The implementation uses cuDNN Frontend CuTeDSL grouped-GEMM kernels for forward, dgrad/dGLU, and wgrad on Blackwell. It requires cuDNN Frontend ≥ 1.32.0 with canonical BF16 layout support.
Thanks @hwanseoc for the help on N-major dgrad weights and direct weight-gradient allocation optimizations (hwanseoc#4).
Type of change
Benchmarks
Unfused vs. fused, Qwen3.5-397B-A17B per-GPU shape
Benchmarked on one B300 using the per-GPU workload for EP32: 16 local experts, hidden size 4096, expert FFN size 1024 with SwiGLU, and 2,560 rows per expert (40,960 tokens total).
The benchmark uses BF16 eager execution with TE from this branch, cuDNN Frontend 1.32.0 (
developat87531690), and NGC PyTorch 26.09. Times are CUDA-event GPU times: the median of 7 trials × 50 iterations, with 3 interleaved rounds per configuration.At the target shape, fusion improves forward performance by 1.075–1.084× and backward performance by approximately 1.065×. End-to-end training-step throughput improves by 1.065–1.068×. Packed and per-expert weights show nearly identical fused performance.
Token-load sweep
The following sweep uses per-expert weights and measures the complete training step:
The fused speedup remains stable as token load increases, reaching 1.066× at 8,192 rows per expert.
Testing
Added coverage for:
Checklist: