Skip to content

[PyTorch] [torch.compile] torch.compile support for LayerNormLinear and LayerNormMLP - #3534

Open
pggPL wants to merge 39 commits into
NVIDIA:mainfrom
pggPL:layernorm_compile
Open

pggPL wants to merge 39 commits into
NVIDIA:mainfrom
pggPL:layernorm_compile

Conversation

@pggPL

@pggPL pggPL commented Sep 17, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Add full-graph torch.compile support for LayerNormLinear and LayerNormMLP, 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.
  • 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 #3628.

Validation

B100/SM100, PyTorch 2.15.0a0+875d815502.nvinternal.main, CUDA 13.4; existing October 7 native libraries reused, no fresh native build.

  • Focused LayerNorm compile selection: 180 passed, 4 expected skips for unsupported LayerNormMLP backward overrides. Includes full-graph forward/backward, non-matrix inputs, normalization output gradients, variants and eager fallbacks.
  • The selection includes 60 normalization scale-layout cases: both modules, LayerNorm/RMSNorm, MXFP8 and NVFP4, cuDNN settings, shapes, returned norm output, and NVFP4 RHT fusion enabled/disabled.
  • The inherited cold CUDA Graph regression is identical to the version validated in [PyTorch] Fix NVFP4 metadata in compiled Linear operations #3628: 48 passed with an independent eager model and no implicit recipe construction for unquantized inputs.
  • Pre-commit, license, syntax and whitespace checks passed. Full PyTorch Python lint retains an unchanged C0411 import-order diagnostic in attention/fused_mla_q_uproj.py in 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.

…rm modules for compile wiring

