Repository navigation
Commit 39a5401
[PyTorch] Fix NaN expert weight gradients at num_groups == 1 with SReLU (#3485)
[PyTorch] Take the num_groups == 1 dense shortcuts only when the kernels agree
At num_groups == 1 the fused grouped MLP may quantize and scale-swizzle the token
buffer as ONE dense tensor over `tensor.shape[0]` rows and read it back the same
way. That is coherent only if the cuDNN kernels also write their intermediates
densely over `tensor.shape[0]`, which is what `use_single_group_runtime_offsets`
asks of them -- they then derive M from the runtime tensor shapes rather than from
the offsets.
The two halves of that decision are currently gated differently. The request to
the kernels is already guarded, because it can be refused:
if supports_single_group_runtime_offsets:
fc1_activation_kwargs["use_single_group_runtime_offsets"] = num_groups == 1
but its siblings -- `use_single_group_weight_swizzle`, `use_single_discrete_weight`,
`use_single_group_dense_fc2`, `use_single_group_dense_dgrad`, the dense quantize
and the plain wgrad GEMM -- are gated on `num_groups == 1` alone. So when the
specialization is unavailable, `ScaledSReLU` at any version or any activation on a
cuDNN frontend older than 1.27.0, the kernels pack their output to
`sum(split_sizes)` rows while TE still reads everything densely.
Because the columnwise swizzled MXFP8 scale layout is `[k/128][m/128][32][4][4]`,
with the m-tile as an INNER stride, an m-extent mismatch misindexes every k-tile
past the first: consumer k-tile j reads producer k-tile j*T_c/T_p. The HEAD rows
-- the ones that do belong to the group -- pick up the wrong scale factors, and
high k-tiles read scale memory the producer never wrote. The data is read
correctly; only the scales move, so the error is order 1 and often NaN. Crucially
this is value-independent: zeroing the padded tail does not prevent it, because
the defect is in the indexing rather than in the padding's contents, so a caller
cannot work around it.
Callers may legally pass a token buffer padded past `sum(split_sizes)` -- an MoE
expert-parallel fixed-capacity receive buffer always does, and
`test_grouped_linear_cuda_graph_safe` documents the padded tail as "intentionally
outside every group" and "uninitialized".
Measured on B300 with MXFP8 and a native ScaledSReLU at num_groups == 1, input
padded 512 -> 768 rows, FC1 main_grad against the unpadded result:
before zeroed tail 406528 / 1048576 non-finite
before poisoned tail 406528 / 1048576 non-finite (identical -- not the values)
after either tail 0.0000e+00, bit-identical
control num_groups=2 clean before and after
Every corrected arm also sits at 1.70e-02 against an unfused reference, the MXFP8
fused-vs-unfused noise floor.
Gate the whole shortcut family on the same predicate the kernels use, applying the
guard TE already writes at the sites that were missing it. No new helper: the
binding calls `_cudnn_frontend_supports_single_group_runtime_offsets` directly,
as this file already does at three other sites, and the flag is named
`use_dense_single_group` to match its neighbours. It deliberately does not claim
the group spans the buffer -- that is unknowable here -- only that producer and
consumer will agree on the extent. It is a host-side check
on an activation type and a package version, so it costs nothing and stays CUDA
graph capturable, and it leaves the GLU activations -- which do get the
specialization -- byte-for-byte on their existing fast path. That matters:
removing the shortcuts outright costs a shared expert +6% to +30% of the fused MLP
step (+5-10% at hidden 4096 / ffn 14336, rising to +28-30% at 1024/4096 with few
tokens), measured by CUDA-graph replay against num_groups >= 2 null controls, and
Megatron's FusedSharedExpertMLP builds exactly this path.
In the two grouped-quantize helpers the condition is just `use_dense_single_group`:
`num_groups == 1` is already folded into that flag at both binding sites, and the
`isinstance(quantizer, (MXFP8Quantizer, NVFP4Quantizer))` test was dead because
`fuse_grouped_mlp_ops` only builds this fusion for an MXFP8 or NVFP4 recipe.
All the shortcuts have to move together: quantization layout and kernel indexing
must agree, so enabling a subset pairs a dense consumer with a packed producer and
yields NaN rather than a slowdown. Hence one flag threaded explicitly through the
grouped-quantize helpers and `_compute_grad_params` rather than a predicate per
site.
What this does NOT do: where the specialization is available, producer and
consumer agree and the residual exposure is that the plain wgrad GEMM still
contracts over `logical_shape[0]` rows, summing any padding past
`sum(split_sizes)` into the weight gradient. That part is value-dependent -- a
zeroed tail contributes an all-zero outer product and is bit-exact, verified over
10 launches -- so a caller that zeroes its padding, or passes none, is unaffected.
Closing that gap needs either a device-side masked zeroing of TE's own
intermediate buffers or an explicit per-op dense-single-group contract; neither is
attempted here.
The condition cannot be evaluated at run time: `split_sizes` is device-resident,
so testing `sum(split_sizes) == tensor.shape[0]` forces a device-to-host sync, and
that test exists to keep this flow sync-free and graph-capturable.
tests/pytorch/test_grouped_mlp.py is at baseline: 6 failed, 48 passed, the 6 being
pre-existing nvfp4_rht and cuBLAS-version failures also present on main.
Signed-off-by: Wentao Guo <wg0420@princeton.edu>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: vthumbe1503 <vthumbe@nvidia.com>1 parent 7c6fa59 commit 39a5401
1 file changed
Lines changed: 34 additions & 14 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
239 | 239 | | |
240 | 240 | | |
241 | 241 | | |
| 242 | + | |
242 | 243 | | |
243 | 244 | | |
244 | 245 | | |
245 | | - | |
| 246 | + | |
246 | 247 | | |
247 | 248 | | |
248 | 249 | | |
| |||
270 | 271 | | |
271 | 272 | | |
272 | 273 | | |
| 274 | + | |
273 | 275 | | |
274 | 276 | | |
275 | 277 | | |
| |||
279 | 281 | | |
280 | 282 | | |
281 | 283 | | |
| 284 | + | |
282 | 285 | | |
283 | 286 | | |
284 | | - | |
| 287 | + | |
285 | 288 | | |
286 | 289 | | |
287 | 290 | | |
| |||
690 | 693 | | |
691 | 694 | | |
692 | 695 | | |
| 696 | + | |
693 | 697 | | |
694 | 698 | | |
695 | 699 | | |
| |||
757 | 761 | | |
758 | 762 | | |
759 | 763 | | |
760 | | - | |
| 764 | + | |
761 | 765 | | |
762 | 766 | | |
763 | 767 | | |
| |||
1125 | 1129 | | |
1126 | 1130 | | |
1127 | 1131 | | |
| 1132 | + | |
| 1133 | + | |
| 1134 | + | |
1128 | 1135 | | |
1129 | 1136 | | |
1130 | 1137 | | |
| |||
1195 | 1202 | | |
1196 | 1203 | | |
1197 | 1204 | | |
1198 | | - | |
| 1205 | + | |
1199 | 1206 | | |
1200 | 1207 | | |
1201 | 1208 | | |
| |||
1276 | 1283 | | |
1277 | 1284 | | |
1278 | 1285 | | |
| 1286 | + | |
1279 | 1287 | | |
1280 | 1288 | | |
1281 | 1289 | | |
| |||
1313 | 1321 | | |
1314 | 1322 | | |
1315 | 1323 | | |
| 1324 | + | |
1316 | 1325 | | |
1317 | 1326 | | |
1318 | 1327 | | |
| |||
1360 | 1369 | | |
1361 | 1370 | | |
1362 | 1371 | | |
| 1372 | + | |
1363 | 1373 | | |
1364 | 1374 | | |
1365 | 1375 | | |
| |||
1495 | 1505 | | |
1496 | 1506 | | |
1497 | 1507 | | |
1498 | | - | |
| 1508 | + | |
1499 | 1509 | | |
1500 | 1510 | | |
1501 | 1511 | | |
| |||
1514 | 1524 | | |
1515 | 1525 | | |
1516 | 1526 | | |
1517 | | - | |
| 1527 | + | |
1518 | 1528 | | |
1519 | 1529 | | |
1520 | 1530 | | |
| |||
1551 | 1561 | | |
1552 | 1562 | | |
1553 | 1563 | | |
1554 | | - | |
| 1564 | + | |
1555 | 1565 | | |
1556 | 1566 | | |
1557 | 1567 | | |
| |||
1653 | 1663 | | |
1654 | 1664 | | |
1655 | 1665 | | |
| 1666 | + | |
1656 | 1667 | | |
1657 | 1668 | | |
1658 | 1669 | | |
| |||
1661 | 1672 | | |
1662 | 1673 | | |
1663 | 1674 | | |
| 1675 | + | |
1664 | 1676 | | |
1665 | 1677 | | |
1666 | 1678 | | |
1667 | 1679 | | |
1668 | | - | |
| 1680 | + | |
1669 | 1681 | | |
1670 | 1682 | | |
1671 | 1683 | | |
| |||
1723 | 1735 | | |
1724 | 1736 | | |
1725 | 1737 | | |
1726 | | - | |
| 1738 | + | |
1727 | 1739 | | |
1728 | 1740 | | |
1729 | 1741 | | |
| |||
1764 | 1776 | | |
1765 | 1777 | | |
1766 | 1778 | | |
1767 | | - | |
| 1779 | + | |
1768 | 1780 | | |
1769 | 1781 | | |
1770 | 1782 | | |
| |||
1935 | 1947 | | |
1936 | 1948 | | |
1937 | 1949 | | |
| 1950 | + | |
| 1951 | + | |
| 1952 | + | |
1938 | 1953 | | |
1939 | 1954 | | |
1940 | 1955 | | |
| |||
2041 | 2056 | | |
2042 | 2057 | | |
2043 | 2058 | | |
| 2059 | + | |
2044 | 2060 | | |
2045 | 2061 | | |
2046 | 2062 | | |
| |||
2194 | 2210 | | |
2195 | 2211 | | |
2196 | 2212 | | |
2197 | | - | |
| 2213 | + | |
2198 | 2214 | | |
2199 | 2215 | | |
2200 | 2216 | | |
| |||
2248 | 2264 | | |
2249 | 2265 | | |
2250 | 2266 | | |
2251 | | - | |
| 2267 | + | |
2252 | 2268 | | |
2253 | 2269 | | |
2254 | 2270 | | |
| |||
2353 | 2369 | | |
2354 | 2370 | | |
2355 | 2371 | | |
| 2372 | + | |
2356 | 2373 | | |
2357 | 2374 | | |
2358 | 2375 | | |
| |||
2430 | 2447 | | |
2431 | 2448 | | |
2432 | 2449 | | |
| 2450 | + | |
2433 | 2451 | | |
2434 | 2452 | | |
2435 | 2453 | | |
| |||
2466 | 2484 | | |
2467 | 2485 | | |
2468 | 2486 | | |
| 2487 | + | |
2469 | 2488 | | |
2470 | 2489 | | |
2471 | 2490 | | |
| |||
2491 | 2510 | | |
2492 | 2511 | | |
2493 | 2512 | | |
2494 | | - | |
| 2513 | + | |
2495 | 2514 | | |
2496 | 2515 | | |
2497 | 2516 | | |
| |||
2545 | 2564 | | |
2546 | 2565 | | |
2547 | 2566 | | |
2548 | | - | |
| 2567 | + | |
2549 | 2568 | | |
2550 | 2569 | | |
2551 | 2570 | | |
| |||
2622 | 2641 | | |
2623 | 2642 | | |
2624 | 2643 | | |
| 2644 | + | |
2625 | 2645 | | |
2626 | 2646 | | |
2627 | 2647 | | |
| |||
0 commit comments