Skip to content

Remove deprecations marked in 0.45 and 0.46 - #2182

Open
kevalmorabia97 wants to merge 7 commits into
mainfrom
kmorabia/remove-0.45-0.46-deprecations
Open

Remove deprecations marked in 0.45 and 0.46#2182
kevalmorabia97 wants to merge 7 commits into
mainfrom
kmorabia/remove-0.45-0.46-deprecations

Conversation

@kevalmorabia97

@kevalmorabia97 kevalmorabia97 commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

Type of change: Backward breaking change (deprecation removal)

Ahead of the 0.47 code freeze, this removes every deprecation still outstanding from the previous two releases (0.45 and 0.46). Two are intentionally left in place: the Python 3.10 drop and the transformers 4.x drop

Deprecation Marked in Replacement
--auto_quantize_bits / _method / _score_size / _cost_model / _active_moe_expert_ratio 0.46 AutoQuantize --recipe
examples/llm_ptq symlink + examples/vlm_ptq/ forwarder 0.46 examples/hf_ptq (--vlm for VLMs)
QuantizationArgumentsWithConfig alias 0.45 QuantizationArguments
QFORMAT_ALIASES short names 0.45 canonical preset basenames
layerwise bool + flat layerwise_checkpoint_dir 0.45 nested layerwise: {enable, checkpoint_dir}
in-trainer quant_cfg / --quant_cfg 0.45 --recipe

Two things worth a closer look

1. The use_sequential alias goes too. It is the pre-#1251 alias on QuantizeAlgorithmConfig.layerwise and only ever carried a bool. Once the bool form is rejected it cannot accept a valid value, so keeping it would only produce a differently-worded validation error. Note the direction is breaking either way (extra="forbid"): a pre-0.45 modelopt_state carrying use_sequential: True or a top-level layerwise_checkpoint_dir now fails validation instead of being migrated.

2. Removing in-trainer --quant_cfg required two new recipes. The examples/gpt-oss QAT flow ran on --quant_cfg MXFP4_MLP_WEIGHT_ONLY_CFG and no general/ptq/ recipe covered it. This PR adds general/ptq/mxfp4_mlp_weight_only and general/ptq/nvfp4_mlp_weight_only, verified to model_dump identical to mtq.MXFP4_MLP_WEIGHT_ONLY_CFG / mtq.NVFP4_MLP_WEIGHT_ONLY_CFG, and migrates the gpt-oss README, both SFT configs, sft.py and tests/examples/gpt-oss/test_gpt_oss_qat.py. examples/llm_qat was already recipe-only.

Usage

# AutoQuantize: --auto_quantize_* flags -> an AutoQuantize recipe
scripts/huggingface_example.sh --model $HF_PATH \
  --recipe general/auto_quantize/nvfp4_fp8_at_5p4bits --calib_batch_size 4

# --qformat / --quant_cfg: short name -> canonical preset basename
#   int8_sq -> int8_smoothquant                nvfp4_mse           -> nvfp4_w4a4_weight_mse_fp8_sweep
#   int8_wo -> int8_weight_only                nvfp4_local_hessian -> nvfp4_w4a4_weight_local_hessian
#   w4a8_awq -> w4a8_awq_beta                  fp8_pb_wo           -> fp8_2d_blockwise_weight_only
#   nvfp4_awq -> nvfp4_awq_lite                fp8_pc_pt           -> fp8_per_channel_per_token
scripts/huggingface_example.sh --model $HF_PATH --quant int8_smoothquant

# VLM PTQ: examples/vlm_ptq -> examples/hf_ptq with --vlm
scripts/huggingface_example.sh --model $HF_PATH --quant fp8 --vlm

# gpt-oss QAT: --quant_cfg <CFG name> -> --recipe <recipe path>
accelerate launch --config_file configs/zero3.yaml sft.py \
  --config configs/sft_full.yaml --model_name_or_path openai/gpt-oss-20b \
  --recipe general/ptq/mxfp4_mlp_weight_only --output_dir gpt-oss-20b-qat
# Layerwise calibration: bool / flat key -> nested LayerwiseConfig
quant_cfg["algorithm"] = {"method": "gptq", "layerwise": {"enable": True, "checkpoint_dir": "/path"}}

Testing

  • tests/unit/recipe (229 passed), tests/unit/torch/quantization/test_config_validation.py (79 passed), tests/examples/hf_ptq/test_hf_ptq_args.py (23 passed).
  • Verified the two new recipes model_dump identical to the mtq.*_CFG constants they replace.
  • ruff check modelopt/ examples/ tests/ clean; ruff format --check clean on all changed Python files.
  • GPU suites (tests/gpu/torch/export/test_unified_hf_export_and_check_safetensors.py, test_accelerate_gpu.py, test_gptq.py) had their preset / layerwise literals updated but were not run locally — relying on CI.
  • examples/llm_qat/ARGUMENTS.md is hand-edited to match what the generate-arguments-md hook emits; the generator could not run locally (missing transformers package metadata in this environment).

Before your PR is "Ready for review"

  • Is this change backward compatible?: ❌ — that is the point of the PR: it removes shims deprecated in 0.45/0.46. Callers must move to the replacements in the table above. Additionally, a pre-0.45 modelopt_state carrying use_sequential or a top-level layerwise_checkpoint_dir will now fail config validation.
  • 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?: ✅ — existing tests migrated to the surviving APIs; TestLayerwiseNestedConfig::test_legacy_forms_rejected pins that the bool form, the use_sequential alias and the flat checkpoint-dir key are all rejected. Tests covering the removed shims were deleted.
  • Did you update Changelog?: ✅
  • Did you get Claude approval on this PR?: ❌

Additional Information

Follow-up: the transformers 4.x drop deprecated in 0.46 is still outstanding and will need its own PR.

🤖 Generated with Claude Code

Summary by CodeRabbit

New Features

  • Added MXFP4 and NVFP4 weight-only quantization recipes for MLP and MoE layers.
  • Added shared layer exclusions for more accurate effective-bits calculations.

Improvements

  • Updated PTQ, QAT, GPT-OSS, deployment, and quantization-format examples with current recipe names and configuration formats.
  • Standardized layerwise settings under nested configuration fields.

Breaking Changes

  • Removed deprecated AutoQuantize options, quant_cfg usage, format aliases, legacy layerwise settings, and compatibility example paths.
  • Recipe-based and nested configuration forms are now required.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

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: 70162731-0aef-47ed-8649-dd38c9d49f79

📥 Commits

Reviewing files that changed from the base of the PR and between ad331ce and 58d6659.

📒 Files selected for processing (3)
  • CHANGELOG.rst
  • modelopt_recipes/general/ptq/nvfp4_experts_only-kv_fp8_cast.yaml
  • modelopt_recipes/general/ptq/nvfp4_experts_only_input_scale1-kv_fp8_cast.yaml
🚧 Files skipped from review as they are similar to previous changes (3)
  • modelopt_recipes/general/ptq/nvfp4_experts_only_input_scale1-kv_fp8_cast.yaml
  • modelopt_recipes/general/ptq/nvfp4_experts_only-kv_fp8_cast.yaml
  • CHANGELOG.rst

📝 Walkthrough

Walkthrough

Version 0.47 standardizes quantization around recipes and nested layerwise configuration. It removes deprecated AutoQuantize flags, aliases, and compatibility paths. It adds NVFP4 and MXFP4 MLP/MoE weight-only recipes and updates examples, tests, and documentation.

Changes

Quantization modernization