Behavior-neutral groundwork for registering LayerNormLinear and LayerNormMLP
as torch.compile custom ops (follows the Linear split NVIDIA#2967 / NVIDIA#3053).

dynamo/custom_op.py:
- A bwd args dataclass may declare GRAD_OUTPUT_FIELDS naming one grad field
  per user output; the LN modules have two differentiable outputs (out and
  the returned norm output), so a single grad_output slot is not enough.
- Dict[str, <simple>] annotations are bundle-simple (activation_params).

module/_common.py: sp_out_leading / sp_inp_leading / fake_workspace_valid
shared by Linear and the LN modules (moved out of linear.py).

layernorm_linear.py / layernorm_mlp.py:
- GRAD_OUTPUT_FIELDS on the bwd args; fp8_output carried in the fwd args.
- inp_shape is rederived from grad_output in backward instead of being
  stored on the bwd args (SymInt dims are not hashable in the value bundle).
- LayerNormMLP: the recipe object no longer rides on the backward args; the
  properties the backward needs (float8_block_scaling, custom, dbias-dact
  fusion availability) are bools computed in Module.forward. The activation
  tables are split into per-activation (act, dact) pairs plus the fused dbias
  kernels so the backward looks them up without a recipe.
- The returned-norm-output grad is tolerated as None in backward.

No functional change.

Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
…nd LayerNormMLP

Register the LayerNormLinear and LayerNormMLP forward/backward as
torch.library custom ops on top of the framework from NVIDIA#3053, so both trace
under fullgraph compile with the FP8/MXFP8/NVFP4 recipes. Builds on the
module restructuring and the framework groundwork in the two preceding PRs.

layernorm_linear.py / layernorm_mlp.py:
- compile_unsupported_reason gate, data-free forward/backward fakes on
  TensorSpec, register_custom_op, @no_torch_dynamo eager wrapper, compiled
  dispatch and eager fallback in Module.forward, mirroring Linear.
- Eager fallbacks: debug, quantized input, fsdp_group, differentiable
  fp8_output, CPU offload, delayed wgrad, FP8 weight caching,
  fuse_wgrad_accumulation, non-opaque quantizers; MLP also activation
  checkpointing and gemm_gelu_fusion under FP8.

tests/pytorch/test_torch_compile.py: LN module coverage (recipes x compile
modes, norm/activation/return_layernorm_output variants, FP8 primary weight,
frozen weights / no bias, dynamic shapes, eager fallbacks).

Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Keep delay-capable stores in eager even while disabled, preserving toggles between forward and backward. Exclude unused queue-free stores from the custom-op arguments so the main branch's unconditional store forwarding does not disable compilation.

Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
…modules"

This reverts commit aa4cde8.

Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Keep configuration fallback checks before prepare_forward and remove their duplicates from the argument bundles. Rename the remaining late check to describe its quantizer-only scope.

Validation: GPU compile regression 135 passed, 3 skipped, 1 xpassed; Pylint 3.3.1 rates all three modules 10/10; Python syntax and diff whitespace checks pass.
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Validate each forward's existing quantizer sequence in one common helper instead of duplicating validation and field lists in three forward argument classes.

Validation: GPU torch.compile regression 135 passed, 3 skipped, 1 xpassed; Pylint 3.3.1 four modules 10/10; Black helper check and diff whitespace check pass.
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Remove the single-use requires_grad_params method and evaluate the same predicate directly in the early compile fallback check. Validated Python syntax and git diff --check.

Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Accept shapes in check_gemm_dims so LayerNormMLP can validate FC2 without materializing its activation input. Derive the activation width and gathered row count for gated activations and sequence parallelism. Update Linear and LayerNormLinear callers to pass shapes.

Validation: existing GPU torch.compile regression 135 passed, 3 skipped, 1 xpassed. One-off GELU and SwiGLU invalid-FC2 probes both reject during tracing before the backend runs. Pylint 3.3.1 rates touched files 10/10; syntax and whitespace checks pass. No test changes.
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Remove the obsolete inp_shape constructor argument and order the packaging import before the TE extension import. Full CI Python lint scope passes with Pylint 3.3.1 (exit 0); the BF16 projection backward matches an FP32 reference on GPU. No test files changed.

Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Restore optional inp_shape for existing eager callers while keeping shape reconstruction local when it is unset. Restore the attention file to main so the PR has no attention changes. Existing compile regression: 135 passed, 3 skipped, 1 xpassed. Full Python lint passes with the local TE extension classified as third-party, matching CI.

Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
@pggPL
pggPL marked this pull request as ready for review September 17, 2026 17:13
@pggPL
pggPL requested a review from ksivaman as a code owner September 17, 2026 17:13
@greptile-apps

greptile-apps Bot commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The changes affect compiled PyTorch module workflows and shared backward paths.

The PR still needs the backward compatibility fix before merging.

Findings

  1. P1 Backward API Compatibility Break ▶

Summary

Adds full-graph torch.compile support for LayerNormLinear and LayerNormMLP.

  • LayerNormLinear runs as a compiled operation with backward support.
  • LayerNormMLP runs as a compiled operation across both matrix steps.
  • Each compiled operation assigns gradients for all its public outputs.
  • Fake tensor descriptions now match normalization and activation outputs.

No new findings were identified in the changes since the previous review.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[LayerNorm module call] --> B{Compile settings supported?}
  B -->|No| C[Eager fallback]
  B -->|Yes| D[Registered forward operation]
  D --> E[Fake outputs describe shapes and buffers]
  D --> F[Real forward saves backward state]
  F --> G[Output gradients]
  G --> H[setup_grad_outputs]
  H --> I[Registered backward operation]
  I --> J[Input and parameter gradients]
Loading

Reviews (14) · Last reviewed commit: "Remove unused LayerNorm compile metadata" · Reviewed by Greptile

bwd_obj.grad_outputs = tuple(user_grads)
else:
bwd_obj.grad_output = user_grads[0]
bwd_obj.setup_grad_outputs(user_grads)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Backward API Compatibility Break

register_custom_op is exported from transformer_engine.pytorch.dynamo, but backward now unconditionally calls setup_grad_outputs. Existing integrations that follow the previous grad_output or grad_outputs field convention can therefore register and compile successfully, then fail with AttributeError during backward. Please preserve the field-based fallback or provide a compatibility default while callers migrate.

Preserve both LayerNorm and OperationFuser compile tests and adapt module registrations to register_custom_op_with_autograd. Validated 156 passing compile tests, 3 skips and 1 xpass, plus full Python lint with the local TE extension classified as third-party to match CI.

Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Store the actual GEMM scale layout independently of the quantizer optimization request. Preserve it when converting real tensors and rebuilding custom-op outputs. Describe the NVFP4 normalization output layout without changing the quantizer configuration.

Parametrize the existing tensor round-trip test with layouts opposite to the quantizer request. Use deterministic NVFP4 for exact module comparisons and skip the backward override unsupported by eager LayerNormMLP.

Validation: 181 passed, 3 skipped, 1 xpassed on Ada; full Python lint and Black pass. NVFP4 allocation and reassembly metadata agree with C++ for RHT and 4over6. Full NVFP4 forward/backward on Blackwell remains pending.
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Comment thread transformer_engine/pytorch/module/layernorm_linear.py Outdated
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Comment thread tests/pytorch/test_torch_compile.py
@ptrendx ptrendx self-assigned this Sep 28, 2026
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Comment thread transformer_engine/pytorch/module/_common.py Outdated
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Describe columnwise FP4 buffers with the flattened 2D shape used by native quantization. Cover 3D and 4D inputs, singleton dimensions, RHT variants, buffer metadata, and compiled forward/backward with CUDA graphs.

Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
pggPL added 5 commits October 12, 2026 16:04
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Preserve the actual scale layout across custom-op boundaries and describe Bias backward output with the native fused-quantization layout. Keep the columnwise storage warning outside tracing. Cover compiled ops.Linear gradients with compact and swizzled scales, including disabled RHT fusion and CUDA Graphs.

Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Exercise current and block FP8, MXFP8, and NVFP4 variants in the existing fresh-process test. Keep scale-layout defaults in create_metadata instead of duplicating them in TensorSpec initialization.

Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Preserve the LayerNorm and inherited Linear shape regressions, share the simplified TensorSpec metadata contract, and adapt fused-attention gradient setup to the LayerNorm custom-op framework.

Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
@greptile-apps

greptile-apps Bot commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

Comments Outside Diff

These findings could not be posted inline.

  • P1 Quantized fake tensors fail transformer_engine/pytorch/dynamo/tensor_spec.py:102 ▶

    When a quantized TensorSpec does not explicitly set with_gemm_swizzled_scales, these lines omit that value from the metadata passed to storage reconstruction. BasicLinear’s fake quantized forward and dgrad paths create such specs, but the MXFP8 and NVFP4 storage constructors require this argument. Tracing therefore fails while assembling the fake tensor, before the compiled operation can run. Please preserve the quantizer-derived default when the field is unspecified while still allowing fake paths to override a known native layout.

@pggPL
pggPL changed the base branch from pgadzinski/fix_nvfp4_compile_nd to main October 12, 2026 15:43
pggPL added 7 commits October 12, 2026 18:54
Skip TE autocast for unquantized inputs and give the eager reference its own model so quantizer usage changes do not invalidate compiled graphs.

Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Use fake_norm for LayerNormLinear and LayerNormMLP, reuse the fused-quantization layout predicate, and cover NVFP4 normalization with RHT fusion enabled and disabled.

Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>
Signed-off-by: Pawel Gadzinski <pgadzinski@nvidia.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants