[6078291][OMNIML-3716] Add ViT FP8 + Torch-TRT example, wire softmax_quantizer in _QuantAttention#1569
Conversation
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds an end-to-end ModelOpt -> Torch-TensorRT PTQ deployment example for HuggingFace ViT (FP8/NVFP4), two PTQ recipes, an accuracy evaluation script, documentation and requirements, an integration test, CI/ownership updates, and a softmax quantization fix for HuggingFace attention. ChangesViT PTQ Torch-TensorRT Deployment
🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers:
🚥 Pre-merge checks | ✅ 5 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1569 +/- ##
===========================================
+ Coverage 61.17% 76.98% +15.81%
===========================================
Files 515 515
Lines 57207 57216 +9
===========================================
+ Hits 34994 44046 +9052
+ Misses 22213 13170 -9043
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
examples/torch_trt/torch_tensorrt_ptq.py (1)
277-294: ⚡ Quick winArgmax "match" results are informational only — the example never fails on a mismatch.
fq_match/trt_matchare computed and printed but never used to exit non-zero. The e2e test docstring (test_torch_tensorrt_ptq.py, Lines 44-46) claims the CLI "exits non-zero ... if the compiled-model argmax doesn't match the fake-quant argmax", but as written the test only validates that the pipeline runs to completion. Either enforce the check here or correct the test docstring.Note: also worth deciding intent — the comparison is against
baseline_pred(BF16), while the docstring/README phrase it as matching the fake-quant argmax. If you do enforce, be cautious: a tiny--no_pretrainedmodel under NVFP4 can legitimately flip argmax on random input, so a hard gate may be flaky for that path.♻️ One option: gate the run on mismatch
trt_match = (trt_pred == baseline_pred).all().item() print(f"TRT argmax class: {trt_pred.tolist()} (matches baseline: {trt_match})") + if not trt_match: + raise SystemExit("Torch-TensorRT argmax did not match the BF16 baseline.")🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/torch_trt/torch_tensorrt_ptq.py` around lines 277 - 294, The script currently computes fq_match and trt_match but doesn't fail on mismatch; update the run to enforce non-zero exit when mismatches occur: after computing fq_match/trt_match, if fq_match is False or trt_match is False, log an error with context (include fq_pred, trt_pred, baseline_pred) and call sys.exit(1). Locate the checks around fq_pred/baseline_pred and trt_pred (symbols: fq_pred, fq_match, trt_pred, trt_match, baseline_pred, ViTLogitsWrapper, compile_with_torch_tensorrt) and add the exit-on-mismatch logic (or, if you prefer the other approach, instead update the test/docstring to accurately state that mismatches are informational rather than failing).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@examples/torch_trt/torch_tensorrt_ptq.py`:
- Around line 277-294: The script currently computes fq_match and trt_match but
doesn't fail on mismatch; update the run to enforce non-zero exit when
mismatches occur: after computing fq_match/trt_match, if fq_match is False or
trt_match is False, log an error with context (include fq_pred, trt_pred,
baseline_pred) and call sys.exit(1). Locate the checks around
fq_pred/baseline_pred and trt_pred (symbols: fq_pred, fq_match, trt_pred,
trt_match, baseline_pred, ViTLogitsWrapper, compile_with_torch_tensorrt) and add
the exit-on-mismatch logic (or, if you prefer the other approach, instead update
the test/docstring to accurately state that mismatches are informational rather
than failing).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: aea38a8d-a5f8-44cf-8b02-9e7a700116ba
📒 Files selected for processing (8)
CHANGELOG.rstexamples/torch_trt/README.mdexamples/torch_trt/requirements.txtexamples/torch_trt/torch_tensorrt_ptq.pymodelopt/torch/quantization/plugins/huggingface.pymodelopt_recipes/huggingface/vit/ptq/fp8.yamlmodelopt_recipes/huggingface/vit/ptq/nvfp4.yamltests/examples/torch_trt/test_torch_tensorrt_ptq.py
cjluo-nv
left a comment
There was a problem hiding this comment.
Bot review — DM the bot to share feedback.
Bug-fix portion has a regression risk on hosts that have the optional kitchen package installed: _init_kitchen_attn_fn runs before the new non-kitchen FP8 softmax path and raises NotImplementedError for any non-MXFP8 softmax quantizer. The new ViT FP8/NVFP4 recipes both enable plain E4M3 FP8 on *softmax_quantizer, so on a kitchen-equipped GPU they will fail before the new patched-softmax code path is reached. The new test uses importorskip("torch_tensorrt") but does not skip when kitchen is also installed, so this gap isn't caught in CI. Otherwise the design is reasonable (this is "new example + tuned recipes + 11-line plugin fix" rather than a new subsystem; the deterministic complexity gate fired only because of directory count) and the recipes/example look correct.
| # From the NVIDIA TensorRT docker image (recommended): | ||
| docker run --gpus all -it --rm -v $(pwd):/workspace -w /workspace nvcr.io/nvidia/tensorrt:26.02-py3 bash | ||
|
|
||
| pip install -U "nvidia-modelopt[torch]" |
There was a problem hiding this comment.
| pip install -U "nvidia-modelopt[torch]" | |
| pip install -U "nvidia-modelopt" |
cjluo-nv
left a comment
There was a problem hiding this comment.
Bot review — DM the bot to share feedback.
Re-review — several previously-flagged issues still unresolved in the latest diff.
Critical, still present:
- Kitchen-vs-FP8 ordering bug in
_QuantAttention._quantized_attention(cjluo-nv's earlier review). On hosts with thekitchenpackage installed,_init_kitchen_attn_fnruns before the new non-kitchen softmax path and raisesNotImplementedErrorwheneversoftmax_quantizer.is_enabledis True and the quantizer is not MXFP8. Both new ViT recipes enable plain E4M3 FP8 on*softmax_quantizer, so calibrating either recipe on a kitchen-equipped GPU will fail atmtq.quantizetime before the new wrapper-softmax branch is reachable. The new branch'sif not self.use_kitchenguard is dead code in exactly the configuration this PR ships. Fix in_init_kitchen_attn_fn(don't setuse_kitchen=Trueand don't raise for non-MXFP8 — just fall through to the new wrapper path), or skip kitchen init entirely when the quantizer isn't MXFP8. - CI gap reinforces the above: the new test only
importorskipstorch_tensorrt, notkitchen, so the regression mode isn't exercised in isolation either. Either fix the underlying ordering bug or add aif kitchen is not None: pytest.skip(...)guard. tests/examples/torch_trt/is not wired into.github/workflows/example_tests.yml(kevalmorabia97). I confirmed the workflow file still has the matrix[llm_distill, llm_qat, llm_sparsity, diffusers_sparsity]with notorch_trtentry, so the new e2e test won't run in CI even on PRs that touch it. The "tested in CI" claim in the PR body is currently not true onmain.
Minor, still unaddressed (verified against current diff):
examples/torch_trt/README.md:19still haspip install -U "nvidia-modelopt[torch]"; reviewer asked for"nvidia-modelopt".examples/torch_trt/requirements.txt:3still pinstransformers>=4.40; reviewer asked for>=4.56.examples/torch_trt/is missing from.github/CODEOWNERS— confirmed not added in this PR.- The "argmax must match" claim in the test docstring (lines 44-46) is still informational only —
fq_match/trt_matchintorch_tensorrt_ptq.py(lines 277-294) are printed but never gate exit status, so the test passes whenever the pipeline runs to completion regardless of correctness. Either enforce the check (carefully — small--no_pretrainedNVFP4 runs can flip argmax legitimately) or correct the docstring.
Design note: The deterministic complexity gate fired on directory count (5 dirs), but cjluo-nv correctly characterized this as "new example + tuned recipes + 11-line plugin fix" rather than a new subsystem. Recipes reuse the existing YAML recipe loader (modelopt.recipe.load_recipe / ModelOptPTQRecipe) and don't introduce a new abstraction. Design is fine; the blockers above are correctness/CI-coverage, not architecture.
Additional comments (outside the PR diff):
.github/workflows/example_tests.yml:38— > Bot comment.
Still missing torch_trt from the example matrix (kevalmorabia97 raised this previously). Without an entry here, tests/examples/torch_trt/test_torch_tensorrt_ptq.py is not run in CI on PRs that touch examples/torch_trt/ or modelopt/torch/quantization/plugins/huggingface.py, so the PR-body claim of 2 parametrized cases passing is hand-verified-only. Add torch_trt to the appropriate matrix (looks like the onnx group, since both run under nvcr.io/nvidia/tensorrt:26.02-py3).
.github/CODEOWNERS:49— > Bot comment.
Still missing /examples/torch_trt (kevalmorabia97). Add an entry alongside the other example owners so PRs touching this directory get the right reviewers.
7db9fad to
33366a8
Compare
There was a problem hiding this comment.
Warning
CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.
Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/torch_trt/torch_tensorrt_accuracy.py`:
- Around line 145-148: The help text for the "--baseline" CLI flag says the
baseline is BF16 but the code sets dtype = torch.float16; update them to match:
either change the argparse help for "--baseline" to say "FP16" if you intend
dtype=torch.float16, or change the dtype selection logic so that when the
baseline flag is used it sets dtype = torch.bfloat16; ensure the variable name
dtype and the "--baseline" flag (and any reporting code that prints the baseline
precision) are consistent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: c5b7ad31-84f2-45e3-bf4e-31e4d002ac8d
📒 Files selected for processing (3)
examples/torch_trt/torch_tensorrt_accuracy.pymodelopt_recipes/huggingface/vit/ptq/fp8.yamlmodelopt_recipes/huggingface/vit/ptq/nvfp4.yaml
cjluo-nv
left a comment
There was a problem hiding this comment.
Bot review — DM the bot to share feedback.
Re-review: all previously-flagged critical issues are resolved.
- Kitchen-vs-FP8 ordering bug fixed in
_init_kitchen_attn_fn: the MXFP8 check is now folded into the early-return guard, so non-MXFP8 (e.g. plain FP8 E4M3) softmax quantizers fall through withuse_kitchen=Falseand the new wrapper-softmax path in_quantized_attentionactually runs. The newif not self.use_kitchenbranch is now reachable on kitchen-equipped hosts, which is exactly the regression mode the previous review flagged. - CI wiring:
torch_trtis now in theonnxmatrix in.github/workflows/example_tests.yml, and/examples/torch_trtis in.github/CODEOWNERSunder the onnx codeowners team. - README/requirements nits: install line is now
pip install -U "nvidia-modelopt"andtransformers>=4.56. - Test docstring: now accurately describes the argmax comparison as informational (a tiny random-weight ViT under NVFP4 can legitimately flip argmax), so the test–behavior contract is consistent.
torch_tensorrt_accuracy.pybaseline label: the BF16/FP16 mismatch is gone —--baselinehelp text is generic, and the printed tag derives fromstr(dtype)so it always matches.
Design is appropriate: this is "new example + tuned recipes + 11-line plugin fix" reusing the existing recipe loader (modelopt.recipe.load_recipe / ModelOptPTQRecipe), not a new subsystem. The deterministic complexity gate fired only on directory count.
Complex PR: spans 7 directories (≥ 5). Looping in a human for approval.
cjluo-nv
left a comment
There was a problem hiding this comment.
Bot review — DM the bot to share feedback.
Re-review: all previously-flagged critical issues are resolved in the latest diff.
- 💬 Kitchen-vs-FP8 ordering bug — fixed in
_init_kitchen_attn_fn(modelopt/torch/quantization/plugins/huggingface.py:85-89): the early-return guard now folds innot self.softmax_quantizer.is_mxfp(8), so plain FP8 E4M3 (the configuration both new ViT recipes ship) falls through withuse_kitchen=Falseand the new wrapper-softmax path in_quantized_attentionactually runs on kitchen-equipped hosts. The dead-code concern from the prior review no longer applies. - 💬 CI wiring —
torch_trtis now in theonnxmatrix in.github/workflows/example_tests.yml:101, and/examples/torch_trtis in.github/CODEOWNERS:56under the onnx codeowners team. PR-body claim of "tested in CI" is now true. - 💬 README install line +
transformerspin updated topip install -U "nvidia-modelopt"andtransformers>=4.56. - 💬 Test docstring (
tests/examples/torch_trt/test_torch_tensorrt_ptq.py:43-46) now correctly states the baseline/fake-quant/TRT argmax comparison is informational — consistent with the script not gating on it. - 💬
torch_tensorrt_accuracy.pybaseline label now derives fromstr(dtype), so the BF16/FP16 mismatch is gone.
Design is appropriate: this is "new example + tuned recipes + 11-line plugin fix" reusing the existing recipe loader (modelopt.recipe.load_recipe / ModelOptPTQRecipe), not a new subsystem. The deterministic complexity gate fired only on directory count.
Nudging for a human reviewer to sign off — the PR spans 7 directories and the design-review gate fired, so per the re-review guidance the architectural-scope check warrants a human.
| - Make ``.agents/skills/`` the canonical location for agent skills; agent-specific directories (``.claude/skills/``, etc.) are now relative symlinks into ``.agents/``, so one skill suite serves multiple coding agents (Claude Code, Codex). See ``.agents/README.md``. | ||
| - Extend Claude Code agent skills for PTQ, deployment, evaluation, monitoring, and baseline-vs-quantized result comparison. Adds evaluation task references for additional benchmarks, stronger PTQ checkpoint validation gates, and session-scoped workspace/job tracking. | ||
| - Add SLURM Quality of Service (QoS) support to the ModelOpt launcher. Users can set QoS via ``slurm_config.qos`` or ``SLURM_QOS`` and the value is forwarded to ``nemo_run.SlurmExecutor``. | ||
| - Add Torch-TensorRT FP8 / NVFP4 deployment example for HuggingFace ViT (``examples/torch_trt/``): ``torch_tensorrt_ptq.py`` covers ``mtq.quantize`` → ``torch_tensorrt.compile(ir="dynamo")``, and ``torch_tensorrt_accuracy.py`` reports the compiled model's ImageNet-1k top-1/top-5 accuracy via the ``onnx_ptq`` ``evaluate`` harness (the unquantized baseline is Torch-TensorRT-compiled too, for an apples-to-apples comparison). Ships two ViT-tuned PTQ recipes under ``modelopt_recipes/huggingface/vit/ptq/`` (``fp8.yaml``, ``nvfp4.yaml``) composed from the shared ``modelopt_recipes/configs/`` units: FP8 quantizes the encoder Linears, patch-embed ``nn.Conv2d``, ``classifier``, and per-block LayerNorm inputs plus the attention Q/K/V BMMs and softmax; NVFP4 runs W4A4 on the encoder ``nn.Linear`` weights/inputs while holding the patch-embed ``nn.Conv2d``, ``classifier``, and attention BMMs/softmax at FP8. Verified on ``google/vit-base-patch16-224`` (ImageNet-1k 50k validation): FP8 stays within 0.13 pp Top-1 of the FP16 baseline. |
There was a problem hiding this comment.
changelog entries would go to 0.46 section
4322938 to
66aec06
Compare
66aec06 to
4e7e345
Compare
4e7e345 to
242f9fa
Compare
* modelopt_recipes/huggingface/vit/ptq/{fp8,nvfp4}.yaml -- self-contained
ViT-tuned PTQ recipes targeting HuggingFace ViTForImageClassification.
Encoder Linear weights/inputs quantized; attention Q/K/V BMMs, softmax,
and per-block LayerNorm outputs at FP8; patch-embed nn.Conv2d, classifier,
and the final vit.layernorm left FP16. NVFP4 variant runs encoder Linears
in W4A4 NVFP4 (E2M1, block 16, FP8 scales) with AWQ-lite calibration.
* examples/torch_trt/ -- end-to-end Torch-TensorRT deployment example
(load HF model -> calibrate from tiny-imagenet -> mtq.quantize ->
torch_tensorrt.compile(ir="dynamo") -> benchmark). Defaults to
google/vit-large-patch16-224; --model_id + --recipe retarget any
HF model + ModelOpt PTQ recipe.
Attention softmax-P quantization uses the shared attention_qkv_fp8 recipe
unit, which enables _QuantAttention.p_bmm_quantizer on HuggingFace attention.
ImageNet-1k full-50k validation accuracy on google/vit-base-patch16-224
(batch=128, 49920/50000 samples):
FP16 baseline: Top-1 81.769% Top-5 96.124%
FP8 modelopt.onnx CLI: Top-1 81.707% Top-5 96.110% (-0.062 pp)
FP8 torch path (this PR): Top-1 81.637% Top-5 96.140% (-0.132 pp)
Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…omparison * examples/torch_trt/quantize_and_compile_vit.py -> torch_tensorrt_ptq.py * Drop the latency / speedup benchmarking comparison from the script and README; the script now only verifies that the compiled-model argmax matches the fake-quant argmax on a sample input. Accuracy comparison belongs in a separate harness, not in a "quantize + compile" example. Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
* tests/examples/torch_trt/test_torch_tensorrt_ptq.py -- mirrors the
tests/examples/torch_onnx/test_torch_quant_to_onnx.py pattern: invokes
the example via run_example_command, parametrizes over (fp8, nvfp4),
uses a 1-layer ViT config (--no_pretrained + --model_kwargs) so the
test completes in ~30 s per parametrized case. Two variants:
- test_torch_tensorrt_ptq[precision] -- full e2e through
torch_tensorrt.compile (importorskip on torch_tensorrt).
- test_torch_tensorrt_ptq_skip_trt[precision] -- quantize-only
smoke test, useful on hosts without torch_tensorrt installed.
* examples/torch_trt/torch_tensorrt_ptq.py:
- Add --no_pretrained + --model_kwargs flags (mirroring torch_onnx)
so the same script doubles as the test entry point.
- Force aten.cat.default into PyTorch fallback inside
compile_with_torch_tensorrt -- torch_tensorrt 2.10's cat converter
chokes on the HF ViT cls-token + patch-embedding concat (BF16:
"Got unsupported ScalarType BFloat16"; FP16: rank-(-1) TRT tensor
that crashes the downstream `embeddings + position_embeddings`
add). The cat is a tiny [1,1,H] + [1,N,H] op that runs once per
forward, so PyTorch fallback costs essentially nothing.
Verified locally: pytest tests/examples/torch_trt/test_torch_tensorrt_ptq.py
-> 4 passed in 103 s on RTX 6000 Ada.
Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
Drops `test_torch_tensorrt_ptq_skip_trt` -- the full `test_torch_tensorrt_ptq` variant already exercises the same mtq.quantize path and goes further (torch_tensorrt.compile). The skip-variant added duplicate CI runtime without unique coverage. Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
Recompose the ViT PTQ recipes from the shared $import building blocks under modelopt_recipes/configs/ instead of inlined quant_cfg entries: - fp8: import w8a8_fp8_fp8 + attention_qkv_fp8 (resolves to the same config). - nvfp4: import numerics/nvfp4 for the nn.Linear weight/input cfg and attention_qkv_fp8 for the q/k/v BMM + softmax, and hold the patch-embed Conv2d and classifier head at per-tensor FP8. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
examples/torch_trt/torch_tensorrt_accuracy.py quantizes and Torch-TensorRT- compiles a HuggingFace ViT (reusing torch_tensorrt_ptq.py) and reports ImageNet-1k top-1/top-5 via the onnx_ptq evaluate() harness. A thin adapter casts the float32 dataloader batches to the compiled model's compute dtype and unwraps logits; the Torch-TRT path is pinned to batch_size=1 (static engine). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
- torch_tensorrt_accuracy.py: the --baseline reference is now Torch-TensorRT- compiled like the quantized model (shared to_eval_model helper), so every reported number comes from the same TRT runtime. - README/CHANGELOG: document torch_tensorrt_accuracy.py and correct the recipe description — the recipes now compose from the shared modelopt_recipes/configs/ $import units, and the nvfp4 recipe holds the patch-embed Conv2d + classifier head at FP8. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
compile_with_torch_tensorrt imports torch_tensorrt inside the function (not at module scope) so the quantize-only --skip_trt path still runs on hosts without torch_tensorrt installed. Add a one-line comment making that intent explicit. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
- example_tests.yml: add torch_trt to the ONNX/TensorRT example matrix. - .github/CODEOWNERS: add /examples/torch_trt. - README: install nvidia-modelopt (drop the [torch] extra). - requirements.txt: bump transformers to >=4.56. - torch_tensorrt_accuracy.py: default --calib_samples to 512. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
Address PR review: explain how the Torch-TensorRT PTQ example differs from the ONNX export examples with a 3-way comparison table covering starting point, where quantization happens, export step, intermediate artifact, and runtime. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
- Compile a dynamic-batch engine by default: the cls-token cat stays in TRT (one engine) so Q/DQ fuse into FP8 across the whole ViT (~121 vs ~24 GEMMs). Static keeps the bf16-cat PyTorch fallback (two engines). - hidden_act="gelu_fast"; defaults: --batch_size 128, --calib_samples 1024, --save_dir ./modelopt_quantized. - Replace --precision with --recipe (default ViT FP8 recipe); drop --no_pretrained / --model_kwargs. - Accuracy script: dynamic engine + batch 128, recipe-derived result label. - Update example test + README. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
Run the ViT in float16 in both torch_tensorrt_ptq.py and torch_tensorrt_accuracy.py (the PTQ script previously used bfloat16), so both paths share one compute dtype. compile_with_torch_tensorrt now always builds a single dynamic-batch engine: remove the static-compile branch, its forced-cat fallback, and the dynamic= plumbing from both entry points. load_model_and_processor always loads pretrained weights; drop the pretrained/config_overrides args and the unused ViTConfig import (matches the test's CLI-only contract). README: restructure as a focused single-example guide; list the FP8/NVFP4 minimum compute capability (8.9+ / 10.0+) and architectures in Hardware Requirements; note both scripts run in float16; remove stale Dynamic Engine links. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
…x PTQ Load the ViT classifier with attn_implementation="eager" so softmax runs through F.softmax instead of the fused SDPA kernel. The recipe's *softmax_quantizer is then exercised during calibration (otherwise it stays uncalibrated, amax=dynamic) and emits Q/DQ around the softmax output on export. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
NVFP4's TRT kernels are only generated on Blackwell (SM >= 100); on older GPUs torch_tensorrt.compile fails at NVRTC/Myelin codegen. Guard the nvfp4 parametrization with skipif(not fp4_compatible()) so the suite skips rather than fails on non-Blackwell hardware. The fp8 case is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
Build the e2e test's ViT from a tiny randomly-initialized config saved with its image processor (new create_tiny_vit_dir helper in tests/_test_utils/torch/transformers_models.py) instead of downloading google/vit-base-patch16-224, so the test runs offline and fast while exercising the same module structure (3-channel patch conv, attention q/k/v, classifier). Drop the NVFP4/Blackwell-gated parametrization (and the now-unused fp4_compatible import) so the test covers the FP8 recipe only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
Delete modelopt_recipes/huggingface/vit/ptq/nvfp4.yaml and scrub every remaining reference to it: the README (recipe/hardware table rows, usage examples, building-block list), the --recipe help text in torch_tensorrt_ptq.py / torch_tensorrt_accuracy.py, and the CHANGELOG entry. The ViT Torch-TRT example is now FP8-only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com>
…a eager p_bmm_quantizer wrapper ModelOpt's built-in softmax-P quant path (``_QuantAttention.p_bmm_quantizer``) runs through the Triton flash-attention kernel, which only supports causal attention. ViT attention is non-causal, so the FP8 ViT recipe's p_bmm_quantizer tripped ``NotImplementedError: ... does not support non-causal attention`` during ``mtq.quantize`` / ``torch_tensorrt.compile``. Route non-causal attention (``is_causal=False``) to an eager softmax wrapper that applies p_bmm_quantizer by temporarily swapping ``torch.nn.functional.softmax`` for a Q/DQ-emitting version. This keeps the softmax-P quantizer in the traced graph so ONNX / Torch-TRT export sees Q/DQ around the softmax output, while attention is still computed by the original (eager) interface. Requires an eager attention implementation; SDPA-fused softmax is unaffected. The causal LLM path still uses the Triton kernel, and the other out-of-envelope cases (sliding window, sinks, softcapping, dropout, KV cache, padded masks) still raise. Verified on google/vit-base-patch16-224: the torch_trt e2e example test (quantize -> torch_tensorrt.compile) passes, the causal Triton path is unchanged, and a new GPU test covers the non-causal eager fallback. Signed-off-by: ajrasane <131806219+ajrasane@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
242f9fa to
3b0a302
Compare
…tests (#1970) ### What does this PR do? **Type of change:** documentation (+ new tests) `modelopt_recipes/ptq.md` is meant to track every shipped PTQ recipe, but recent recipe PRs did not update it. This PR brings the doc back in sync and adds unit tests so it can't drift again. **Doc sync — general recipes:** - Add `nvfp4_experts_only_input_scale1-kv_fp8_cast` (#1947) to the shipped-recipes table (now 20 recipes) and document the `input_scale1` variant (constant amax 2688 → exported NVFP4 `input_scale == 1.0`, expert activations uncalibrated). - Add a pointer that the PTQ recipes' `quantize` sections also drive QAT/QAD, with the LSQ / Dual-LSQ QAD recipes under `general/qad/` (#1884). **Doc sync — model-specific recipes:** - Add `gemma4` (algorithm override, #1690), `diffusion_gemma` (extra `*self_conditioning*` exclusion, #1707), `vit` (FP8 with attention BMM quantizers for Torch-TRT, #1569), and the qwen3_5 / qwen3_5_moe `w4a16_nvfp4_mse-fp8_attn-kv_fp8_cast` twins (#1620). - Rewrite the checkpoint-mirror section for the `huggingface/models/nvidia/` tier: Super recipe rename (`super-nvfp4.yaml` → `nvfp4-mse.yaml` / `nvfp4-max-calib.yaml`), Nano-4B GGUF Q4_K_M mirror (#1327/#1606), Ultra-550B `nvfp4-4o6` (#1684); fix stale `models/<checkpoint>` paths. **Enforcement — new `tests/unit/recipe/test_recipe_docs.py`:** 1. Every `general/ptq/*.yaml` stem must appear (backticked) in `ptq.md`. 2. Every recipe row in the shipped-recipes table must exist on disk (catches renames/removals). 3. The "All N `general/ptq/` recipes" count must match the file count. 4. Every model folder under `huggingface/` containing `ptq/*.yaml` must be mentioned in the doc. ### Usage ```bash pytest tests/unit/recipe/test_recipe_docs.py -q ``` ### Testing - `pytest tests/unit/recipe/ -q` → 218 passed (includes the 4 new tests). - Verified enforcement bites: against the pre-update `ptq.md`, 3 of the 4 new tests fail with actionable messages. - `pre-commit run --files modelopt_recipes/ptq.md tests/unit/recipe/test_recipe_docs.py` → all hooks pass. ### 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?: ✅ (docs + tests only; no runtime code changed) - 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?: ✅ — `tests/unit/recipe/test_recipe_docs.py` - Did you update [Changelog](https://github.com/NVIDIA/Model-Optimizer/blob/main/CHANGELOG.rst)?: N/A (documentation/test change) - Did you get Claude approval on this PR?: ❌ (pending) ### Additional Information Follow-up to the recipe guide added in #1662. The doc-consistency tests could also be wired into `tools/precommit/check_modelopt_recipes.py` for commit-time feedback if reviewers prefer both layers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Added the `nvfp4_experts_only_input_scale1-kv_fp8_cast` recipe to the general PTQ catalog. * Documented the new `input_scale1` calibration behavior and related quantization/caching details. * Expanded and reworked PTQ documentation, including updated navigation, “Beyond PTQ” guidance, new/updated model-specific recipes, and expanded checkpoint mirror entries. * Updated the general PTQ shipped-recipe count to 20. * **Tests** * Added automated consistency checks between on-disk shipped recipe YAML files and the PTQ documentation (coverage, existence, and counts). <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Chenjie Luo <chenjiel@nvidia.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
What does this PR do?
Type of change: new feature + bug fix
Adds a Torch-TensorRT deployment path for HuggingFace ViT and closes the
modelopt-side gap that prevented
*softmax_quantizerfrom being appliedon the standard attention forward path.
New ViT PTQ recipes under
modelopt_recipes/huggingface/vit/ptq/:fp8.yaml— W8A8 per-tensor FP8 E4M3 on encoder Linear weights/inputs;attention Q/K/V BMMs + softmax output at FP8; per-block LayerNorm output
at FP8 (one shared Q/DQ feeds Q/K/V + MLP); patch-embed
nn.Conv2d,classifier, and the finalvit.layernormleft FP16. Uses maxcalibration.
$importof shared snippets) anduse the "specific-enable" style: narrow
parent_class+ path scopingon every enable rule, so no
enable: falsecarve-outs are needed.New example under
examples/torch_trt/:torch_tensorrt_ptq.py— single-model pipeline (load HF model,calibrate from
zh-plus/tiny-imagenet,mtq.quantize,torch_tensorrt.compile, verify the compiled-model argmax matches thefake-quant argmax). Defaults to
google/vit-large-patch16-224; pass--model_idand--recipeto target any model + recipe combination.--no_pretrained+--model_kwargsshrink the model for fast tests.README.mddocumenting the flow, the shipped recipes, hardwarerequirements, and CLI usage.
requirements.txt.Bug fix in
modelopt/torch/quantization/plugins/huggingface.py— inside_QuantAttention._quantized_attention, the non-kitchen branch nowtemporarily replaces
torch.nn.functional.softmax(via the existingreplace_functioncontext manager) with a wrapper that pipes the softmaxoutput through
self.softmax_quantizer. Previously the slot was createdon every registered attention class but only consumed by the optional
Kitchen MXFP8 flash-attention path, so FP8 / NVFP4 recipes that enabled
*softmax_quantizersaw it stay uncalibrated (amax=None) and emittedno Q/DQ around the softmax output during ONNX / Torch-TRT export. With
this fix the
softmax_quantizeris calibrated alongside the rest ofthe model, and both the modelopt ONNX exporter and
torch_tensorrt.compilepick up the Q/DQ pair. The patch short-circuits to the unwrapped call
when the quantizer is disabled (zero-overhead) and has no effect on SDPA
paths that fuse softmax inside a C++ kernel.
New e2e integration test at
tests/examples/torch_trt/test_torch_tensorrt_ptq.py— mirrors thetorch_onnxtest pattern: invokes the example throughrun_example_command, parametrizes over the two precision modes (fp8,nvfp4), uses a 1-layer ViT config (
--no_pretrained+--model_kwargs)so each parametrized case completes in under a minute.
importorskipontorch_tensorrtso the test is automatically skipped on hosts withoutthe package.
Usage
Testing
Recipes load via
modelopt.recipe.load_recipe()and passQuantizeConfigschema validation.Run
pytest tests/examples/torch_trt/test_torch_tensorrt_ptq.py→1 parametrized case passes on RTX 6000 Ada (fp8).
End-to-end on
google/vit-base-patch16-224:mtq.quantizewith the newFP8 recipe followed by
torch_tensorrt.compile(ir="dynamo")produces aTRT engine whose argmax matches the FP16 baseline.
ONNX exported from the torch path now contains Q/DQ on 12 / 12
softmax outputs (was 0 / 12 before this PR's
_QuantAttentionfix),matching the ONNX-CLI output's quantization layout.
Both FP8 paths land within 0.13 pp Top-1 of the FP16 baseline; Top-5 is
within 0.02 pp across all three.
ImageNet-1k validation accuracy via the new
torch_tensorrt_accuracy.py(full 50000 samples, batch=1, every model Torch-TensorRT-compiled —
including the baseline — so the comparison is apples-to-apples) for the
example's default
google/vit-large-patch16-224:FP8 is within noise of the FP16 TRT baseline and NVFP4 W4A4 costs only
−0.13 pp Top-1 / −0.05 pp Top-5. Absolute Top-1 sits below the model card's
~85.5% because evaluation uses the HF
AutoImageProcessordefaultpreprocessing (direct 224×224 resize, no resize-then-center-crop), applied
identically to all three models — so the deltas are the comparison signal.
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.).CONTRIBUTING.md: N/Atests/examples/torch_trt/.Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Requirements
Tests