Layer / File(s) Summary
Recipe-only quantization flows
examples/gpt-oss/*, examples/hf_ptq/*, examples/llm_qat/*, modelopt/torch/quantization/plugins/transformers_trainer.py, tests/examples/gpt-oss/*, plugins/modelopt/skills/deployment/*
Quantization entry points now use recipes. Deprecated AutoQuantize flags, trainer-side quant_cfg handling, compatibility aliases, and legacy forwarding paths were removed.
Nested layerwise configuration
examples/hf_ptq/example_utils.py, modelopt/torch/quantization/config.py, tests/_test_utils/..., tests/gpu/torch/quantization/*, tests/unit/torch/quantization/*, modelopt_recipes/*/ptq/*
Layerwise settings now use nested enable and checkpoint_dir fields. Legacy boolean, alias, and flat checkpoint forms are no longer supported.
Preset names and weight-only recipes
modelopt/recipe/presets.py, modelopt_recipes/general/ptq/*, modelopt_recipes/ptq.md, examples/hf_ptq/README.md, examples/megatron_bridge/*, tests/examples/hf_ptq/*, tests/gpu/torch/export/*
Preset discovery uses YAML basenames without aliases. Canonical qformat names are used. NVFP4 and MXFP4 MLP/MoE weight-only recipes are added, documented, and tested.
AutoQuantize recipe composition and validation
modelopt/recipe/config.py, modelopt_recipes/configs/auto_quantize/*, modelopt_recipes/general/auto_quantize/*, tests/examples/hf_ptq/test_hf_ptq_args.py, tests/unit/recipe/test_loader.py
AutoQuantize recipes import shared cost exclusions. Tests validate excluded layers, shipped PTQ recipe discovery, and calibration configuration construction.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Mergeability Score: ⚪ Minimal · up to 58d66

This PR removes deprecated interfaces and updates documented replacements and tests; no actionable merge-blocking risk remains after normal checks and review.

Possibly related PRs

Suggested reviewers: realasma, jenchen13, shengliangxu

🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the primary change: removing deprecations introduced in versions 0.45 and 0.46.
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 The PR diff adds no prohibited torch.load, numpy.load, trust_remote_code=True, eval/exec, or # nosec patterns, and changes no dependency manifests.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch kmorabia/remove-0.45-0.46-deprecations

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

@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://NVIDIA.github.io/Model-Optimizer/pr-preview/pr-2182/

Built to branch gh-pages at 2026-08-15 18:23 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@coderabbitai coderabbitai Bot 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.

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.

👉 Steps to fix this

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/hf_ptq/scripts/huggingface_example.sh`:
- Around line 97-99: Update the AutoQuantize checkpoint-generation condition to
inspect the loaded recipe’s type rather than matching the RECIPE path string.
Use the recipe data produced by load_recipe() to identify AutoQuantize recipes,
while preserving the existing AUTO_QUANTIZE_CHECKPOINT-empty guard.
🪄 Autofix

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: 5573ac1c-1d47-4362-bc5f-f27a40aad3a0

📥 Commits

Reviewing files that changed from the base of the PR and between 96b4aac and 4ae2718.

📒 Files selected for processing (40)
  • CHANGELOG.rst
  • examples/gpt-oss/README.md
  • examples/gpt-oss/configs/sft_full.yaml
  • examples/gpt-oss/configs/sft_lora.yaml
  • examples/gpt-oss/sft.py
  • examples/hf_ptq/README.md
  • examples/hf_ptq/example_utils.py
  • examples/hf_ptq/hf_ptq.py
  • examples/hf_ptq/scripts/huggingface_example.sh
  • examples/hf_ptq/scripts/parser.sh
  • examples/llm_ptq
  • examples/llm_qat/ARGUMENTS.md
  • examples/llm_qat/quantize.py
  • examples/megatron_bridge/README.md
  • examples/vlm_ptq/.gitignore
  • examples/vlm_ptq/README.md
  • examples/vlm_ptq/scripts/huggingface_example.sh
  • modelopt/recipe/config.py
  • modelopt/recipe/presets.py
  • modelopt/torch/quantization/backends/nvfp4_gemm.py
  • modelopt/torch/quantization/config.py
  • modelopt/torch/quantization/plugins/transformers_trainer.py
  • modelopt/torch/utils/dataset_utils.py
  • modelopt_recipes/general/auto_quantize/w4a16_nvfp4_fp8_at_6p0bits-active_moe.yaml
  • modelopt_recipes/general/ptq/mxfp4_mlp_weight_only.yaml
  • modelopt_recipes/general/ptq/nvfp4_mlp_weight_only.yaml
  • modelopt_recipes/huggingface/qwen3_6_moe/auto_quantize/w4a16_nvfp4_fp8_at_6p0bits-active_moe.yaml
  • modelopt_recipes/ptq.md
  • plugins/modelopt/skills/deployment/references/trtllm.md
  • plugins/modelopt/skills/deployment/scripts/deploy.sh
  • tests/_test_utils/torch/quantization/offload.py
  • tests/examples/gpt-oss/test_gpt_oss_qat.py
  • tests/examples/hf_ptq/test_hf_ptq_args.py
  • tests/examples/hf_ptq/test_llm_ptq.py
  • tests/examples/hf_ptq/test_vlm_ptq.py
  • tests/gpu/torch/export/test_unified_hf_export_and_check_safetensors.py
  • tests/gpu/torch/quantization/plugins/test_accelerate_gpu.py
  • tests/gpu/torch/quantization/test_gptq.py
  • tests/unit/recipe/test_presets.py
  • tests/unit/torch/quantization/test_config_validation.py
💤 Files with no reviewable changes (7)
  • examples/vlm_ptq/.gitignore
  • examples/vlm_ptq/scripts/huggingface_example.sh
  • examples/vlm_ptq/README.md
  • modelopt/recipe/config.py
  • examples/llm_ptq
  • tests/examples/hf_ptq/test_hf_ptq_args.py
  • tests/unit/recipe/test_presets.py

Comment thread examples/hf_ptq/scripts/huggingface_example.sh

@cjluo-nv cjluo-nv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Bot review (bedrock-claude-opus-5) — DM the bot to share feedback.

Mechanical, well-scoped deprecation removal (0.45/0.46), mostly deletions with the surviving APIs' tests migrated in place. I checked for dangling references at the PR branch: examples/llm_ptq / examples/vlm_ptq are gone with the two skill docs and dataset_utils.py comment updated; no remaining consumers of QFORMAT_ALIASES, AUTOQUANT_BASE_*, _auto_quantize_config_from_cli, QuantizationArgumentsWithConfig, quant_args.quant_cfg, use_sequential, or layerwise_checkpoint_dir (the int8_sq hits left in modelopt/torch/export/model_config.py, docs/.../1_tensorrt_llm.rst, tests/gpu/torch/export/test_export.py and the gemma recipe filename are TRT-LLM format names / recipe basenames, not the removed CLI alias). load_config is correctly dropped from modelopt/recipe/config.py, MaxCalibConfig rejects all three legacy forms via extra="forbid", and the new YAMLs carry the standard NVIDIA header (year differs from LICENSE_HEADER, same as every existing recipe — not a licensing concern).

Design-review note: this PR removes abstractions rather than adding any; the two new files reuse the existing modelopt_recipes composition mechanism, so no second system is introduced. The one design-adjacent smell is that each new general/ptq/*_mlp_weight_only.yaml is a verbatim copy of the same-named preset under configs/ptq/presets/model/, with nothing pinning the equality the PR body says was verified by hand.

Findings (all small, none blocking): one now-dead "sq" in args.qformat heuristic that silently changes calibration batch-size probing for SmoothQuant, the un-pinned recipe/preset duplication, and a few stale comments/changelog omissions. Details inline.

Comment thread examples/hf_ptq/hf_ptq.py
Comment thread modelopt_recipes/general/ptq/mxfp4_mlp_weight_only.yaml Outdated
Comment thread examples/hf_ptq/hf_ptq.py
Comment thread modelopt/torch/quantization/config.py
Comment thread CHANGELOG.rst Outdated
@kevalmorabia97

Copy link
Copy Markdown
Collaborator Author

Pushed 8736546 addressing review feedback, plus a CI unit-test failure.

CI failure (not from review — linux unit tests)

tests/unit/torch/quantization/test_layerwise_calibrate.py had 6 failures: four call sites still passed the removed layerwise: True bool form. Fixed; the file's 33 tests pass locally. My original sweep did match these — I truncated its output and cut them off. Re-swept untruncated: the only remaining layerwise: True / use_sequential occurrences are the deliberate negative cases in test_legacy_forms_rejected.

Review comments — 5 addressed, 1 pushed back

Comment Outcome
"sq" in args.qformat heuristic now dead Fixed — real regression, see below
New recipes duplicate presets with nothing pinning parity Fixed — added a parity test
Stale --auto_quantize_* comment Fixed
Stale "alias path" docstring Fixed
CHANGELOG missing restore-failure consequence Fixed
Shell should inspect recipe type, not glob the path Pushed back — pre-existing, thread left open

The sq one was the substantive catch and a genuine regression in the first commit: int8_smoothquant contains hq, not sq, so renaming the alias silently killed the branch that gives AWQ/SmoothQuant 2x memory headroom in the auto batch-size probe. SmoothQuant calibration would have run at 1.1x and been OOM-prone, including the untuned int8_smoothquant cases in test_llm_ptq.py. Now keyed on "smoothquant".

For the parity concern I added test_mlp_weight_only_recipe_matches_its_mtq_cfg, and verified it actually bites — mutating a quantizer_name in the recipe fails it, restoring passes. So the recipe/mtq.*_CFG equality the gpt-oss migration depends on is now enforced rather than asserted in prose.

Verified locally: 366 tests pass across tests/unit/recipe, test_config_validation.py, test_layerwise_calibrate.py, test_hf_ptq_args.py; ruff check and ruff format --check clean.

Still unrun locally: the GPU suites whose preset/layerwise literals this PR updates (test_unified_hf_export_and_check_safetensors.py, test_accelerate_gpu.py, test_gptq.py) — relying on CI.

@kevalmorabia97

Copy link
Copy Markdown
Collaborator Author

/claude review

@cjluo-nv cjluo-nv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Bot review (bedrock-claude-opus-5) — DM the bot to share feedback.

Re-review of PR #2182 (0.45/0.46 deprecation removal, 41 files, +234/-564). All previously-flagged items are resolved in 8736546:

  • Critical — dead "sq" in args.qformat heuristic: fixed, now "smoothquant" in args.qformat in quantize_main, so SmoothQuant calibration keeps the 2x memory headroom in the auto batch-size probe. (awq half still matches w4a8_awq_beta / nvfp4_awq_lite.)
  • Critical — new general/ptq/*_mlp_weight_only.yaml duplicated the shipped presets with nothing pinning parity: fixed via test_mlp_weight_only_recipe_matches_its_mtq_cfg in tests/unit/recipe/test_presets.py, parametrized over both recipes, comparing load_recipe(...).quantize.model_dump(exclude_unset=True) to QuantizeConfig(**mtq.<CFG>).model_dump(exclude_unset=True). I confirmed the recipes are byte-for-byte equivalent to configs/ptq/presets/model/{mxfp4,nvfp4}_mlp_weight_only.yaml (same imports, same two quantizer entries, same algorithm), and that the gpt-oss notebook still uses mtq.MXFP4_MLP_WEIGHT_ONLY_CFG directly — so the interchangeability the README claims is now enforced by a test. Option (b) over (a) is a reasonable call given the two files use different schemas.
  • Critical (CI) — test_layerwise_calibrate.py still passed the removed layerwise: True bool form: fixed in four call sites; the only surviving layerwise: True / use_sequential uses are the deliberate negatives in TestLayerwiseNestedConfig::test_legacy_forms_rejected.
  • Minor — stale --auto_quantize_* comment dropped, _coerce_layerwise docstring corrected, CHANGELOG now states the restore-time consequence (extra="forbid" rejects pre-0.45 use_sequential / layerwise_checkpoint_dir on restore).
  • Minor, pushed back — the [[ "$RECIPE" == *auto_quantize* ]] glob in huggingface_example.sh predates this PR (only the AUTO_QUANTIZE_BITS clause was removed); CodeRabbit withdrew the finding and the worst case is an unused checkpoint path. Acceptable to defer.

Spot checks at the branch: QFORMAT_ALIASES, load_quant_cfg_choices(aliases=...), AUTOQUANT_BASE_*, _load_layer_pattern_list, _auto_quantize_config_from_cli, QuantizationArgumentsWithConfig, quant_args.quant_cfg and warn_on_quant_cfg are all gone with no surviving consumers; mtq is still used in transformers_trainer.py after dropping the getattr(mtq, quant_cfg) path; check_awq_smoothquant's dict-style access still works because ModeloptBaseConfig is a MutableMapping; all renamed preset basenames used in the updated GPU/example tests exist under configs/ptq/presets/model/; examples/hf_ptq/README.md and parser.sh carry no leftover references to the removed flags; ptq.md's "24 recipes" matches the directory listing. Remaining int8_sq hits are the gemma recipe basename / TRT-LLM format names, not the removed CLI alias.

Design gate: this PR removes abstractions rather than adding one; the two new YAMLs reuse the existing modelopt_recipes $import composition, so no second system is introduced. Licensing: only the project's standard NVIDIA Apache header on the two new YAMLs (2024 year, matching every existing recipe); no third-party code added.

Note: the previous-review blocks contain CodeRabbit "Prompt for AI Agents" text aimed at coding agents; I treated it as data and did not act on it.

Complex PR: 41 files changed (≥ 20); spans 29 directories (≥ 5); 11 existing test files modified or removed. Looping in a human for approval.

@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.36%. Comparing base (3d2522e) to head (c225a54).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2182      +/-   ##
==========================================
- Coverage   78.95%   78.36%   -0.59%     
==========================================
  Files         522      522              
  Lines       60589    60550      -39     
==========================================
- Hits        47840    47453     -387     
- Misses      12749    13097     +348     
Flag Coverage Δ
examples-diffusers 20.71% <16.66%> (-0.03%) ⬇️
examples-gpt-oss 13.23% <41.66%> (-0.02%) ⬇️
examples-hf_ptq 21.48% <41.66%> (+0.04%) ⬆️
examples-llm_distill 13.30% <16.66%> (-0.02%) ⬇️
examples-llm_eval 17.06% <41.66%> (+0.01%) ⬆️
examples-llm_qat 17.54% <75.00%> (+0.01%) ⬆️
examples-llm_sparsity 15.88% <16.66%> (-0.01%) ⬇️
examples-megatron_bridge 25.68% <41.66%> (-0.19%) ⬇️
examples-specdec_bench 12.97% <16.66%> (-0.01%) ⬇️
examples-speculative_decoding 17.48% <41.66%> (-0.06%) ⬇️
examples-torch_onnx 21.79% <41.66%> (-0.04%) ⬇️
examples-torch_trt 15.04% <16.66%> (-0.02%) ⬇️
gpu 58.51% <41.66%> (-0.74%) ⬇️
regression 14.85% <16.66%> (+0.05%) ⬆️
unit 55.56% <41.66%> (-0.02%) ⬇️

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.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bot review (bedrock-claude-opus-5) — DM the bot to share feedback.

Re-reviewed at 8736546 (the commit addressing the previous round). Full scope: all 41 changed files, modelopt/examples/modelopt_recipes/tests/.

Findings: CRITICAL 0 · IMPORTANT 1 · SUGGESTION 1

Previous round's findings — all verified resolved

  • "sq" in args.qformat → now "smoothquant" in args.qformat (hf_ptq.py:1159); the export branch is keyed on "int8_smoothquant" (:824). The regression was real and is correctly fixed — int8_smoothquant contains hq, not sq, so SmoothQuant calibration would have probed batch size at 1.1x.
  • Recipe/preset parity is now pinned by test_mlp_weight_only_recipe_matches_its_mtq_cfg. I diffed both new general/ptq/*_mlp_weight_only.yaml against configs/ptq/presets/model/*_mlp_weight_only.yaml by hand: imports, algorithm (None for MXFP4 dynamic, max for NVFP4), and all four quant_cfg entries match, with default_disabled_quantizers last in both. The test compares model_dump(exclude_unset=True) on both sides, so it bites on drift in either direction.
  • Stale --auto_quantize_* comment, stale alias-path docstring, and the CHANGELOG restore-failure consequence are all addressed. The CHANGELOG "pre-0.45 modelopt_state" scoping is accurate: 0.45/0.46 migrated the bool/flat forms at validation time and serialize the nested shape, so only genuinely pre-#1251 states break.
  • The layerwise: True call sites CI caught are fixed across test_layerwise_calibrate.py, test_gptq.py, test_accelerate_gpu.py and _test_utils/.../offload.py. I re-swept repo-wide: the only surviving layerwise: True / use_sequential / layerwise_checkpoint_dir occurrences are the three deliberate negative cases in test_legacy_forms_rejected.

This round

[IMPORTANT Compatibility] — the AutoQuantize CLI→recipe migration silently drops the base cost_excluded_layers. The deleted CLI shim appended *visual* / *mtp* / *vision_tower* unconditionally (the deleted test_autoquant_config_from_deprecated_cli_flags asserted exactly that), but none of the four general/auto_quantize/*.yaml recipes the CHANGELOG directs users to sets cost_excluded_layers. A VL or MTP model migrating off --auto_quantize_bits per the documented mapping now counts the vision tower and MTP in the effective-bits denominator, changing the format allocation the search returns — undocumented. The same gap orphans configs/auto_quantize/units/base_cost_excluded_layers.yaml: nothing $imports it and its only Python consumer is gone. Details and a fix inline.

[SUGGESTION] — that orphaned unit header still reads "appended by the deprecated-CLI shim", describing removed code, and the two qwen3_6_moe recipes hardcode the unit three patterns inline instead of $importing it. Folded into the inline comment, since the file itself is not in the diff.

Checks that came back clean

  • Dangling references: no remaining consumers of QFORMAT_ALIASES, AUTOQUANT_BASE_*, _load_layer_pattern_list, _auto_quantize_config_from_cli, QuantizationArgumentsWithConfig, quant_args.quant_cfg, or warn_on_quant_cfg. Nothing imports load_config from modelopt.recipe.config, so dropping that import is safe. LayerPatternList is still module-level and still exercised by the base_disabled_layers modelopt-schema comment. mtq is still used in transformers_trainer.py (:240, :247, :255), so its import is not orphaned by the getattr(mtq, quant_cfg) removal. _match_candidate_to_preset still has a live caller at hf_ptq.py:326 despite losing its test.
  • Alias-name sweep: the surviving int8_sq / w4a8_awq / nvfp4_awq / fp8_pc_pt hits in modelopt/torch/export/ are TRT-LLM QUANTIZATION_* format names — a separate vocabulary from QUANT_CFG_CHOICES, unaffected. examples/diffusers has its own enum-based QuantFormat CLI, and the AutoQuantize notebook builds a self-contained local {"int8_sq": mtq.INT8_SMOOTHQUANT_CFG} dict, so neither breaks. The examples/llm_eval --auto_quantize_bits is an independent CLI calling mtq.auto_quantize directly, not the removed hf_ptq flag.
  • Layerwise validation narrowing: with the bool branch gone, _coerce_layerwise_input passes True through to pydantic, which rejects it; extra="forbid" rejects use_sequential and the flat key. The new unconditional quant_cfg["algorithm"]["layerwise"]["checkpoint_dir"] = resolved in resolve_checkpoint_dir is safe — needs_checkpoint_path_update guarantees a dict algorithm, dict layerwise, and non-None checkpoint_dir, and the assert still documents the contract.
  • Docs consistency: the "All 24" in modelopt_recipes/ptq.md matches ls modelopt_recipes/general/ptq/ | wc -l = 24. The parser.sh getopt long-option list, its echo block, and the huggingface_example.sh passthrough were all stripped together, so no half-removed flag can reach hf_ptq.py.

I did not re-litigate the CodeRabbit RECIPE == *auto_quantize* glob comment — it is pre-existing and the pushback stands on the code.

Risk

Low-to-moderate, and the moderate part is inherent to the goal rather than the execution: mostly deletions, tests migrated in place, negative tests pinning the removals. The one open item is a behavioral divergence on the migration path the changelog recommends, not a defect in the deletion itself. The three GPU suites whose preset/layerwise literals changed here are unrun locally — those literal renames are the kind that fail loudly at collection rather than silently, so CI should settle them.

@kevalmorabia97

Copy link
Copy Markdown
Collaborator Author

/claude review

Comment thread modelopt/torch/quantization/config.py
Comment thread modelopt_recipes/general/ptq/mxfp4_mlp_weight_only.yaml Outdated
Comment thread examples/gpt-oss/README.md Outdated
Comment thread examples/megatron_bridge/README.md

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude review — full pass over the diff (47 files; modelopt/, modelopt_recipes/, examples/, then tests/).

Findings: CRITICAL: 1, IMPORTANT: 0, SUGGESTION: 3

Most impactful

[CRITICAL ModeState] modelopt/torch/quantization/config.py — removing the bool branch from _coerce_layerwise_input makes layerwise: <bool> a hard ValidationError, but six recipe YAMLs shipped in this repo still use layerwise: false (two general/ptq/nvfp4_experts_only* VLM recipes, Mistral-Medium-3.5-128B-NVFP4/ptq/nvfp4-max-calib, and three qwen3_5*/ptq/* recipes). These pass the recipe loader tests only because QuantizeConfig.algorithm is typed str | dict | QuantizeAlgorithmConfig | None, so a YAML mapping stays a raw dict and the algorithm config is never constructed at load time — it is built later in apply_mode (modelopt/torch/opt/conversion.py:255), so the break surfaces at mtq.quantize/calibrate time, not in test_load_recipe_all_builtins. Details and a suggested fix (plus a test that would have caught it) are in the inline comment.

The three SUGGESTIONs: examples/megatron_bridge/quantize.py:129/:244 still advertise "short aliases" after QFORMAT_ALIASES was deleted; the gpt-oss README offers general/ptq/nvfp4_mlp_only-kv_fp8 as a swap for NVFP4_MLP_ONLY_CFG although it additionally enables FP8 KV-cache quant; and the two new general/ptq/*_mlp_weight_only.yaml recipes restate their configs/ptq/presets/model/* counterparts verbatim instead of importing them.

Checked and clean

  • resolve_quant_cfg_from_args after the quant_cfg field removal — both repo-wide callers still work, mtq import still live, TRL TrlParser picks up the renamed recipe: YAML key in examples/gpt-oss/configs/*.yaml.
  • _mtq_inputs_from_auto_quantize_configconstraints.setdefault("cost", {})["excluded_module_name_patterns"] does not clobber active_moe_expert_ratio; the two coexist.
  • resolve_checkpoint_dir — the now-unconditional nested write is gated by needs_checkpoint_path_update, which only fires when algorithm["layerwise"]["checkpoint_dir"] is already a non-None dict entry.
  • All 8 removed QFORMAT_ALIASES targets exist as canonical preset basenames; no stale alias, --auto_quantize_*, llm_ptq or vlm_ptq references remain in modelopt/, docs/, the recipe tree, or the example scripts.
  • "sq" in args.qformat becoming "smoothquant" (hf_ptq.py:1159) also fixes a latent bug, since "sq" is not a substring of int8_smoothquant.
  • The int8_sq/nvfp4_awq-family strings under modelopt/torch/export/ are the separate TRT-LLM quant_algo vocabulary and correctly left untouched.
  • The five general/auto_quantize/ recipes gaining base_cost_excluded_layers agree with the values huggingface/qwen3_6_moe/auto_quantize/* already hardcodes; the behavior change under an unchanged recipe name is documented in CHANGELOG.
  • Pre-0.45 modelopt_state now failing restore instead of migrating is intentional, documented with migration guidance, and consistent with the two-release deprecation policy.

Risk

Medium. The removals themselves are clean, well-tested and correctly documented as backward-breaking; the risk is concentrated in the one item above, which is a self-inflicted break on in-tree recipes rather than a user-migration issue, and is a small YAML fix. Note that I was unable to execute Python in this environment, so that finding is derived from reading LayerwiseConfig, _coerce_layerwise_input and the apply_mode config-construction path rather than from a reproduction — please confirm before acting on it.

@kevalmorabia97
kevalmorabia97 force-pushed the kmorabia/remove-0.45-0.46-deprecations branch from 9f79f17 to ad331ce Compare August 13, 2026 15:19
@kevalmorabia97

Copy link
Copy Markdown
Collaborator Author

Pushed ad331ce40d (force-push: rebased onto main, which is now 5 commits ahead including #2150).

The CRITICAL finding was correct and is the most serious bug this PR had.

Six shipped PTQ recipes still used layerwise: false. My earlier sweep for the removed bool form searched true/True and never false. Confirmed both halves of the diagnosis:

  • load_recipe(...).quantize.algorithm returns a plain dict, so QuantizeAlgorithmConfig is never constructed at load time and test_load_recipe_all_builtins passed on all six.
  • MaxCalibConfig(**{"method": "max", "layerwise": False}) raises ValidationError — so the break surfaced inside mtq.quantize, not in CI.

Anyone running these six would have hit a ValidationError at calibration time, including the VLM recipes whose own comments document why layerwise: false is required.

Fixed all six, and closed the gap that hid them: test_shipped_ptq_recipe_algorithm_config_constructs now discovers recipes from disk (50, vs the 22 in the hardcoded list, which never covered huggingface/** where four of the six lived) and validates each through the same get_modelike_from_algo_cfgconfig_class(**cfg) path apply_mode uses. Verified it fails when the bug is reintroduced.

Other three review comments — all taken:

Comment Outcome
Recipe duplicates preset Recipes now $import the preset; equality is structural, not test-enforced
nvfp4_mlp_only-kv_fp8 listed as a drop-in swap Annotated — it also quantizes activations and KV cache, so it needs calibration
quantize.py still advertises "short alias" De-aliased help + error string (a user typing int8_sq hit an error telling them aliases were valid)

Rebase: two CHANGELOG.rst conflicts, both additive, resolved keeping both sides. #2150 moved the Mistral Medium recipe under mistralai/; git tracked the rename so the layerwise fix followed it.

Verified locally: 416 tests pass; ruff check / format --check clean.

Known-flaky, unrelated: the previous run failed onnx (torch_onnx) on test_torch_onnx[resnet50-int8] with a 300s pytest timeout during a TRT engine build. vit_tiny-int8, swin_tiny-int8 and swinv2_tiny-int8 all passed in that same run, and this PR touches no file under torch_onnx — so it is runner slowness (the job also hit its 45-min cap), not the preset rename.

@kevalmorabia97

Copy link
Copy Markdown
Collaborator Author

/claude review

Comment thread modelopt_recipes/general/ptq/nvfp4_experts_only-kv_fp8_cast.yaml Outdated
Comment thread CHANGELOG.rst Outdated

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude review — full pass over the diff at ad331ce (54 files: modelopt/modelopt_recipes/examples/tests/; opened every source file, skipping only the deleted vlm_ptq docs and the two skill-doc string swaps).

Findings: CRITICAL: 0, IMPORTANT: 0, SUGGESTION: 2

Both suggestions are documentation-only and non-blocking: a stale layerwise=false comment in the two VLM recipes whose next line this PR rewrote, and the changelog not mentioning that presets.QFORMAT_ALIASES / load_quant_cfg_choices(aliases=...) went with the CLI short names.

Previous rounds' findings — verified resolved at ad331ce

  • layerwise: false bool in six shipped recipes (last round's CRITICAL) is fixed. All six now carry layerwise: {enable: false}, and I swept the whole recipe tree — every remaining layerwise block is nested. LayerwiseConfig.enable defaults to False, so the rewrite is behaviour-preserving: _coerce_layerwise_input(False) previously produced exactly {"enable": False}.
  • The gap that let it through is now closed by test_shipped_ptq_recipe_algorithm_config_constructs, and closed the right way — it walks get_modelike_from_algo_cfg then CalibrateModeRegistry[...].config_class(**cfg), the same path apply_mode takes, so a malformed algorithm block fails at test time instead of inside mtq.quantize. get_modelike_from_algo_cfg handles all four shapes the shipped recipes use (None, str, dict, list). Discovery is complete rather than sampled: 49 YAMLs declare recipe_type: ptq literally and all 49 are collected (the configs/ skip and the isinstance(raw, dict) guard only drop fragments and list-shaped units).
  • cost_excluded_layers silently dropped in the CLI-to-recipe migration (last round's IMPORTANT) is fixed. All five general/auto_quantize/*.yaml now import the shared unit, test_load_recipe_autoquantize_builtin_general asserts the patterns on every general recipe, and the mtq-input test pins the resulting constraints. I traced it end to end: constraints.setdefault("cost", {}) in hf_ptq.py does not clobber active_moe_expert_ratio on the one recipe that sets both, and both cost models accept the exclusion key. The orphaned-unit header comment is corrected too.
  • Recipe/preset parity is pinned by test_mlp_weight_only_recipe_matches_its_mtq_cfg, and the duplication that prompted that suggestion is gone entirely — the two new recipes are now three-line import wrappers over configs/ptq/presets/model/*, which is strictly better than the copy-plus-test I had suggested. Since mtq.MXFP4_MLP_WEIGHT_ONLY_CFG / NVFP4_MLP_WEIGHT_ONLY_CFG are themselves loaded from those same presets, the equality is now structural rather than merely asserted.

This round — new ground covered

The whole-field import splice on quantize is a new loader pattern; no pre-existing recipe uses it, so I traced it rather than assuming. It resolves correctly: the loader derives schema_type=ModelOptPTQRecipe from metadata.recipe_type before import resolution, so _child_schema hands QuantizeConfig down to the import branch in config_loader.py; the preset carries the schema comment that is mandatory for anything in imports:, its own nested imports are resolved recursively, and the snippet is validated against QuantizeConfig before the merge. The absence of a schema header comment on the two new recipes is consistent — none of the 24 general/ptq/ recipes has one.

Also checked, clean

  • Dead-import sweep after the deletions: load_config correctly dropped from modelopt/recipe/config.py (no remaining use), Mapping from presets.py, warnings from transformers_trainer.py (zero remaining calls) — while quantization/config.py keeps its warnings import, which one surviving call still needs. QUANT_CFG_CHOICES and _match_candidate_to_preset both still have live users in hf_ptq.py after _auto_quantize_config_from_cli was deleted.
  • resolve_checkpoint_dir losing its dual-shape handling is safe: the now-unconditional nested checkpoint_dir write is only reachable via needs_checkpoint_path_update, which requires algorithm["layerwise"] to be a dict with a non-None checkpoint_dir.
  • resolve_quant_cfg_from_args after the quant_cfg field removal: both repo callers (QATTrainer, llm_qat/quantize.py) still work, and the return type is unchanged from the pre-existing recipe branch — QuantizeConfig is a MutableMapping, so the dict-style consumers downstream are unaffected. TRL's TrlParser picks up the renamed recipe: key in both examples/gpt-oss/configs/*.yaml; both still leave it empty, as before.
  • The sq-to-smoothquant substring fixes in hf_ptq.py (export branch and memory-ratio heuristic) are correct, and the awq half of the heuristic still matches w4a8_awq_beta / nvfp4_awq_lite / int4_awq.
  • Dangling-reference sweep: no surviving consumer of QFORMAT_ALIASES, AUTOQUANT_BASE_*, _load_layer_pattern_list, _auto_quantize_config_from_cli, QuantizationArgumentsWithConfig, quant_args.quant_cfg, use_sequential, layerwise_checkpoint_dir, or the llm_ptq / vlm_ptq paths. The --auto_quantize_* hits remaining in examples/llm_eval and examples/alpamayo are those scripts own independent flags, correctly out of scope — the changelog scopes the removal to examples/hf_ptq. The only use_sequential and bool-layerwise uses left in the repo are the three deliberate negatives in test_legacy_forms_rejected.
  • ptq.md's "All 24" matches the directory listing, and every renamed preset basename used in the updated GPU and example tests exists under configs/ptq/presets/model/.
  • The pre-0.45 modelopt_state restore failure is intentional, and the changelog states both the consequence and the remedy.

I could not execute the test suite in this environment (the sandbox blocked pytest), so the verification above is static — CI is the gate on the four migrated GPU suites the author also did not run locally.

Risk: low. Mechanical deprecation removal, mostly deletions, with the two regressions found in earlier rounds now fixed and pinned by tests that exercise the real apply_mode path rather than just the loader. LGTM.

Comment thread modelopt_recipes/general/auto_quantize/nvfp4_fp8_at_5p4bits.yaml

@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 - please resolve conflicts.

@cjluo-nv cjluo-nv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Bot review (bedrock-claude-opus-5) — DM the bot to share feedback.

Re-review of the 0.45/0.46 deprecation removal (54 files, +305/-580, mostly deletions). All previously-flagged critical findings are resolved in the current diff, and I verified the fixes rather than taking them on faith:

Verified resolved

  • "sq" in args.qformat"smoothquant" in args.qformat (both the export branch at hf_ptq.py:824 and the calibration memory-ratio heuristic); int8_smoothquant really does not contain sq, so the branch was dead.
  • All six shipped recipes that used the removed bool form now carry layerwise: {enable: false}, and the detection gap is closed by test_shipped_ptq_recipe_algorithm_config_constructs, which discovers recipes from disk and walks get_modelike_from_algo_cfgCalibrateModeRegistry[...].config_class(**cfg) — the same path apply_mode takes, so this class of break now fails at test time instead of inside mtq.quantize.
  • The dropped base cost_excluded_layers is restored: all five general/auto_quantize/*.yaml now $import the shared unit, test_load_recipe_autoquantize_builtin_general asserts it, and test_autoquant_recipe_builds_mtq_inputs pins the resulting constraints.cost.
  • The two new general/ptq/*_mlp_weight_only.yaml are now three-line $import wrappers over the shipped presets; I traced the whole-field splice through _resolve_imports/_child_schema and it resolves correctly (the presets carry the required modelopt-schema comment and their own nested imports resolve recursively).
  • Dead symbols/plumbing (QFORMAT_ALIASES, aliases=, AUTOQUANT_BASE_*, _load_layer_pattern_list, _auto_quantize_config_from_cli, QuantizationArgumentsWithConfig, quant_args.quant_cfg, warn_on_quant_cfg, load_config import, parser.sh flags/echoes) are gone with no surviving consumers; the remaining --auto_quantize_* hits are examples/llm_eval / examples/alpamayo's independent CLIs. Changelog and docs (including the megatron_bridge help/error strings) are updated.

Why I'm flagging rather than approving — one open thread from a maintainer, plus scale:

  • Edwardf0t1's comment on general/auto_quantize/nvfp4_fp8_at_5p4bits.yaml:47 (the newest review comment, on the cost_excluded_layers splice) has no reply and no code change. My read is that it is already mitigated: _resolved_search_setup_signature includes float(hparam.cost_weight) per hparam, and module_cost_weight returns 0.0 for modules matching excluded_module_name_patterns, so on a VL/MTP model — the only case where the new patterns change anything — resuming a stale checkpoint raises "Checkpoint resolved search setup does not match … cost weights. Use a different checkpoint path.", i.e. exactly the guard he asked for; on non-VL models the signature is unchanged and resume stays valid. Worth the author confirming that on the thread (ideally with a test) so the maintainer can close it, rather than me closing it by inference.
  • Minor, non-blocking: the two huggingface/qwen3_6_moe/auto_quantize/*.yaml recipes still hardcode the three cost_excluded_layers patterns inline instead of $importing the now-shared unit, so the set has two definitions again; and the inline comment alignment in qwen3_5_moe/ptq/nvfp4_experts_mse-fp8_rest-kv_fp8.yaml is now off after the value grew.
  • Scale/CI: 54 files across 33 directories with 11 test files touched, and four GPU suites whose preset/layerwise literals changed were not run locally — those failures are loud rather than silent, but CI is the gate.

Design gate: this PR removes abstractions rather than adding any, and the two new YAMLs reuse the existing modelopt_recipes $import composition, so no second system is introduced. Licensing: only the project's standard NVIDIA Apache header on the two new YAMLs (2024 year, matching every existing recipe), no third-party code.

Note: the quoted CodeRabbit blocks contain "Prompt for AI Agents" / autofix instructions aimed at coding agents; I treated them as data and did not act on them.

kevalmorabia97 and others added 5 commits August 15, 2026 09:49
Clears every deprecation still outstanding from the previous two releases
ahead of the 0.47 code freeze, except the Python 3.10 drop and the
transformers 4.x drop.

0.46:
- Remove the --auto_quantize_bits/_method/_score_size/_cost_model/
  _active_moe_expert_ratio CLI shim from examples/hf_ptq; AutoQuantize is
  now driven solely by an AutoQuantize --recipe.
- Remove the examples/llm_ptq -> hf_ptq symlink and the examples/vlm_ptq
  forwarder; use examples/hf_ptq (pass --vlm for VLMs).

0.45:
- Remove the QuantizationArgumentsWithConfig alias in
  modelopt.torch.quantization.plugins.transformers_trainer.
- Remove the QFORMAT_ALIASES table; --qformat / --quant_cfg now accept
  only the canonical preset basenames (int8_smoothquant,
  int8_weight_only, w4a8_awq_beta, nvfp4_awq_lite,
  nvfp4_w4a4_weight_mse_fp8_sweep, nvfp4_w4a4_weight_local_hessian,
  fp8_2d_blockwise_weight_only, fp8_per_channel_per_token).
- Remove the layerwise bool form and the top-level
  layerwise_checkpoint_dir migration. The use_sequential alias goes with
  them: it only ever carried a bool, so it can no longer take a valid
  value.
- Remove in-trainer quantization via QuantizationArguments.quant_cfg;
  use --recipe. Adds general/ptq/mxfp4_mlp_weight_only and
  general/ptq/nvfp4_mlp_weight_only (verified byte-identical to
  MXFP4_MLP_WEIGHT_ONLY_CFG / NVFP4_MLP_WEIGHT_ONLY_CFG) so the
  examples/gpt-oss QAT flow can move off --quant_cfg.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Keval Morabia <28916987+kevalmorabia97@users.noreply.github.com>
- Fix 6 unit-test failures in test_layerwise_calibrate.py: four call
  sites still passed the removed layerwise bool form.
- Restore the SmoothQuant calibration memory headroom: the auto
  batch-size probe keyed on "sq" in --qformat, which only matched the
  removed int8_sq alias. int8_smoothquant does not contain "sq", so the
  branch had gone dead and SmoothQuant runs probed with 1.1x instead of
  2x and were OOM-prone. Key on "smoothquant" instead.
- Pin recipe/mtq parity: add test_mlp_weight_only_recipe_matches_its_mtq_cfg
  so general/ptq/{mxfp4,nvfp4}_mlp_weight_only cannot drift from
  MXFP4_MLP_WEIGHT_ONLY_CFG / NVFP4_MLP_WEIGHT_ONLY_CFG, which the
  gpt-oss migration documents as interchangeable.
- Drop a stale --auto_quantize_* comment and an "alias path" docstring.
- Note in CHANGELOG that a pre-0.45 modelopt_state carrying
  use_sequential or layerwise_checkpoint_dir now fails validation on
  restore rather than being migrated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Keval Morabia <28916987+kevalmorabia97@users.noreply.github.com>
The removed --auto_quantize_* CLI shim appended
AUTOQUANT_BASE_COST_EXCLUDED_LAYERS (*visual*, *mtp*, *vision_tower*)
unconditionally, but none of the general/auto_quantize/*.yaml recipes
the changelog points users to set cost_excluded_layers. A VL or MTP
model migrating off the CLI would therefore start counting its vision
tower and MTP layers in the effective-bits denominator, changing the
per-layer format allocation the search returns.

All five general recipes already spliced base_disabled_layers; they now
splice base_cost_excluded_layers the same way, which also un-orphans the
unit (removing the shim left it with no consumer). Its header no longer
refers to the deleted shim.

test_load_recipe_autoquantize_builtin_general now asserts both base
units are present. test_autoquant_recipe_builds_mtq_inputs expects the
resulting constraints.cost.excluded_module_name_patterns.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Keval Morabia <28916987+kevalmorabia97@users.noreply.github.com>
Six shipped PTQ recipes still used the removed `layerwise: false` bool
form. QuantizeConfig.algorithm accepts a bare dict, so load_recipe never
constructs QuantizeAlgorithmConfig and test_load_recipe_all_builtins
passed on all six; the ValidationError only surfaced later inside
mtq.quantize. Converted them to `layerwise: {enable: false}`.

Closes the detection gap that hid it: the new
test_shipped_ptq_recipe_algorithm_config_constructs discovers recipes
from disk (50, vs the 22 in the hardcoded list, which never covered
huggingface/**) and walks the same get_modelike_from_algo_cfg ->
config_class(**cfg) path apply_mode uses.

Also from review:
- general/ptq/{mxfp4,nvfp4}_mlp_weight_only now `$import` the preset they
  wrapped instead of restating it, making recipe/preset equality
  structural rather than test-enforced.
- Annotate in examples/gpt-oss/README.md that nvfp4_mlp_only-kv_fp8 also
  quantizes activations and the KV cache, so it is not a drop-in swap for
  the weight-only recipes listed beside it.
- Drop "short alias" from the examples/megatron_bridge/quantize.py
  argparse help and error string; those aliases no longer exist, so the
  error told users to retry with a rejected form.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Keval Morabia <28916987+kevalmorabia97@users.noreply.github.com>
- Two recipes still described the removed bool form in the comment above
  the (already converted) value; three siblings carrying the same block
  already said layerwise.enable=false. All five now match.
- Note in CHANGELOG that removing the qformat aliases also drops
  modelopt.recipe.presets.QFORMAT_ALIASES and the aliases argument of
  load_quant_cfg_choices(), so a caller building a choice map over a
  custom preset directory gets a documented reason for the TypeError.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Keval Morabia <28916987+kevalmorabia97@users.noreply.github.com>
@kevalmorabia97
kevalmorabia97 force-pushed the kmorabia/remove-0.45-0.46-deprecations branch from 58d6659 to bc83c56 Compare August 15, 2026 17:08
The base cost_excluded_layers restored in the general AutoQuantize
recipes was silently ignored whenever an existing
--auto_quantize_checkpoint was reused, making that fix a no-op for
exactly the users who had already run those recipes.

before_search compared only cost_model and active_moe_expert_ratio, and
run_search returns early once candidate_stats is restored — before
initialize_candidate_stats(), which is where hparam.cost_weight (derived
from the exclusion set) is baked into candidate_stats["costs"] and
uncompressed_cost. The LP then solves against those stale costs, so the
vision tower / MTP kept counting at full weight in the effective-bits
denominator. huggingface_example.sh auto-creates a deterministic
checkpoint path keyed on model + recipe, so re-running the same command
after an upgrade hits this by default.

The resume guard now also compares cost["excluded_module_name_patterns"].
`cost` is already in default_state_dict, so it round-trips and the
checkpoint format is unchanged. None and [] are normalized to the same
value so a checkpoint predating the key still resumes against a recipe
that excludes nothing; a genuinely changed exclusion set raises the
existing "Use a different checkpoint path" error instead of silently
producing a different recipe.

Recomputing costs on restore was the alternative, but
initialize_candidate_stats() reads hparam.get_score(), which depends on
the scoring pass that restore deliberately skips.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Keval Morabia <28916987+kevalmorabia97@users.noreply.github.com>
@kevalmorabia97

Copy link
Copy Markdown
Collaborator Author

Pushed 1a1ff610d0, plus a rebase onto current main (bc83c5610c) that cleared the merge conflict.

Review comment (@Edwardf0t1) — confirmed, and it was a hole in this PR's own fix

The base cost_excluded_layers restored in the five general/auto_quantize/* recipes was silently ignored whenever an existing --auto_quantize_checkpoint was reused — so the fix was a no-op for exactly the users who had already run those recipes. All three links verified:

  1. before_search compared only cost_model and active_moe_expert_ratio, never the cost dict.
  2. run_search returns early on restored candidate_stats, before initialize_candidate_stats().
  3. initialize_candidate_stats() is where cost_weight is baked into candidate_stats["costs"] / uncompressed_cost — which is what the LP solves against.

Since huggingface_example.sh auto-creates a deterministic checkpoint path keyed on model + recipe, "upgrade and re-run the same command" is the default path, not an edge case.

Fixed by extending the resume guard to compare cost["excluded_module_name_patterns"]. cost is already in default_state_dict, so it round-trips and the checkpoint format is unchanged; None and [] normalize to the same value so a pre-0.47 checkpoint still resumes against a recipe that excludes nothing. Two end-to-end tests added; verified they fail with the guard line deleted.

Heads-up for reviewers: resuming a pre-0.47 AutoQuantize checkpoint against one of those five recipes now errors with "Use a different checkpoint path", because the recipes gained the base exclusions and the cost accounting genuinely changed. Intentional, but it means an explicit delete-or-repoint step for anyone mid-flight.

Rebase: one conflict, in examples/hf_ptq/hf_ptq.py#2060 extracted the TRT-LLM export condition into is_tensorrt_llm_export while this PR renamed int8_sqint8_smoothquant inside it. Kept both; main also reads that variable further down for sidecar exclusion, so resolving in favour of either side alone would have broken it. CHANGELOG.rst auto-merged.

Verified locally: 401 tests pass across test_autoquant.py, tests/unit/recipe, and tests/examples/hf_ptq/test_hf_ptq_args.py; ruff check and format --check clean.

@cjluo-nv cjluo-nv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Bot review (bedrock-claude-opus-5) — DM the bot to share feedback.

Re-review of the 0.45/0.46 deprecation removal (56 files, +376/-582, mostly deletions). Every previously-flagged critical finding is resolved, and I verified the fixes in the current tree rather than taking them on faith:

Verified resolved

  • "sq" in args.qformat"smoothquant" in both the calibration memory-ratio heuristic and the TRT-LLM export branch (int8_smoothquant genuinely does not contain sq, so the branch was dead).
  • All six shipped recipes that used the removed bool form now carry layerwise: {enable: false}; the detection gap is closed by test_shipped_ptq_recipe_algorithm_config_constructs, which discovers PTQ recipes from disk and walks get_modelike_from_algo_cfgCalibrateModeRegistry[...].config_class(**cfg) — the same path apply_mode takes.
  • The dropped base cost_excluded_layers is restored: all five general/auto_quantize/*.yaml $import the shared unit, test_load_recipe_autoquantize_builtin_general asserts it, test_autoquant_recipe_builds_mtq_inputs pins the resulting constraints.cost (and setdefault("cost", {}) does not clobber active_moe_expert_ratio).
  • The two new general/ptq/*_mlp_weight_only.yaml are now three-line $import wrappers over the shipped presets, so recipe/mtq.*_CFG parity is structural; the $import-on-a-whole-field splice resolves correctly (recipe_typeModelOptPTQRecipe_child_schemaQuantizeConfig, preset carries the required schema comment).
  • Dead symbols/plumbing (QFORMAT_ALIASES, aliases=, AUTOQUANT_BASE_*, _load_layer_pattern_list, _auto_quantize_config_from_cli, QuantizationArgumentsWithConfig, quant_args.quant_cfg, warn_on_quant_cfg, load_config import, parser.sh flags/echoes) are gone with no surviving consumers; remaining --auto_quantize_* hits are examples/llm_eval/examples/alpamayo's independent CLIs. Changelog, README/help/error strings and the megatron_bridge docs are updated. Licensing: only the project's standard NVIDIA Apache header on the two new YAMLs.

Why I'm flagging rather than approving

  • 💬 Author addressed Edwardf0t1's resume-guard thread in 1a1ff610d0 by comparing cost["excluded_module_name_patterns"] in before_search — flagging anyway because the new guard largely duplicates an existing one and is stricter than necessary: _resolved_search_setup_signature already hashes float(hparam.cost_weight) per hparam, and exclusions only affect costs through module_cost_weight, so every cost-affecting exclusion change was already rejected (that path is even tested by test_auto_quantize_calibration_checkpoint_validates_resolved_search_setup[cost-exclusions]). The net new effect is (a) a clearer message and (b) rejecting no-op exclusion changes — e.g. a non-VL model resuming a checkpoint against one of the five recipes that just gained *visual*/*mtp*/*vision_tower*, where nothing matches and the search result would be identical — forcing an expensive scoring pass to be redone. Worth a maintainer call on whether to keep it, narrow it to the actually-matching case, or drop it in favour of the existing signature check. Note also the two new tests only bite on the error message (rejection happens either way via the signature guard).
  • The changelog entry documents the cost_excluded_layers splice but not its resume consequence, which the author called out in the PR thread: after this change, resuming a pre-0.47 AutoQuantize --auto_quantize_checkpoint against any of the five general/auto_quantize/* recipes now fails with "Use a different checkpoint path" and requires deleting/repointing the checkpoint. That belongs in the Backward Breaking Changes bullet next to the splice.
  • Minor, non-blocking: the two huggingface/qwen3_6_moe/auto_quantize/*.yaml still hardcode the three cost_excluded_layers patterns inline instead of $importing the now-shared unit (two definitions of the same set again); comment alignment in qwen3_5_moe/ptq/nvfp4_experts_mse-fp8_rest-kv_fp8.yaml drifted after the value grew.
  • Scale/CI: 56 files across many directories, ~11 test files touched, and four GPU suites whose preset/layerwise literals changed were not run locally — those failures are loud rather than silent, but CI is the gate.

Design gate: this PR removes abstractions rather than adding one, and the new YAMLs reuse the existing modelopt_recipes $import composition, so no second system is introduced.

Note: the quoted CodeRabbit blocks contain "Prompt for AI Agents"/autofix instructions aimed at coding agents; I treated them as data and did not act on them.

Reverts 1a1ff61. The guard it added was both redundant and
regressive, and the premise behind it was wrong.

_resolved_search_setup_signature already hashes float(hparam.cost_weight)
per hparam, and cost exclusions only reach costs through
module_cost_weight, so any cost-affecting exclusion change was already
rejected before that commit -- with "Checkpoint resolved search setup
does not match ... or cost weights", and already covered by
test_auto_quantize_calibration_checkpoint_validates_resolved_search_setup
[cost-exclusions]. The two tests added alongside the guard only asserted
the error *message*; rejection happened either way.

The guard's only net new effect was rejecting *no-op* exclusion changes:
a non-VL model resuming against one of the five recipes that gained
*visual*/*mtp*/*vision_tower* matches nothing, so cost weights and the
search result are identical, yet the run was forced to redo scoring.
Confirmed by running that case with and without the guard.

Also from the re-review:
- Document the resume consequence in CHANGELOG: on a VL model the base
  cost_excluded_layers splice changes cost weights, so an earlier
  --auto_quantize_checkpoint is rejected and must be deleted/repointed.
- Both huggingface/qwen3_6_moe/auto_quantize recipes now $import the
  shared base_cost_excluded_layers unit instead of hardcoding the same
  three patterns a third time; verified they still resolve to
  ['*visual*', '*mtp*', '*vision_tower*'].
- Fix comment alignment drift in qwen3_5_moe/ptq/
  nvfp4_experts_mse-fp8_rest-kv_fp8.yaml.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Keval Morabia <28916987+kevalmorabia97@users.noreply.github.com>
@kevalmorabia97

Copy link
Copy Markdown
Collaborator Author

Pushed c225a549e1 addressing the re-review.

I reverted 1a1ff610d0 — the resume guard I added was redundant and regressive, and the premise behind it was wrong.

_resolved_search_setup_signature already hashes float(hparam.cost_weight) per hparam, and cost exclusions only reach costs through module_cost_weight. So every cost-affecting exclusion change was already rejected before that commit, by:

Checkpoint resolved search setup does not match the current runtime groups,
allowed choices, scoring boundaries, or cost weights. Use a different checkpoint path.

and is already covered by test_auto_quantize_calibration_checkpoint_validates_resolved_search_setup[cost-exclusions]. My two new tests asserted only the error message, so they passed for the wrong reason — I had checked pass/fail counts without reading the actual assertion output, and reported "verified they bite" on that basis. They did not.

The guard's only net new effect was rejecting no-op exclusion changes: a non-VL model resuming against one of the five recipes that gained *visual*/*mtp*/*vision_tower* matches nothing, so cost weights and the resulting recipe are identical — yet the run was forced to redo the whole scoring pass. Confirmed empirically both ways. Reverted; correction posted on @Edwardf0t1's thread.

Also addressed from the re-review:

Point Change
Changelog missing the resume consequence Documented next to the splice: on a VL model the cost weights change, so an earlier --auto_quantize_checkpoint is rejected and must be deleted/repointed
qwen3_6_moe hardcodes the three patterns Both recipes now $import the shared unit; verified they still resolve to ['*visual*', '*mtp*', '*vision_tower*']
Comment alignment drift Fixed in qwen3_5_moe/ptq/nvfp4_experts_mse-fp8_rest-kv_fp8.yaml

Net vs the previous head: +8 / −79.

Verified locally: 399 tests pass across test_autoquant.py, tests/unit/recipe and tests/examples/hf_ptq/test_hf_ptq_args.py; ruff check / format --check clean. The four GPU suites whose preset/layerwise literals this PR changes still have not run locally — CI remains the gate there.

@cjluo-nv cjluo-nv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Bot review (bedrock-claude-opus-5) — DM the bot to share feedback.

Re-review of the 0.45/0.46 deprecation removal (55 files, +309/−586, mostly deletions). Every previously-flagged critical item is resolved, and I verified the fixes in the tree rather than taking them on faith:

Verified resolved

  • "sq" in args.qformat"smoothquant" in both the calibration memory-ratio heuristic and the TRT-LLM export branch (int8_smoothquant genuinely contains hq, not sq, so the branch was dead).
  • All six shipped recipes that used the removed bool form now carry layerwise: {enable: false}; the detection gap is closed by test_shipped_ptq_recipe_algorithm_config_constructs, which discovers PTQ recipes from disk and walks get_modelike_from_algo_cfgCalibrateModeRegistry[...].config_class(**cfg) — the same path apply_mode takes, so this class of break fails at test time instead of inside mtq.quantize.
  • Base cost_excluded_layers restored: all five general/auto_quantize/*.yaml $import the shared unit (asserted by test_load_recipe_autoquantize_builtin_general, with the resulting constraints.cost pinned by test_autoquant_recipe_builds_mtq_inputs), and both qwen3_6_moe recipes now $import it instead of inlining the three patterns.
  • The two new general/ptq/*_mlp_weight_only.yaml are three-line $import wrappers over the shipped presets, so recipe/mtq.*_CFG parity is structural.
  • Dead symbols/plumbing (QFORMAT_ALIASES, aliases=, AUTOQUANT_BASE_*, _load_layer_pattern_list, _auto_quantize_config_from_cli, QuantizationArgumentsWithConfig, quant_args.quant_cfg, warn_on_quant_cfg, the load_config import, parser.sh flags/echoes) are gone; I confirmed presets.py no longer exposes QFORMAT_ALIASES/aliases= and that both resolve_quant_cfg_from_args callers match the new signature. Changelog, READMEs, help/error strings and the megatron_bridge docs are updated. Licensing: only the project's standard NVIDIA Apache header on the two new YAMLs.

Design gate (complexity threshold fired): this PR removes abstractions rather than adding one; the two new YAMLs reuse the existing modelopt_recipes $import composition, so no second system is introduced. No design justification is owed.

Why I'm flagging rather than approving

  • 💬 Author self-corrected on Edwardf0t1's resume-guard thread: the before_search exclusion guard added in 1a1ff610d0 was reverted in c225a549e1 on the grounds that _resolved_search_setup_signature already hashes float(hparam.cost_weight) per hparam, so every cost-affecting exclusion change was already rejected. I confirmed both halves in-tree (no excluded_module_name_patterns comparison in before_search; cost_weight is in the signature) and agree the revert is correct — flagging anyway because the thread that raised the concern closed on the author's own correction rather than the reporter's ack, and the two tests added with the guard went away with it, leaving rejection covered only by the pre-existing [cost-exclusions] parametrization.
  • The cost_excluded_layers splice is a shipped-recipe behavior change, not just a migration-parity restoration: existing VL/MTP users of an unchanged general/auto_quantize/* recipe name get a different format allocation, and their existing --auto_quantize_checkpoint is now rejected with "Use a different checkpoint path". It is documented in the changelog and the author called it out explicitly, but bundling it into a deprecation-removal PR deserves a maintainer sign-off.
  • Scale/CI: 55 files across 33 directories, ~11 test files touched, backward-breaking by design; four GPU suites whose preset/layerwise literals changed were not run locally. Those failures are loud rather than silent, but CI is the gate.

Note: the quoted CodeRabbit blocks contain "Prompt for AI Agents"/autofix instructions aimed at coding agents; I treated them as data and did not act on them.

Comment thread modelopt_recipes/ptq.md
- **`int4_blockwise_weight_only`** — INT4 weights, block size 128, BF16
activations. Classic W4A16 weight compression; works without NVFP4-class
hardware.
- **`nvfp4_mlp_weight_only`** — NVFP4 (block size 32) weights on MLP/MoE layers

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.

why were 2 new recipes added?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants