Repository navigation
Conversation
6 of 8 tasks
pggPL
force-pushed
the
layernorm_compile
branch
from
September 3, 2026 12:42
90f05e3 to
9422845
Compare
pggPL
changed the base branch from
layernorm_compile_refactor
to
layernorm_compile_prep
September 3, 2026 12:42
6 of 8 tasks
pggPL
force-pushed
the
layernorm_compile
branch
from
September 3, 2026 12:49
9422845 to
4cfffaf
Compare
pggPL
force-pushed
the
layernorm_compile
branch
from
September 17, 2026 11:00
4cfffaf to
dc5fe4c
Compare
pggPL
force-pushed
the
layernorm_compile
branch
from
September 17, 2026 16:56
01275cd to
e09c276
Compare
…the fused grouped MLP (NVIDIA#3545) * [PyTorch] Quantize distributed BF16 weights in the fused grouped MLP A distributed (e.g. GTP) weight whose shards are not natively quantized is re-gathered as BF16. The fused grouped-MLP op assumed gathered weights were already quantized: forward quantized the shards before the gather, and backward read _columnwise_data / the NVFP4 amax straight off the gathered tensor, which fails for a module whose per-module recipe (e.g. MXFP8 experts under a global NVFP4 recipe) does not create native-quantized params. Gather first, then quantize whatever is still unquantized with the op's per-expert weight quantizers, mirroring module/linear.py's handling of a re-gathered BF16 distributed weight. Native-quantized shards gather as quantized tensors and pass through unchanged. The FC2 backward re-gather moves ahead of the NVFP4 amax / global-scale computation so that path no longer reads un-gathered shards. The per-expert weight quantizer lists are built once in forward and saved on the FC1/FC2 contexts; backward quantizes the re-gathered weights with those rather than reading the live op. A later forward on the same module under a different recipe, or with quantization disabled, resets the ops' quantizers before the earlier backward runs (pipelined microbatches, or a module shared across recipe scopes), which would otherwise hit None or quantize in the wrong format. Regression tests: a fake routed-expert DistributedWeight group whose materialize hooks return BF16 tensors (or MXFP8 tensors for the native-quantized case) drives the CuTeDSL fused grouped MLP under per-module MXFP8, optionally inside a global NVFP4 autocast. Distinct power-of-two scales in the forward/backward hooks make the gathered weights observable: output, dgrad and the main_grad wgrads must match a plain reference bit-exactly up to those scales. A unit check confirms already-quantized gathered weights pass through the helper unchanged. A further case runs a second forward under no recipe or NVFP4 between an MXFP8 forward and its backward and requires bit-exact agreement with a reference. Fails on the unpatched op with AttributeError on _columnwise_data in backward; passes with the fix. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Xiaowei Ren <xren@nvidia.com> * [PyTorch] Drop NVFP4 rowwise input copies from the fused grouped MLP saved state Every wgrad path reads only the columnwise tiles of the saved FC1/FC2 inputs: the cuDNN grouped wgrad kernel, the single-group dense GEMM (general_gemm with the NT layout unwraps both operands columnwise) and the generic grouped-GEMM fallback (NVFP4 forces a TN layout by taking the columnwise data for a non-transposed A and a transposed B, which is the wgrad case). The save path already pruned the rowwise data and scales for MXFP8 but kept them for NVFP4, citing the generic fallback, so each quantized NVFP4 input was held (and, under activation offloading, copied to host and back) twice. Prune them for NVFP4 as well, unconditionally. The amax tensors are untouched. Per decoder expert layer of a Nemotron hybrid proxy (83k tokens, hidden 3072) this removes a 121 MiB data and a 15 MiB scale tensor from the ~1.9 GiB saved set, with unchanged numerics on both the cuDNN kernel and the forced generic fallback (NVTE_DISABLE_CUTEDSL_WGRAD_FUSED_GROUPED_MLP=1). Adds a saved_tensors_hooks test asserting exactly one FP4 data and one scale tensor is saved per quantized input on the fused NVFP4 path, for group sizes 1 and 4, with token counts chosen so the inputs cannot be confused with weights in the count, and registers it in the L0 unit-test runner. Grouped storage is saved as raw buffers; the single-group dense path (cuDNN frontend >= 1.27) saves a GroupedTensor wrapper whole, so the test inspects the wrapper's buffers directly and requires its rowwise data and scales to be None. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Xiaowei Ren <xren@nvidia.com> * Update transformer_engine/pytorch/ops/fused/grouped_mlp.py Co-authored-by: Tim Moon <4406448+timmoon10@users.noreply.github.com> Signed-off-by: Xiaowei Ren <103958965+xrennvidia@users.noreply.github.com> * [PyTorch] Move the NVFP4 saved-state test into test_grouped_mlp.py The check that the fused grouped MLP saves only the columnwise NVFP4 input tiles lives naturally with the other fused grouped MLP tests. Move it into TestGroupedMLPFusedOp as test_nvfp4_saves_columnwise_inputs_only, drop the standalone file, and remove its separate line from the L0 launcher, which already runs test_grouped_mlp.py. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Xiaowei Ren <xren@nvidia.com> * [PyTorch] Move the fused grouped MLP distributed-weight tests into test_grouped_mlp.py The DistributedWeight dispatch tests for the fused grouped MLP (BF16 and native-quantized shard gather, the quantizer pass-through unit check, and the backward-after-recipe-change regression) move into test_grouped_mlp.py as TestGroupedMLPDistributedWeight, with their fake DistributedWeight helpers. Drop the standalone file and its separate L0 launcher line, which already runs test_grouped_mlp.py. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Xiaowei Ren <xren@nvidia.com> * [PyTorch] Build fused grouped MLP weight quantizer lists lazily The per-expert weight quantizer lists were built unconditionally at the top of the fused grouped MLP forward, costing 2 * num_groups quantizer lookups on every call, including the single grouped weight path that never uses them. Build them only where they are consumed: the discrete-weight FC1/FC2 quantization and the distributed-weight gather-then-quantize sites. Save the full list on the backward context only for distributed weights, which is the one path that re-quantizes in backward; every other path keeps saving just the first expert's quantizer as before. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Xiaowei Ren <xren@nvidia.com> * Apply suggestion from @ksivaman Co-authored-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com> Signed-off-by: Xiaowei Ren <103958965+xrennvidia@users.noreply.github.com> * [PyTorch] Skip columnwise quantization of gathered distributed FC1 weights in forward The forward GEMMs read only the rowwise weight data; the columnwise copy exists for the dgrad GEMM in backward, which reads it from the saved weight. A distributed weight's gathered copy is not saved (the shards are, and backward re-gathers and quantizes columnwise itself), so the columnwise tiles produced in forward were built and immediately discarded. Match the FC2 distributed site and skip them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Xiaowei Ren <xren@nvidia.com> --------- Signed-off-by: Xiaowei Ren <xren@nvidia.com> Signed-off-by: Xiaowei Ren <103958965+xrennvidia@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: Tim Moon <4406448+timmoon10@users.noreply.github.com> Co-authored-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com>
* [PyTorch] Keep None sentinels on the custom op device Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com> * [PyTorch] Remove the sentinel device test Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com> * [PyTorch] Restore the original test file ending Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com> * [PyTorch] Scope the device to custom op result packing Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com> * [PyTorch] Make result device selection easier to read Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com> --------- Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
…3721) * Run minimum-versions build on pushes to main to warm sccache The workflow only runs on pull_request, so sccache's GHA backend stores every object in a PR-scoped cache that other PRs can't read. Running it on pushes to main populates the base-branch scope, which PR runs can restore, so a new PR's first build no longer compiles from scratch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Rt4UYn6zqR9uS7DWNGEBYx Signed-off-by: Apoorva Garg <271577+agarg21@users.noreply.github.com> * Restrict minimum-version workflow token permissions Signed-off-by: Przemek Tredak <ptredak@nvidia.com> --------- Signed-off-by: Apoorva Garg <271577+agarg21@users.noreply.github.com> Signed-off-by: Przemek Tredak <ptredak@nvidia.com> Co-authored-by: Apoorva Garg <271577+agarg21@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Przemek Tredak <ptredak@nvidia.com>
* Support row-only MXFP8 distributed master-weight casts Signed-off-by: xiuhu17 <zhihao.wang@perplexity.ai> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Share the NCCL process group across row-only cast tests Signed-off-by: xiuhu17 <zhihao.wang@perplexity.ai> * Address row-only MXFP8 review and preserve bidirectional performance Signed-off-by: Zhihao Wang <zhihao.wang@perplexity.ai> * Select MXFP8 partial-cast directions from output storage Use columnwise output presence to select partial-cast computation in the common API and PyTorch binding. Require scales for requested columnwise output and ignore them when that output is omitted. Document the contract and cover unused scales, empty shards, and missing required scales in regression tests. Signed-off-by: Codex <codex@openai.com> --------- Signed-off-by: xiuhu17 <zhihao.wang@perplexity.ai> Signed-off-by: Zhihao Wang <zhihao.wang@perplexity.ai> Signed-off-by: Codex <codex@openai.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Codex <codex@openai.com>
…A#3744) Set device during NCCL init in symmetric memory test Signed-off-by: Tim Moon <tmoon@nvidia.com>
…ath (NVIDIA#3649) * [Common][PyTorch] Add NVFP4 row-scaled grouped cast with graph-safe path Single-launch grouped row-scaled NVFP4 cast + fused amax, plus graph-safe amax/cast variants driven by device first_dims/tensor_offsets for capture-once/replay MoE. Wired into PyTorch (ep.nvfp4_group_row_scaled_cast) with C++ and PyTorch capture/replay tests. Signed-off-by: Cael Ling <caell@nvidia.com> * Address review: guard grouped row-scaled cast dispatch and inputs Restrict the FUSED_NVFP4_ROW_SCALED selection to shapes the grouped kernels accept (128-aligned last dim, <= 64 experts) so unsupported requests fall back to the per-expert path. Return early for empty routing, make the graph-safe binding's input contiguous, and reject with_rht/with_2d_quantization/with_amax_reduction on both row-scaled entries. Add regression tests for the four guarded paths. Signed-off-by: Cael Ling <caell@nvidia.com> * Guard row-scaled grouped cast against non-2D, partial, and strided routing The grouped row-scaled cast treats its input as 2D [rows, last_dim] indexed by split counts, so route higher-rank inputs and partial splits (split sum below the row count) to the per-expert path instead of the grouped kernel. Make first_dims and tensor_offsets contiguous in the graph-safe cast so a strided routing view is not misread. Add fallback and strided-routing tests. 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 * Fall back to per-expert cast for mixed NVFP4 row/tensor-scaled splits The bulk NVFP4 split_quantize allocation sizes its amax buffer from the first quantizer's row-scale setting, so a group mixing row-scaled and tensor-scaled quantizers writes per-row amax into a per-tensor buffer and corrupts neighbors. Detect the mixed case and fall back to the unfused per-split path. Signed-off-by: Cael Ling <caell@nvidia.com> * Route row-scaled NVFP4 grouped quantize through nvte_group_quantize Add the kNVTEGroupedRowScaledNVFP4 grouped tensor param and dispatch row-scaled NVFP4 outputs in nvte_group_quantize to the graph-safe amax and cast kernels. Handle row-scaled quantizers in tex.group_quantize. Remove the row-scaled-specific C APIs, the host-split row-scaled cast kernel, tex.nvfp4_group_row_scaled_cast_graph_safe, the ep.py helper, and the fused row-scaled split_quantize path. Add a top-level static_assert for unregistered types in TypeInfo. 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 * Require 128-row experts for uniform row-scaled NVFP4 group_quantize 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 * Fold row-scaled NVFP4 amax into nvte_group_amax Dispatch nvte_group_amax and nvte_group_amax_graph_safe on the output tensor format so that row-scaled NVFP4 outputs get per-row amaxes, and deprecate nvte_group_nvfp4_compute_amax in favor of nvte_group_amax. Rename the row-scaled amax helpers to group_row_amax(_graph_safe). In split_quantize, fall back to unfused allocation and quantization whenever any NVFP4 quantizer is row-scaled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tim Moon <tmoon@nvidia.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix missing include Review suggestion from @greptile-apps Signed-off-by: Tim Moon <tmoon@nvidia.com> * Add missing header include Signed-off-by: Tim Moon <tmoon@nvidia.com> --------- Signed-off-by: Cael Ling <caell@nvidia.com> Signed-off-by: Tim Moon <tmoon@nvidia.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Tim Moon <tmoon@nvidia.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…IA#3596) Support user-provided routing and return expert counts Add RouterComputationInfo and RoutingMapInfo to the JAX MoE API. moe() takes one router_info argument: RouterComputationInfo has TE compute the gate and top-k, while RoutingMapInfo supplies caller-computed expert indices and differentiable routing weights (e.g. DeepSeek-V4 hash routing) and skips TE's router. moe() and _MoEBlock also return global per-expert assignment counts as a fourth output. collect_expert_counts=False skips the associated all-reduce. Signed-off-by: Deep Patel <deepatel@nvidia.com>
* [Common] Keep cuda_driver::call's symbol cache alive through exit rtc::KernelManager's static destructor unloads its CUDA modules through cuda_driver::call. Each instantiation of call caches driver entry points in function-local statics, and those caches are usually first constructed after the KernelManager, so they are destroyed before it. ~Kernel then reads a destroyed unordered_map: with GCC 16's libstdc++ the process segfaults at exit; with GCC 13's it writes into freed memory instead. Allocate the cache and its mutex with new and never destroy them, and add a test that the process exits cleanly after running NVRTC kernels. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Connor Baker <connorb@nvidia.com> * [Common] Never destroy rtc::KernelManager or the fused-attention graph caches Both were function-local statics whose destructors call into CUDA after main returns: ~Kernel unloads modules through the driver, and destroying a cached cuDNN plan that a CUDA graph retains releases a CUDA user object. The CUDA Programming Guide makes any use of CUDA during program termination undefined behavior, and both crashed at exit depending on static destruction order. Allocate both with new and never delete them, as TVMFFIConfigCache::create() and the fused-attention debug registry already do. Both caches only ever insert, so nothing changes while the process runs. Replace tests/pytorch/test_process_exit.py, whose LayerNorm only runs NVRTC kernels while the NVTE_NORM_FWD_USE_CUDNN and NVTE_NORM_BWD_USE_CUDNN switches are off, with MALLOC_PERTURB_=165 for the C++ util tests. UtilTest.NVRTC drives rtc::KernelManager directly, and ctest checks each test's exit status. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Connor Baker <connorb@nvidia.com> --------- Signed-off-by: Connor Baker <connorb@nvidia.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Fix DistributedWeight handling under saved-tensor hooks Signed-off-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com> * Reduce CPU overhead of the DistributedWeight check in prepare_for_saving prepare_for_saving and restore_from_saved run for every tensor every TE module saves, so the DistributedWeight check sits on a hot path for all users, not just GTP. Test None and torch.Tensor first, read the marker with an inline getattr (DistributedWeight implementers must be Tensor subclasses), and only query torch.compiler.is_compiling() for a flagged weight. On restore, test the common None/Tensor case first. On a CPU microbenchmark this brings the non-distributed cost back to roughly main's, e.g. 4.5 -> 5.2 us (was 10.0 us) per prepare_for_saving for a 32-expert bf16 GroupedLinear. Signed-off-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Add saved-tensor hook tests for DistributedWeight modules Port the Linear and GroupedLinear saved-tensor hook tests from NVIDIA#3545 to the prepare_for_saving fix, and extend them: - Run each module case both under identity saved_tensors_hooks and under te.checkpoint(use_reentrant=False), whose pack hook discards saved tensors and returns recomputed ones in backward. - Cover LayerNormLinear, which also gates its backward on the saved weight being a DistributedWeight. - Add CPU-only checks that prepare_for_saving keeps a DistributedWeight by reference and that backward gets the same object back with no hooks, identity hooks, and torch.utils.checkpoint. Co-authored-by: Xiaowei Ren <xren@nvidia.com> Signed-off-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Still use the autograd checker for the dist weight Signed-off-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com> * Error for distweight + torch.compile Signed-off-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com> * Rename _SavedDistributedWeight to _SavedTensorRef and drop premise test Remove test_saved_tensor_hooks_unpack_subclass_as_plain_tensor, which only checked PyTorch's saved-tensor-hook behavior rather than TE's. Signed-off-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Signed-off-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Xiaowei Ren <xren@nvidia.com>
* Remove QB bounds device side validation Signed-off-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com> * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Signed-off-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
* [PyTorch] Test grouped FP8 block-scaling GEMM against the split-tensor path MXFP8 GEMM on Blackwell accumulates at higher precision than FP8 block-scaling GEMM on Hopper. The grouped FP8 block-scaling GEMM tests compared against an FP32 reference, so they passed with the MXFP8 emulation on Blackwell but failed on Hopper. Compare against the legacy split-tensor grouped GEMM instead, consistent with the existing MXFP8 grouped GEMM tests. Also remove the FP8 block-scaling zero-size-expert and mixed-operand tests, which no other recipe has. Signed-off-by: Alp Dener <adener@nvidia.com> * [PyTorch] Test grouped FP8 block-scaling GEMM with uneven and empty experts Dropping the varying splits and the zero-size-expert test left gaps: the remaining tests no longer run grouped FP8 block-scaling GEMM with uneven or empty experts when the weights or outputs are per-expert lists, when accumulating, or when K is not a multiple of 128. Parametrize the grouped FP8 block-scaling GEMM test over uniform, varying and zero-expert splits, checked against the split-tensor reference. Signed-off-by: Alp Dener <adener@nvidia.com> --------- Signed-off-by: Alp Dener <adener@nvidia.com>
NVIDIA#3513) * fix: patch cuda hardcodes for plugin compatibility (complete debug directory coverage) This commit completes the CUDA plugin compatibility patches across the entire codebase: 1. Debug directory (transformer_engine/debug/): - fake_quant.py: Replace is_cuda checks with te_device_type() - log_fp8_tensor_stats.py: Replace torch.device('cuda') and torch.cuda.get_device_capability() - per_tensor_scaling.py: Replace is_cuda checks with te_device_type() - utils/stats_buffer.py: Replace .cuda() calls with .to(te_device_type()) 2. Additional missing files from cuda_patch_rc2.14: - permutation.py: Replace all is_cuda checks with device.type comparisons - tensor/float8_tensor.py: Replace is_cuda checks with device.type comparisons - tensor/float8_blockwise_tensor.py: Replace is_cuda checks with device.type comparisons - tensor/mxfp8_tensor.py: Replace is_cuda checks with device.type comparisons 3. Core infrastructure: - transformer_engine/__init__.py: Export te_platform and te_device_type from pytorch module - transformer_engine/pytorch/__init__.py: Define te_platform() and te_device_type() functions All runtime CUDA hardcodes have been replaced with plugin-compatible abstractions. Total: 64 files modified (+405/-289 lines) Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * fix: remove explicit import to avoid black parsing error The te_platform and te_device_type functions are dynamically assigned to the transformer_engine module namespace via: transformer_engine.te_platform = te_platform transformer_engine.te_platform = te_platform in transformer_engine/pytorch/__init__.py, so explicit imports in transformer_engine/__init__.py cause black to fail parsing due to circular import detection. Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * fix: correct malformed imports that prevent module loading Move te_platform and te_device_type imports outside of parenthesized import lists to fix SyntaxError. The imports were incorrectly placed inside multi-line import statements, preventing the modules from loading. Fixed files: - transformer_engine/debug/features/log_fp8_tensor_stats.py - transformer_engine/pytorch/attention/dot_product_attention/backends.py - transformer_engine/pytorch/attention/dot_product_attention/context_parallel.py - transformer_engine/pytorch/attention/dot_product_attention/dot_product_attention.py - transformer_engine/pytorch/attention/inference.py - transformer_engine/pytorch/graph.py - transformer_engine/pytorch/quantization.py - transformer_engine/pytorch/quantized_tensor.py - transformer_engine/pytorch/transformer.py Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * fix: add missing te_device_type import to files using it Several files imported only te_platform but also called te_device_type(), causing NameError at runtime. Add te_device_type to imports. Fixed files: - transformer_engine/pytorch/attention/dot_product_attention/flex_attention.py - transformer_engine/pytorch/attention/rope.py - transformer_engine/pytorch/cpp_extensions/gemm.py - transformer_engine/pytorch/optimizers/fused_adam.py - transformer_engine/pytorch/utils.py Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * fix: correct malformed imports in additional files Move te_platform and te_device_type imports outside of parenthesized import lists to fix SyntaxError across 20 more files. Fixed files: - transformer_engine/pytorch/attention/dot_product_attention/utils.py - transformer_engine/pytorch/attention/multi_head_attention.py - transformer_engine/pytorch/cpu_offload.py - transformer_engine/pytorch/module/base.py - transformer_engine/pytorch/module/grouped_linear.py - transformer_engine/pytorch/module/layernorm_linear.py - transformer_engine/pytorch/module/layernorm_mlp.py - transformer_engine/pytorch/module/linear.py - transformer_engine/pytorch/ops/basic/basic_linear.py - transformer_engine/pytorch/ops/basic/grouped_linear.py - transformer_engine/pytorch/ops/basic/l2normalization.py - transformer_engine/pytorch/ops/fused/forward_linear_scale_add.py - transformer_engine/pytorch/ops/fused/grouped_mlp.py - transformer_engine/pytorch/ops/fused/userbuffers_backward_linear.py - transformer_engine/pytorch/ops/fused/userbuffers_forward_linear.py - transformer_engine/pytorch/ops/op.py - transformer_engine/pytorch/tensor/nvfp4_tensor.py - transformer_engine/pytorch/tensor/storage/mxfp8_tensor_storage.py - transformer_engine/pytorch/triton/mhc.py - transformer_engine/pytorch/triton/permutation.py Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * fix: use routing_map device instead of hardcoded device type In make_row_id_map, use routing_map.device for tensor allocation instead of te_device_type() to respect the input tensor's device. Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * revert: remove te_platform() replacements, keep te_device_type() Revert all te_platform() method calls back to torch.cuda.* calls. Keep te_device_type() string replacements for device type parameters. Preserve te_platform definition in transformer_engine/pytorch/__init__.py. Changes: - Reverted 146 te_platform() calls back to torch.cuda.* - Removed 'from transformer_engine import te_platform' imports - Kept all te_device_type() replacements intact - Kept te_platform definition in __init__.py for future use Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * fix: remove remaining te_platform() calls in utils, fused_adam, and distributed Replace remaining te_platform() calls with torch.cuda equivalents: - torch.cuda.nvtx.range() / range_push() / range_pop() for NVTX profiling - torch.cuda.amp.autocast for autocast context manager - Update docstring reference in fused_adam.py All te_platform() usage has been removed except for the definition in transformer_engine/pytorch/__init__.py. Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * keep sync with torch.cuda api usage Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * format Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * Fix missing te_device_type imports and import ordering Add the missing `te_device_type` import to eight modules that called it without importing it, which would raise NameError at runtime: jit, attention/inference, attention/dot_product_attention/{backends, context_parallel,utils}, ops/fused/{grouped_mlp, userbuffers_backward_linear}, and triton/mhc. Move the `te_device_type` import ahead of relative imports where pylint classifies it as a first-party import that must precede local ones. In jit and distributed, place it so it does not split the torch import group. Order `transformer_engine_torch` before `transformer_engine` in ops/_common. Add docstrings to `te_device_type` and `te_platform`. Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * Query autocast state and dtype on the same device The device-type patch had changed the autocast dtype lookups to the configured device while leaving the enabled checks on CUDA. With a non-CUDA device type, vendor autocast enabled, and CUDA autocast disabled, these sites took the non-autocast branch and kept the input dtype instead of the requested autocast dtype. Route the operation sites through `maybe_autocast_dtype`, which already queries one device for both calls and carries the torch version guard. This covers the activation, SwiGLU, grouped linear, basic linear, and fused linear forward operations. Add `torch_is_autocast_gpu_enabled` next to `torch_get_autocast_gpu_dtype` for the two sites outside the operation layer that had the same mismatch: `set_activation_dtype`, which sets the activation dtype for every module, and the TransformerLayer forward cast. Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * Gate per-document THD partitioning on CUDA `tex.thd_get_partitioned_indices` allocates a CUDA output tensor and launches a CUDA kernel on the current CUDA stream, so it runs only on CUDA. The device-type patch had changed its dispatch condition to the configured device type, which sent packed sequences into that kernel on a non-CUDA device instead of the device-capable fallback, failing the `is_cuda` assertion before the fallback could run. Restore the CUDA condition in `build_rank_indices` and in `_get_thd_partition_cu_seqlens`, which had the same problem when normalizing the boundaries that feed the kernel, and record why both are gated on CUDA rather than on the configured device. Keep the configured device in the NO_LOAD_BALANCE branch, which builds indices with plain tensor operations and runs no CUDA kernel. Restore the assertion message, which named the device type that triggers it. Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * Drop incidental changes from the device-type patch Narrow the diff against main to the device-type substitutions themselves: - context_parallel.py: remove the comments on the THD partitioning device gates. - cpp_extensions/gemm.py: restore the single-line Float8BlockwiseQTensorStorage import, which did not need wrapping. - graph.py: remove an added blank line, leaving the file unchanged from main. Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * Cover device-type checks missed in recently merged code Two paths reached from main used CUDA device checks where the work below them is not CUDA-specific: - tensor/nvfp4_tensor.py: `NVFP4Tensor` kept CUDA checks in its `record_stream` dispatch and in `copy_`, while the sibling `Float8Tensor`, `MXFP8Tensor`, and `Float8BlockwiseQTensor` classes use the configured device type for the same logic. On another device type `copy_` would move the operand to the destination device and `record_stream` would skip stream tracking. - cross_entropy.py: the input validation rejected non-CUDA tensors even though the Triton backend derives every allocation from the input device and contains nothing CUDA-specific. Leave the checks that guard compiled CUDA kernels, the `device_types` dispatch keys on custom operations, and the `is_cuda` properties that implement the PyTorch tensor contract. Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * Apply plugin device patches after the _nv alias is registered The top-level hook in transformer_engine/__init__.py imported <plugin>.patches before load_framework_extension() registered transformer_engine_torch_nv. A plugin that imports that alias at package level - a case the loader explicitly supports - failed there, and the enclosing except only warned, so apply_patches() never ran. The loader later imported the plugin successfully but never retried the patches, leaving device patches unapplied while vendor calls still went through CUDA. Move the call into load_framework_extension(), after the alias is registered and before the PyTorch submodules capture references to torch.cuda entry points. Probe the submodule with find_spec so a plugin that needs no patches may omit it, without masking real import failures inside an existing patches module. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * Accept the configured device type in the shared forward input check The modules whose `device` argument now defaults to `te_device_type()` allocate their parameters on the configured device, but the `prepare_forward()` input check still rejected anything whose `is_cuda` was false. That property is a tensor attribute, so patching the `torch.cuda` namespace does not change it, and forward raised before a plugin's native operation could run. Compare `device.type` against `te_device_type()` instead, and report the configured device type in the error message. One check covers Linear, LayerNormLinear, GroupedLinear, and LayerNormMLP, which share this base method. Behavior on CUDA is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * Restore the original spacing in the top-level package Removing the plugin hook left an extra blank line behind. Drop it so the file matches main and no longer appears in the diff. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * Skip patch discovery for single-file plugins find_spec() raises ModuleNotFoundError instead of returning None when the parent module is not a package, so a single-file plugin that provides load_plugins() failed the optional-patches probe. The exception handler then disabled the plugin and restored the original extension. Check for __path__ before searching for the submodule. Genuine import failures inside an existing patches module still propagate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * Use the configured device type in GroupedTensor record_stream The merged upstream GroupedTensor stream-tracking handler checked `tensor.is_cuda`, which pins the path to CUDA. Match the device abstraction used by the other quantized-tensor `record_stream` handlers so plugin device types propagate allocator stream tracking. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * Accept the configured device type in the attention input checks The attention entry points asserted `is_cuda` on queries, keys, and values, so a non-CUDA configured device failed validation before any attention implementation could run, even though the surrounding state was already created on the configured device. Check the configured device type instead, in DotProductAttention and in the matching FlashAttention and FusedAttention assertions. Apply the same change to the per-document THD partitioning check in context parallelism, and drop the redundant CUDA half of the mixed-THD sequence_ids check, where the comparison against the Q/K/V device already enforces the documented requirement. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * Keep the paged KV cache and EP buffer on CUDA The paged KV cache page table and the EpBuffer default device fed tensors into torch.library custom ops registered with device_types="cuda". Allocating them on a configured non-CUDA device left no matching registered implementation, so the dispatcher failed the call before the wrapped tex function could run. Restore the CUDA allocations so these tensors match their op registrations, and drop the now-unused imports. Supporting another device on these paths requires changing the op registrations, which depends on how the device is registered with PyTorch and on when the device type is configured relative to module import. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * Apply plugin device patches after the plugin finishes loading apply_patches() rewrites process-global state in place - torch.cuda entry points, TE_DEVICE_TYPE and TE_PLATFORM - with no way to undo it. Running it before load_plugins() meant a load_plugins() failure left those patches active while the except block restored only sys.modules, so import continued with the CUDA extension under a vendor device type and failed later, far from the cause. Run load_plugins() first so everything that can fail is rolled back completely. The patches still precede the PyTorch submodules that capture torch.cuda entry points, and still follow the _nv alias registration that a plugin package may need to import itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> * Fix regex in test_cross_entropy Signed-off-by: Przemyslaw Tredak <ptrendx@gmail.com> --------- Signed-off-by: Xianduo Li <lixianduo@mail.nankai.edu.cn> Signed-off-by: Przemyslaw Tredak <ptrendx@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Przemyslaw Tredak <ptrendx@gmail.com>
* Guard fused MoE auxiliary loss integer offsets Signed-off-by: Srijan Keshri <212402043+arcusbuilds@users.noreply.github.com> * Update tests/pytorch/test_fused_router.py Co-authored-by: Alp Dener <adener@nvidia.com> Signed-off-by: Srijan Keshri <212402043+arcusbuilds@users.noreply.github.com> * Use 64-bit indexing for fused MoE auxiliary loss Signed-off-by: Srijan Keshri <212402043+arcusbuilds@users.noreply.github.com> * Unroll forward row loop in fused MoE aux loss Signed-off-by: arcusbuilds <srijankeshri007@gmail.com> * Revert 64-bit indexing, restore INT_MAX guard in fused MoE aux loss Match the other fused router kernels, which reject num_tokens * num_experts > INT_MAX. Keep #pragma unroll 4 on the forward row loops. Signed-off-by: arcusbuilds <srijankeshri007@gmail.com> * Use 64-bit loop counters in fused MoE aux loss kernels Shapes at the INT_MAX guard (e.g. INT_MAX x 1) overflowed the int loop counters on their last increment and the backward grid-size math. Flattened offsets stay 32-bit, which the guard bounds. Signed-off-by: arcusbuilds <srijankeshri007@gmail.com> --------- Signed-off-by: Srijan Keshri <212402043+arcusbuilds@users.noreply.github.com> Signed-off-by: arcusbuilds <srijankeshri007@gmail.com> Co-authored-by: Alp Dener <adener@nvidia.com>
* rely on recipe object for fusion, reduce cpu overhedads for deciding the grouped tensor path Signed-off-by: Varun Thumbe <vthumbe@nvidia.com> * Keep fusion decisions local to op fuser Signed-off-by: Varun Thumbe <vthumbe@nvidia.com> * Use recipe representation for fusion cache key Signed-off-by: Varun Thumbe <vthumbe@nvidia.com> * Include CUDA device in grouped tensor support cache Signed-off-by: Varun Thumbe <vthumbe@nvidia.com> * Declare derived quantizer settings as recipe fields Signed-off-by: Varun Thumbe <vthumbe@nvidia.com> * Update transformer_engine/pytorch/ops/fuser.py Co-authored-by: Tim Moon <4406448+timmoon10@users.noreply.github.com> Signed-off-by: vthumbe1503 <vthumbe@nvidia.com> * Update transformer_engine/pytorch/module/grouped_linear.py Co-authored-by: Tim Moon <4406448+timmoon10@users.noreply.github.com> Signed-off-by: vthumbe1503 <vthumbe@nvidia.com> * Update transformer_engine/pytorch/ops/basic/grouped_linear.py Co-authored-by: Tim Moon <4406448+timmoon10@users.noreply.github.com> Signed-off-by: vthumbe1503 <vthumbe@nvidia.com> --------- Signed-off-by: Varun Thumbe <vthumbe@nvidia.com> Signed-off-by: vthumbe1503 <vthumbe@nvidia.com> Co-authored-by: Tim Moon <4406448+timmoon10@users.noreply.github.com>
…caled kernels (NVIDIA#3682) Optimize scale swizzle kernels Use optimized rowwise full-width and columnwise chunk kernels for MXFP8 and NVFP4 scales, including multi-tensor swizzling. Keep the 16-byte scale-buffer alignment contract and cover its validation in C++ tests. Choose the rowwise full-width kernel after the fallback grid exceeds one SM wave, based on paired GB200 and VR200 measurements. Signed-off-by: Varun Thumbe <vthumbe@nvidia.com>
Fix GH CI docs Signed-off-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com>
…re (NVIDIA#3698) * [CUDA] Handle THD boundary capacity across CP utility kernels THD metadata can exceed per-block shared memory even when the token tensors are valid. Use device-derived default and opt-in capacities before reading the existing global boundary arrays, without allocating scratch buffers. Centralize staging and normalization so indexing helpers consume consistent boundaries while retaining pre-scaled shared reads. Preserve the current old_lse output-accumulation behavior and exercise its rescaling in boundary regression tests. Focused native validation passed 348 boundary/dtype cases, 60 output-rescaling cases including 24 exact upstream comparisons, 33 graph captures with three replays each, and 324 partition stress cases up to one million documents. SM86 and SM100 compilation passed. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com> * [PyTorch] Guard THD boundary tests on available device limits Older PyTorch builds do not expose the shared-memory properties used to choose exact boundary-test sizes. Check both capabilities inside the two affected tests and skip only those tests when either field is missing, without guessing a version cutoff or querying CUDA during import. Include the running PyTorch version in the skip reason to make compatibility skips identifiable. Production kernels and the remaining functional tests are unchanged. Missing/present-property checks and both targeted native boundary tests passed. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com> * Use runtime storage selection for THD boundary tables Avoid duplicating each dtype, layout, and functor specialization solely for boundary storage. Pass a block-uniform storage flag and plain pointers with an explicit read divisor, preserving shared pre-scaling and immutable global metadata. Use the device-reported default shared-memory budget and the existing global table as fallback, removing kernel-specific opt-in state and the boundary-view type. Retain per-boundary integer division and CP validation, and test the two remaining storage regimes. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com> * Restore compile-time storage selection for THD boundaries Runtime storage selection obscures the shared address space and unit read divisor, adding work to boundary searches. Restore shared/global kernel specializations so the compiler can eliminate global-only normalization from the shared path. Keep plain pointer and explicit divisor arguments instead of the boundary view. Retain the default shared-memory budget, immutable global fallback, and the existing default-boundary regression tests without restoring shared-memory opt-in. Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com> --------- Signed-off-by: Sudhakar Singh <sudhakars@nvidia.com>
* Fail fast on Hopper FA4 backward with affected Quack versions Signed-off-by: Kshitij Lakhani <klakhani@nvidia.com> * Remove redundant Quack guard documentation Signed-off-by: Kshitij Lakhani <klakhani@nvidia.com> --------- Signed-off-by: Kshitij Lakhani <klakhani@nvidia.com> Co-authored-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com>
…DIA#3769) Link tests executables against cpython when CuTeDSL is enabled Signed-off-by: Fred Heinecke <fheinecke@nvidia.com>
Register LayerNorm module forward and backward custom ops with matching fake tensor metadata, shared eligibility checks, and compiled weight caches. Extend the existing compile tests to cover the LayerNorm modules. Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
pggPL
force-pushed
the
layernorm_compile
branch
from
October 29, 2026 12:07
70e4b7d to
83641e8
Compare
This branch has not been deployed
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
Add full-graph
torch.compilesupport forLayerNormLinearandLayerNormMLP, including backward, dynamic batch dimensions and normalization outputs.Targets
main. This branch includes the NVFP4 packed-buffer, TensorSpec and Bias correctness fixes from NVIDIA/TransformerEngine#3628.Changes
Describe forward outputs, saved tensors, aliases and backward gradients for both LayerNorm modules; retain eager fallbacks for unsupported configurations.
Share output-gradient setup and quantizer validation with Linear. Adapt the newly inherited fused-attention backward container to the same gradient setup contract, preserving its existing first-output gradient assignment.
Validate both MLP GEMMs, including gated activations and sequence-parallel dimensions.
Support compiled FP8 weight caching in both LayerNorm modules, following Linear: replace the cache on the first microbatch and reuse it on subsequent microbatches, including both MLP weights. GPU-controlled cache updates and fused wgrad accumulation retain eager fallbacks.
Share the cache regression across Linear, LayerNormLinear and LayerNormMLP, checking independent eager outputs/gradients, cache refresh/reuse, optimizer updates, immediate/deferred backward and CUDA Graph replay.
Describe LayerNorm/RMSNorm output, mean and reciprocal standard deviation through
dynamo.fake.fake_norm, used by both LayerNorm modules. Share the fused-quantization layout predicate with activation output metadata, including the RHT-fusion disable flag and output device; remove duplicate layout helpers. Preserve MXFP8/cuDNN normalization layouts and gathered LayerNormMLP output shapes.Parameterize module compile tests across recipes, shapes and modes, with LayerNorm-specific outputs, gradients and eager fallbacks. Retain the non-matrix Linear regressions and expanded cold CUDA Graph recipe coverage inherited from [PyTorch] Fix NVFP4 metadata in compiled Linear operations NVIDIA/TransformerEngine#3628.
Preserve the native RMSNorm MXFP8 2D scale layout in fake normalization metadata; cover metadata reconstruction and add CustomRecipe MXFP8 2D cases to the compiled normalization scale-layout matrix.
Validation
2026-10-23 RMSNorm follow-up: the new metadata regression detects two failures on the old helper. The corrected selection passes 113 tests, with 83 hardware skips on Ada. The final helper also passes all 32 metadata cases after the lint-only condition refactor. Native MXFP8 2D compiled forward/backward cases are added for supported hardware but remain unverified on Ada. Existing native libraries reused.
2026-10-23, workstation RTX 5880 Ada, PyTorch
2.15.0a0+875d815502.nvinternal.main; existing native libraries reused, no fresh native build:dd02f3f7: fake-versus-real outputs, LayerNorm variants and inherited Linear cache selection: 85 passed, 15 skipped.fused_mla_q_uproj.py:19C0411 import-order diagnostic.Historical validation before this merge/cache extension:
B100/SM100, PyTorch
2.15.0a0+875d815502.nvinternal.main, CUDA 13.4; existing October 7 native libraries reused, no fresh native build.attention/fused_mla_q_uproj.pyin the GPU container; no unrelated source cleanup is included. Pylint on all changed production files passed.No complete compile-suite rerun or distributed TP/SP/Userbuffers validation. The gathered-output test emulates the collective and does not establish multi-GPU correctness.