Skip to content

[https://nvbugs/6701777] Explicitly exclude nn.LayerNorm from the diffusers NVFP4 presets. - #2402

Merged
kevalmorabia97 merged 2 commits into
NVIDIA:mainfrom
noeyy-mino:noeyy/fix_bug_6701777
Sep 22, 2026
Merged

kevalmorabia97 merged 2 commits into
NVIDIA:mainfrom
noeyy-mino:noeyy/fix_bug_6701777

Conversation

@noeyy-mino

@noeyy-mino noeyy-mino commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

What does this PR do?

Type of change: Bug fix: 6701777

Regression source: "[OMNIML-3349] Add FP8 MHA
quantization support for HuggingFace ViT" (#1289), merged into
0.44.0rc3 via the batch cherry-pick #1350. This PR:

  1. Registers nn.LayerNorm as a QuantModule for the first time
    (modelopt/torch/quantization/nn/modules/quant_layernorm.py),
    intended to let FP8_DEFAULT_CFG's BMM input / LayerNorm output
    quantizer rules apply to ViT.
  2. Removes the prior forced Cast-alignment logic in export_onnx.py
    that used to normalize Q/DQ node dtypes to trt_high_precision_dtype.

Root Cause:
Once nn.LayerNorm became a registered QuantModule, these wildcards
started unintentionally matching norm1.norm inside FLUX's
AdaLayerNormZero block — an elementwise_affine=False LayerNorm with
no learnable weight/bias. Its input got routed through NVFP4 Q/DQ
(emitted as Float32) while its synthesized affine scale remained
native BFloat16, producing the dtype mismatch.

Chosen fix:
Explicitly exclude nn.LayerNorm from the diffusers NVFP4 presets
rather than touching the global QuantModuleRegistry (which ViT FP8
MHA still needs). Add, in both
modelopt_recipes/configs/ptq/presets/diffusers/nvfp4.yaml and
nvfp4_fp8_mha.yaml, after the existing weight/input wildcard rules
(list order matters — later entries override earlier ones):

  • parent_class: 'nn.LayerNorm'
    quantizer_name: '*'
    enable: false

Usage

python examples/diffusers/quantization/quantize.py --model flux-dev --format fp4 --batch-size 2 --percentile 1.0 --alpha 0.8 --quant-algo max --n-steps 20 --quantized-torch-ckpt-save-path /tmp/pytest-of-root/pytest-0/test_diffusers_quant_export_on0/flux-dev-fp4.pt --onnx-dir /tmp/pytest-of-root/pytest-0/test_diffusers_quant_export_on0/flux-dev-fp4 --collect-method default --calib-size 128 --model-dtype BFloat16 --trt-high-precision-dtype BFloat16

trtexec --onnx=/tmp/pytest-of-root/pytest-0/test_diffusers_quant_export_on0/flux-dev-fp4/model.onnx --builderOptimizationLevel=4 --saveEngine=/tmp/pytest-of-root/pytest-0/test_diffusers_quant_export_on0/flux-dev-fp4/model.plan --stronglyTyped --minShapes=hidden_states:1x1024x64,img_ids:1024x3,encoder_hidden_states:1x512x4096,txt_ids:512x3,timestep:1,pooled_projections:1x768,guidance:1 --optShapes=hidden_states:1x4096x64,img_ids:4096x3,encoder_hidden_states:1x512x4096,txt_ids:512x3,timestep:1,pooled_projections:1x768,guidance:1 --maxShapes=hidden_states:1x4096x64,img_ids:4096x3,encoder_hidden_states:1x512x4096,txt_ids:512x3,timestep:1,pooled_projections:1x768,guidance:1

Testing

The above test commands.

Before your PR is "Ready for review"

Make sure you read and follow Contributor guidelines and your commits are signed (git commit -s -S).

Make sure you read and follow the Security Best Practices (e.g. avoiding hardcoded trust_remote_code=True, torch.load(..., weights_only=False), pickle, etc.).

  • Is this change backward compatible?: N/A
  • If you copied code from any other sources or added a new PIP dependency, did you follow guidance in CONTRIBUTING.md: N/A
  • Did you write any new necessary tests?: N/A
  • Did you update Changelog?: N/A
  • Did you get Claude approval on this PR?: N/A

Additional Information

N/A

Summary by CodeRabbit

  • Bug Fixes
    • Improved Diffusers NVFP4 and NVFP4/FP8 MHA quantization presets by excluding LayerNorm modules from quantization.

Signed-off-by: Noey Yang <174223378+noeyy-mino@users.noreply.github.com>
Signed-off-by: Noey Yang <174223378+noeyy-mino@users.noreply.github.com>
@noeyy-mino
noeyy-mino requested a review from a team as a code owner September 11, 2026 09:50
@noeyy-mino
noeyy-mino requested a review from cjluo-nv September 11, 2026 09:50
@coderabbitai

coderabbitai Bot commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: f774d80b-daa7-41c3-8917-cd18e8f851a3

📥 Commits

Reviewing files that changed from the base of the PR and between 59d93af and 42c250f72d219f94da5350d1f6c2b6cee5f4373d.

📒 Files selected for processing (2)
  • modelopt_recipes/configs/ptq/presets/diffusers/nvfp4.yaml
  • modelopt_recipes/configs/ptq/presets/diffusers/nvfp4_fp8_mha.yaml

Included review availability: Your plan provides up to 12 included reviews per hour; 11 remain after this review.


📝 Walkthrough

Walkthrough

The Diffusers NVFP4 presets now disable all quantizers under nn.LayerNorm parent modules.

Changes

Diffusers PTQ preset updates

Layer / File(s) Summary
LayerNorm quantizer exclusions
modelopt_recipes/configs/ptq/presets/diffusers/nvfp4.yaml, modelopt_recipes/configs/ptq/presets/diffusers/nvfp4_fp8_mha.yaml
Both presets add rules that disable quantizers within nn.LayerNorm modules.

Priority: ⬇️ Low

Estimated code review effort: 1 (Trivial) | ~5 minutes

Change: Bug fix

Suggested reviewers: shengliangxu

Merge Risk: ⚪ Minimal · up to 6b69d

The preset-only change is ready to merge; no actionable current-head risk remains.

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Security Anti-Patterns ✅ Passed PASS. The review-scoped diff changes only two YAML quantization presets: modelopt_recipes/configs/ptq/presets/diffusers/nvfp4.yaml and nvfp4_fp8_mha.yaml. The additions only disable quantizers und…
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: excluding nn.LayerNorm from the Diffusers NVFP4 presets. The bug reference provides useful context.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.77%. Comparing base (59d93af) to head (6b69da9).
⚠️ Report is 23 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2402      +/-   ##
==========================================
+ Coverage   71.15%   78.77%   +7.62%     
==========================================
  Files         543      543              
  Lines       64346    64346              
==========================================
+ Hits        45785    50690    +4905     
+ Misses      18561    13656    -4905     
Flag Coverage Δ
examples-diffusers 20.64% <ø> (-0.01%) ⬇️
examples-gpt-oss 13.19% <ø> (+0.02%) ⬆️
examples-hf_ptq 22.19% <ø> (+0.57%) ⬆️
examples-llm_distill 13.26% <ø> (+0.01%) ⬆️
examples-llm_eval 17.10% <ø> (+0.06%) ⬆️
examples-llm_qat 17.44% <ø> (+0.04%) ⬆️
examples-llm_sparsity 15.74% <ø> (-0.01%) ⬇️
examples-megatron_bridge 26.05% <ø> (-0.20%) ⬇️
examples-specdec_bench 12.94% <ø> (+0.02%) ⬆️
examples-speculative_decoding 17.51% <ø> (-0.14%) ⬇️
examples-torch_onnx 21.62% <ø> (-0.03%) ⬇️
examples-torch_trt 14.95% <ø> (+<0.01%) ⬆️
gpu 58.18% <ø> (+25.95%) ⬆️
unit 57.52% <ø> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@ajrasane

Copy link
Copy Markdown
Contributor

I think this might break the TensorRT layer fusion. Could you check what is the latency of the model before and after this change?

@noeyy-mino

Copy link
Copy Markdown
Contributor Author

Hi @ajrasane,

Thanks for pointing this out. I checked the effective configs: both diffusers NVFP4 presets already disable LayerNorm output quantization before this PR. The effective change is therefore disabling the newly enabled NVFP4 input quantizer on LayerNorm; the existing Linear activation/weight QDQ rules remain unchanged.

Test on B100
ModelOpt: 0.44.0rc1, TRT: 10.16.0.
Latency: min = 66.2664 ms, max = 74.1385 ms, mean = 68.1074 ms, median = 67.3542 ms, percentile(90%) = 72.6786 ms, percentile(95%) = 73.2022 ms, percentile(99%) = 74.1385 ms

ModelOpt with this fix, TRT: 11.1.0

2026-09-14 10:34:52 [09/14/2026-02:34:24] [I] Latency: min = 67.0042 ms, max = 72.2706 ms, mean = 68.703 ms, median = 68.0374 ms, percentile(90%) = 70.9759 ms, percentile(95%) = 71.3879 ms, percentile(99%) = 72.2706 ms

The regression came from the newly registered LayerNorm input quantizers being matched by the existing NVFP4 input wildcard. The intent is to restore the pre-regression quantization scope, not to claim that diffusion models cannot support LayerNorm output quantization.

@Edwardf0t1 Edwardf0t1 left a comment

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.

LGTM

@kevalmorabia97
kevalmorabia97 enabled auto-merge (squash) September 16, 2026 20:20
@noeyy-mino noeyy-mino changed the title Noeyy/fix bug 6701777 [https://nvbugs/6701777] Explicitly exclude nn.LayerNorm from the diffusers NVFP4 presets. Sep 17, 2026
@kevalmorabia97
kevalmorabia97 merged commit ee5c256 into NVIDIA:main Sep 22, 2026
82 of 90 checks passed
@chadvoegele chadvoegele added the cherry-pick-done Added by bot once PR is cherry-picked to the release branch label Sep 22, 2026
chadvoegele pushed a commit that referenced this pull request Sep 22, 2026
### What does this PR do?

Type of change: Bug fix: 6701777

Regression source: "[OMNIML-3349] Add FP8 MHA
quantization support for HuggingFace ViT" (#1289), merged into
0.44.0rc3 via the batch cherry-pick #1350. This PR:
  1. Registers nn.LayerNorm as a QuantModule for the first time
     (modelopt/torch/quantization/nn/modules/quant_layernorm.py),
     intended to let FP8_DEFAULT_CFG's BMM input / LayerNorm output
     quantizer rules apply to ViT.
  2. Removes the prior forced Cast-alignment logic in export_onnx.py
that used to normalize Q/DQ node dtypes to trt_high_precision_dtype.

Root Cause:
Once nn.LayerNorm became a registered QuantModule, these wildcards
started unintentionally matching norm1.norm inside FLUX's
AdaLayerNormZero block — an elementwise_affine=False LayerNorm with
no learnable weight/bias. Its input got routed through NVFP4 Q/DQ
(emitted as Float32) while its synthesized affine scale remained
native BFloat16, producing the dtype mismatch.

Chosen fix:
Explicitly exclude nn.LayerNorm from the diffusers NVFP4 presets
rather than touching the global QuantModuleRegistry (which ViT FP8
MHA still needs). Add, in both
modelopt_recipes/configs/ptq/presets/diffusers/nvfp4.yaml and
nvfp4_fp8_mha.yaml, after the existing weight/input wildcard rules
(list order matters — later entries override earlier ones):

  - parent_class: 'nn.LayerNorm'
    quantizer_name: '*'
    enable: false

### Usage

```
python examples/diffusers/quantization/quantize.py --model flux-dev --format fp4 --batch-size 2 --percentile 1.0 --alpha 0.8 --quant-algo max --n-steps 20 --quantized-torch-ckpt-save-path /tmp/pytest-of-root/pytest-0/test_diffusers_quant_export_on0/flux-dev-fp4.pt --onnx-dir /tmp/pytest-of-root/pytest-0/test_diffusers_quant_export_on0/flux-dev-fp4 --collect-method default --calib-size 128 --model-dtype BFloat16 --trt-high-precision-dtype BFloat16

trtexec --onnx=/tmp/pytest-of-root/pytest-0/test_diffusers_quant_export_on0/flux-dev-fp4/model.onnx --builderOptimizationLevel=4 --saveEngine=/tmp/pytest-of-root/pytest-0/test_diffusers_quant_export_on0/flux-dev-fp4/model.plan --stronglyTyped --minShapes=hidden_states:1x1024x64,img_ids:1024x3,encoder_hidden_states:1x512x4096,txt_ids:512x3,timestep:1,pooled_projections:1x768,guidance:1 --optShapes=hidden_states:1x4096x64,img_ids:4096x3,encoder_hidden_states:1x512x4096,txt_ids:512x3,timestep:1,pooled_projections:1x768,guidance:1 --maxShapes=hidden_states:1x4096x64,img_ids:4096x3,encoder_hidden_states:1x512x4096,txt_ids:512x3,timestep:1,pooled_projections:1x768,guidance:1
```

### Testing
 The above test commands.

### Before your PR is "*Ready for review*"

Make sure you read and follow [Contributor
guidelines](https://github.com/NVIDIA/Model-Optimizer/blob/main/CONTRIBUTING.md)
and your commits are signed (`git commit -s -S`).

Make sure you read and follow the [Security Best
Practices](https://github.com/NVIDIA/Model-Optimizer/blob/main/SECURITY.md#security-coding-practices-for-contributors)
(e.g. avoiding hardcoded `trust_remote_code=True`, `torch.load(...,
weights_only=False)`, `pickle`, etc.).

- Is this change backward compatible?: N/A
- If you copied code from any other sources or added a new PIP
dependency, did you follow guidance in `CONTRIBUTING.md`: N/A
- Did you write any new necessary tests?:  N/A
- Did you update
[Changelog](https://github.com/NVIDIA/Model-Optimizer/blob/main/CHANGELOG.rst)?:
N/A
- Did you get Claude approval on this PR?: N/A

### Additional Information
N/A

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved Diffusers NVFP4 and NVFP4/FP8 MHA quantization presets by
excluding LayerNorm modules from quantization.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: Chad Voegele <cvoegele@nvidia.com>
chadvoegele pushed a commit that referenced this pull request Sep 22, 2026
### What does this PR do?

Type of change: Bug fix: 6701777

Regression source: "[OMNIML-3349] Add FP8 MHA
quantization support for HuggingFace ViT" (#1289), merged into
0.44.0rc3 via the batch cherry-pick #1350. This PR:
  1. Registers nn.LayerNorm as a QuantModule for the first time
     (modelopt/torch/quantization/nn/modules/quant_layernorm.py),
     intended to let FP8_DEFAULT_CFG's BMM input / LayerNorm output
     quantizer rules apply to ViT.
  2. Removes the prior forced Cast-alignment logic in export_onnx.py
that used to normalize Q/DQ node dtypes to trt_high_precision_dtype.

Root Cause:
Once nn.LayerNorm became a registered QuantModule, these wildcards
started unintentionally matching norm1.norm inside FLUX's
AdaLayerNormZero block — an elementwise_affine=False LayerNorm with
no learnable weight/bias. Its input got routed through NVFP4 Q/DQ
(emitted as Float32) while its synthesized affine scale remained
native BFloat16, producing the dtype mismatch.

Chosen fix:
Explicitly exclude nn.LayerNorm from the diffusers NVFP4 presets
rather than touching the global QuantModuleRegistry (which ViT FP8
MHA still needs). Add, in both
modelopt_recipes/configs/ptq/presets/diffusers/nvfp4.yaml and
nvfp4_fp8_mha.yaml, after the existing weight/input wildcard rules
(list order matters — later entries override earlier ones):

  - parent_class: 'nn.LayerNorm'
    quantizer_name: '*'
    enable: false

### Usage

```
python examples/diffusers/quantization/quantize.py --model flux-dev --format fp4 --batch-size 2 --percentile 1.0 --alpha 0.8 --quant-algo max --n-steps 20 --quantized-torch-ckpt-save-path /tmp/pytest-of-root/pytest-0/test_diffusers_quant_export_on0/flux-dev-fp4.pt --onnx-dir /tmp/pytest-of-root/pytest-0/test_diffusers_quant_export_on0/flux-dev-fp4 --collect-method default --calib-size 128 --model-dtype BFloat16 --trt-high-precision-dtype BFloat16

trtexec --onnx=/tmp/pytest-of-root/pytest-0/test_diffusers_quant_export_on0/flux-dev-fp4/model.onnx --builderOptimizationLevel=4 --saveEngine=/tmp/pytest-of-root/pytest-0/test_diffusers_quant_export_on0/flux-dev-fp4/model.plan --stronglyTyped --minShapes=hidden_states:1x1024x64,img_ids:1024x3,encoder_hidden_states:1x512x4096,txt_ids:512x3,timestep:1,pooled_projections:1x768,guidance:1 --optShapes=hidden_states:1x4096x64,img_ids:4096x3,encoder_hidden_states:1x512x4096,txt_ids:512x3,timestep:1,pooled_projections:1x768,guidance:1 --maxShapes=hidden_states:1x4096x64,img_ids:4096x3,encoder_hidden_states:1x512x4096,txt_ids:512x3,timestep:1,pooled_projections:1x768,guidance:1
```

### Testing
 The above test commands.

### Before your PR is "*Ready for review*"

Make sure you read and follow [Contributor
guidelines](https://github.com/NVIDIA/Model-Optimizer/blob/main/CONTRIBUTING.md)
and your commits are signed (`git commit -s -S`).

Make sure you read and follow the [Security Best
Practices](https://github.com/NVIDIA/Model-Optimizer/blob/main/SECURITY.md#security-coding-practices-for-contributors)
(e.g. avoiding hardcoded `trust_remote_code=True`, `torch.load(...,
weights_only=False)`, `pickle`, etc.).

- Is this change backward compatible?: N/A
- If you copied code from any other sources or added a new PIP
dependency, did you follow guidance in `CONTRIBUTING.md`: N/A
- Did you write any new necessary tests?:  N/A
- Did you update
[Changelog](https://github.com/NVIDIA/Model-Optimizer/blob/main/CHANGELOG.rst)?:
N/A
- Did you get Claude approval on this PR?: N/A

### Additional Information
N/A

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved Diffusers NVFP4 and NVFP4/FP8 MHA quantization presets by
excluding LayerNorm modules from quantization.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: Chad Voegele <cvoegele@nvidia.com>
chadvoegele added a commit that referenced this pull request Sep 22, 2026
#2438 #2402 #2434 (#2504)

## Cherry-picked PRs

- #2202
- #2317
- #2314
- #2403
- #2203
- #2413
- #2436
- #2451
- #2336
- #2438
- #2402
- #2434

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added Step-3.7 PTQ recipes for routed experts and MLPs using NVFP4,
with FP8 KV-cache support.
  * Added SDXL FP4 quantization with FP8 convolution support.
  * Expanded FP4 ONNX export guidance to include Flux and SDXL.
  * Added BF16 compatibility for FP8 ONNX export.

* **Bug Fixes**
* Improved ONNX handling for large models, external data, metadata,
opsets, and output types.
  * Improved attention quantization and invalid dynamic-scale handling.
* Quantization now reports unmatched weight configurations, with an
override for valid pipeline-parallel workflows.

* **Documentation**
* Updated calibration, ONNX opset, CLI, Step-3.7, and TensorRT-LLM
deployment guidance.
* Updated deployment guidance to use unified Hugging Face exports with
the TensorRT-LLM PyTorch backend.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Zhiyu Cheng <zhiyuc@nvidia.com>
Signed-off-by: Chad Voegele <cvoegele@nvidia.com>
Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
Signed-off-by: Noey Yang <174223378+noeyy-mino@users.noreply.github.com>
Signed-off-by: Ajinkya Rasane <ajinkyaashwin@gmail.com>
Signed-off-by: Yue <yueshen@nvidia.com>
Signed-off-by: yingguo-trt <244492186+yingguo-trt@users.noreply.github.com>
Co-authored-by: Zhiyu <zhiyuc@nvidia.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Ajinkya Rasane <131806219+ajrasane@users.noreply.github.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Codex <codex@openai.com>
Co-authored-by: noeyy-mino <174223378+noeyy-mino@users.noreply.github.com>
Co-authored-by: Ajinkya Rasane <ajinkyaashwin@gmail.com>
Co-authored-by: yueshen2016 <39203804+yueshen2016@users.noreply.github.com>
Co-authored-by: yingguo-trt <244492186+yingguo-trt@users.noreply.github.com>
kevalmorabia97 pushed a commit that referenced this pull request Oct 15, 2026
### What does this PR do?

Type of change: Bug fix

#1289 (in 0.44.0 through #1350) registered `nn.LayerNorm` in
`QuantModuleRegistry` so that FP8 MHA recipes can quantize its output.
As a side effect, presets and recipes that import
`configs/ptq/units/default_disabled_quantizers` and enable a bare
`*input_quantizer` (`INT8_DEFAULT_CFG`, `FP8_DEFAULT_CFG`,
`NVFP4_DEFAULT_CFG`, ...) also quantize every LayerNorm *input*, i.e.
the residual stream (49 extra NVFP4 quantizers in XLM-R large). In ONNX
export this becomes a dynamic quantize in front of `LayerNormalization`
that no GEMM consumes. Weight-only and layer-scoped presets are not
affected.

This adds a `parent_class: 'nn.LayerNorm'` exclusion to
`default_disabled_quantizers`, in the same form as the existing
`nn.BatchNorm*`, `nn.LeakyReLU` and `nn.Embedding` entries. LayerNorm
quantization stays opt-in: the FP8 MHA override in
`examples/torch_onnx/torch_quant_to_onnx.py`, appended after the preset,
enables the LayerNorm output quantizer and already disables the input
quantizer, so its result is unchanged. As with the BatchNorm entries, an
`nn.LayerNorm` subclass registered as its own quant class is not
covered.

#2402 fixed the same regression for the diffusers NVFP4 presets with the
same entry; those presets do not import this unit. Out of scope:
`NVFP4_FP8_MHA_CONFIG`, `model_type/vit/ptq/fp8.yaml` and the diffusers
`fp8`, `int8` and `nvfp4_fp8_conv` presets also skip this unit and still
quantize LayerNorm inputs.

Effect on `BAAI/bge-reranker-v2-m3` (XLM-R large), NVFP4 W4A4 fake quant
(ModelOpt 0.47.0, same as main here), 60 queries × 100 candidates each:

| NVFP4_DEFAULT_CFG (classifier excluded) | Ko-StrategyQA Recall@10 |
same top-1 as FP32 | mean \|logit − FP32\| | MIRACL-ko Recall@10 | same
top-1 | mean \|logit − FP32\| |
|---|---|---|---|---|---|---|
| as is (LayerNorm inputs quantized) | 87.6% | 80% | 0.94 | 91.1% | 80%
| 1.05 |
| LayerNorm quantizers disabled (this PR) | 90.6% | 90% | 0.61 | 94.5% |
87% | 0.66 |
| FP32 | 88.9% | | | 93.4% | | |

### Usage

No API change. A config that wants LayerNorm input quantization adds the
entry after the default exclusions:

```python
cfg = copy.deepcopy(mtq.FP8_DEFAULT_CFG)
cfg["quant_cfg"].append(
    {"parent_class": "nn.LayerNorm", "quantizer_name": "*input_quantizer", "cfg": {"num_bits": (4, 3), "axis": None}}
)
```

### Testing

- New `test_default_presets_keep_layernorm_inputs_unquantized`
(`INT8_DEFAULT_CFG`, `FP8_DEFAULT_CFG`, `NVFP4_DEFAULT_CFG`): fails on
main, passes here.
- `pytest tests/unit/torch/quantization tests/unit/recipe`: 1912 passed,
1 skipped.
- `pytest tests/examples/torch_onnx/test_torch_quant_to_onnx.py -k
"vit_tiny or swin"` (RTX PRO 6000, TensorRT 11.3): the 12 FP8, INT8,
MXFP8 and auto cases pass. The 3 NVFP4 cases fail the same way on main,
in the FP32 NVFP4 export that #2415 fixes, and pass with a local fix for
it.
- `pre-commit run --files` on the changed files: pass.
- End to end: `bge-reranker-v2-m3` with `NVFP4_DEFAULT_CFG` has 0
LayerNorm input quantizers enabled, and its TensorRT engine matches fake
quant (Recall@10 89.8% for both) with the #2415 export fix applied
locally.

### Before your PR is "*Ready for review*"

Make sure you read and follow [Contributor
guidelines](https://github.com/NVIDIA/Model-Optimizer/blob/main/CONTRIBUTING.md)
and your commits are signed (`git commit -s -S`).

Make sure you read and follow the [Security Best
Practices](https://github.com/NVIDIA/Model-Optimizer/blob/main/SECURITY.md#security-coding-practices-for-contributors)
(e.g. avoiding hardcoded `trust_remote_code=True`, `torch.load(...,
weights_only=False)`, `pickle`, etc.).

- Is this change backward compatible?: ❌ New `mtq.quantize` calls with
these presets no longer add LayerNorm input quantizers, as before 0.44.
Saved checkpoints restore unchanged, because restore replays their
stored config. Usage shows how to re-enable them.
- If you copied code from any other sources or added a new PIP
dependency, did you follow guidance in `CONTRIBUTING.md`: N/A
- Did you write any new necessary tests?: ✅
- Did you update
[Changelog](https://github.com/NVIDIA/Model-Optimizer/blob/main/CHANGELOG.rst)?:
✅ Under 0.49.0; I can move the entry if this should go into 0.48.0.
- Did you get Claude approval on this PR?: N/A

### Additional Information

Found while quantizing `BAAI/bge-reranker-v2-m3` to NVFP4; its TensorRT
engine also needs the FP32 NVFP4 export fix in #2415.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Default quantization presets no longer quantize inputs to `LayerNorm`
modules, avoiding added error in residual streams.
* Re-quantize models affected by this change. Recipes that need
`LayerNorm` input quantization can enable it after importing the
relevant preset.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: Hanjun Cho <gkswns0531@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cherry-pick-done Added by bot once PR is cherry-picked to the release branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants