New Features
Quantization
- Add NVFP4 and FP8 PTQ recipes with projection-output quantizers for Llama-Nemotron embedding and reranking models (
modelopt_recipes/huggingface/nemotron_llama/) and an end-to-end HF embedding/reranking quantize-to-ONNX example (examples/torch_onnx/hf_embedding_quant_to_onnx.py). Quantizing the projection-Linear outputs keeps TensorRT inter-layer activations in FP4, roughly halving engine activation memory versus the plainnvfp4preset. NVFP4/MXFP8 output quantizers now export through the dynamic quantize path.examples/torch_onnx/torch_quant_to_onnx.pyalso gains a--recipeflag to load quantization configs from YAML recipes instead of the removedmtq.*_CFGmodule-constant table. - Add an end-to-end FAR3D ONNX PTQ example with calibration data generation, INT8 and FP8 quantization, TensorRT engine building, and Argoverse 2 accuracy evaluation. See examples/onnx_ptq/far3d/README.md for details.
- Add Learned Scale Quantization (LSQ) and Dual-LSQ support for quantization-aware distillation, including learnable
amaxparameters, tied-scale and pre-scale options, focused NVFP4 recipes, and scale-only training. - Add a fused Triton fast path for the
local_hessianNVFP4 weight-scale search, roughly 34x faster than the Python reference sweep on a single 8192x4096 weight and bit-exact with it for fp32/fp16 weights. Used automatically duringlocal_hessiancalibration for both dense and fused-MoE expert weights; falls back to the reference sweep on CPU, when Triton is unavailable, or viaMODELOPT_NVFP4_TRITON_SWEEP=0. - Add NVFP4 Four-Over-Six (4/6) weight quantization (
mtq.NVFP4_FOUR_OVER_SIX_CFG): MSE weight calibration picks, per block, between an M=6 and an M=4 dynamic range (the choice is folded into the FP8 per-block scales), with thefour_over_six: trueflag normalizing those scales by 256 (vs 448) for M=4 headroom. Supported viamtq.quantizeand HF / Megatron export only -- notmtq.compress, which does not preserve the per-block M=4/M=6 choice. - Add dLLM (tied-weight PTQ and HF-checkpoint export) support for diffusion-based encoder-decoder LLMs (e.g. DiffusionGemma) whose encoder/decoder stacks share parameters via HF
_tied_weights_keys. Modules sharing a source weight are deduplicated at export (~42% storage reduction onnvfp4_experts_onlyfor tied 26B MoE checkpoints), a newsync_tied_input_amaxhelper max-merges per-sideinput_quantizer.amaxacross tied modules so single-backbone consumers don't clip either side, and the exported state dict is reordered so the canonical-side keys win the dedup. Ships a DiffusionGemma recipe undermodelopt_recipes/huggingface/diffusion_gemma/ptq/. Non-tied models see no behavioral change. - Add Torch-TensorRT FP8 deployment example for HuggingFace ViT (
examples/torch_trt/):torch_tensorrt_ptq.pycoversmtq.quantize→torch_tensorrt.compile(ir="dynamo"), andtorch_tensorrt_accuracy.pyreports the compiled model's ImageNet-1k top-1/top-5 accuracy (the unquantized baseline is Torch-TensorRT-compiled too, for an apples-to-apples comparison). Ships a ViT-tuned FP8 PTQ recipe undermodelopt_recipes/huggingface/vit/ptq/fp8.yamlthat quantizes the encoder Linears, patch-embednn.Conv2d,classifier, per-block LayerNorm inputs, and the attention Q/K/V BMMs and softmax. Verified ongoogle/vit-base-patch16-224: FP8 stays within 0.13 pp Top-1 of the FP16 baseline. - Add AutoQuantize recipe support:
mtq.auto_quantizecan be driven declaratively from a YAML recipe (RecipeType.AUTO_QUANTIZE/AutoQuantizeConfig) specifying candidate formats, theeffective_bitstarget, cost model (incl.active_moeandexcluded_module_name_patterns), scoring method, and disabled layers. Adds aneffective_bitscost-model override onQuantizeConfig/QuantizerAttributeConfig(block-scale-accurate NVFP4 = 4.5 viaconfigs/numerics/nvfp4). Shipped recipes live undermodelopt_recipes/general/auto_quantize/and model-specific ones undermodelopt_recipes/huggingface/<model>/auto_quantize/. - Add module-specific AutoQuantize search spaces through
mtq.auto_quantize(..., module_search_spaces=...)and recipe-levelauto_quantize.module_search_spaces. Glob-matched decision groups can override the global candidate formats and control whether BF16/no-quant is solver-selectable withallow_no_quant. A recipe can instead reuse a normal PTQquantizeconfig as the fixed baseline and list only the genuinely searched modules; fixed and searched groups stay in one calibration, scoring, effective-bits, checkpoint, and export flow. - Add
rotate.modeto torch quantizer configs. The default"rotate"keeps the existing rotate-before-quantize behavior;"rotate_back"enables fake-quant rotate → quantize → rotate-back for TensorQuantizer. - Add a
constant_amaxQuantizerAttributeConfigfield that pins a quantizer'samaxto a fixed value and skips activation calibration. Unlikeuse_constant_amax(which hardcodes 448.0 for KV-cache cast math and registers no buffer),constant_amaxstores the constant on the_amaxbuffer so it is used by both the fake-quant forward and the exported scaling factor — for NVFP4 activations,constant_amax: 2688.0yieldsinput_scale == 1.0. Shipsmodelopt_recipes/general/ptq/nvfp4_experts_only_input_scale1-kv_fp8_cast.yaml, which applies this to the MoE expert activation quantizers. - Add
MaxCalibConfig.skip_forward_without_activation_calib(opt-in, defaultFalse): max calibration skips theforward_loopwhen no enabled quantizer needs data-driven activation statistics — e.g. an experts-only recipe usingconstant_amax/use_constant_amax, or dynamic / MX quantization. Weight calibration still runs on the weight tensors directly, so quantized weights are unchanged. It is opt-in because theforward_loopcan carry caller-side effects (notably materializing sharded parameters under DeepSpeed ZeRO-3). Enabled by thenvfp4_experts_only_input_scale1-kv_fp8_castrecipe. - Add
examples/minimax_m3/hf_ptq_mixed_mxfp8_nvfp4.pyfor streaming MiniMax-M3 export and a model-specifichf_ptq.pyrecipe that produces an MXFP8 language-model base with MSE-calibrated NVFP4 routed experts directly from BF16. The NVFP4 expertinput_scaleis fixed to 1.0.
Speculative Decoding
- Add the D-PACE loss objective for DFlash speculative-decoding training (arXiv:2605.18810) and make it the default (
dflash_loss_objective: dpace). It replaces the static exponential position decay with dynamic, confidence-derived per-position weights that adapt to whichever block positions currently limit acceptance. Smoothing is controlled bydflash_dpace_alpha(default 0.5); setdflash_loss_objective: decayto restore the previous static schedule. Training-only and detached from the gradient (no architecture or inference change). - Add streaming speculative-decoding training (EAGLE3 / DFlash): the draft trains on base-model hidden states produced on the fly by a co-located
vllm serve(no disk dump), moved trainer-side over NIXL RDMA, scaling to multi-node (dedicated serve replicas + DDP trainers). New launcher examples for NVFP4 Kimi-K2.5 / K2.6 on GB200/aarch64 undertools/launcher/examples/moonshotai/. - Add Domino speculative-decoding training: the parallel DFlash draft backbone plus a lightweight GRU causal correction head, selected via
dflash_architecture_config.projector_type=domino. Trained with a base/final dual loss whosedflash_lambda_base_start/dflash_lambda_base_decay_ratiocurriculum decays the base-loss weight 1→0. Exports in the z-lab drafter format; recipe atmodelopt_recipes/general/speculative_decoding/domino.yaml. Training only — the inference path is not wired up yet.
Megatron Framework (M-LM / M-Bridge)
-
Add Minitron pruning support for Megatron-Core models with the following new attention and MoE variants. For these, only
hidden_sizeis pruned (alongside the usualffn_hidden_size/num_layers/ MoE dimensions); the variant-internal dimensions noted below are not pruned:- GatedDeltaNet (linear attention) and gated attention (
attention_output_gate), such as Qwen3.5 (hybrid GatedDeltaNet + gated-attention) language models, including MoE variants — attention / linear-attention heads are not pruned. - Multi-Latent Attention (MLA), such as DeepSeek — MLA latent ranks are not pruned.
- Latent MoE, such as Nemotron-3-Super —
hidden_sizepruning resizes the latent projections while the MoE latent dim itself is not pruned.
- GatedDeltaNet (linear attention) and gated attention (
-
Optimize Minitron pruning support for MoE models using the fused grouped GEMM experts (
TEGroupedMLP) in addition to the existingSequentialMLPpath.examples/megatron_bridge/prune_minitron.pynow uses grouped GEMM by default (pass--no_moe_grouped_gemmto fall back toTESequentialMLP). -
Add Minitron pruning support for the language model part of vision-language models (e.g. Qwen3.5-VL, Gemma3-VL) via
examples/megatron_bridge/prune_minitron.py. The language model is pruned while the vision tower is left intact and the full VLM is saved back;hidden_sizeis not pruned if it is shared with the vision projector. Pruning importance is estimated from image-text calibration (the full VLM forward over vision-conditioned activations) by default, or from a text dataset for text-only ablations. -
Add PTQ support for the language model part of vision-language models (e.g. Qwen3.5-VL, Gemma3-VL) via
examples/megatron_bridge/quantize.py. Only the language model is quantized (vision tower + projector left in full precision) and the full VLM is saved as a Megatron checkpoint. The calibration modality is inferred from--calib_dataset_name: an image-text dataset drives the full VLM forward (vision-conditioned activations), while a text dataset runs text-only calibration of the language model. Image-text calibration shards across data-parallel ranks (context parallelism is supported only for text-only calibration). HuggingFace unified export of a quantized VLM is not yet supported. -
Add Megatron-Bridge distillation and Quantization-Aware Distillation (QAD) support for the language model part of vision-language models (e.g. Qwen3.5-VL, Gemma3-VL) via
examples/megatron_bridge/distill.py. -
Add context-parallel (CP) and data-parallel (DP) support to the shared Megatron-Core inference/calibration utilities. Under CP,
get_megatron_calibration_forward_loopandmegatron_mmlupartition each sequence across CP ranks (zigzag load-balanced) and MMLU gathers per-rank logits back to the full sequence for last-token scoring. Under DP, calibration shards the dataset across data-parallel ranks (amax is max-reduced across the DP group insidemtq) andmegatron_mmlushards whole batches and all-reduces the per-subject counts. DP is implicit (world_size / (tp * pp * cp));examples/megatron_bridge/quantize.pygains a--cp_sizeflag. -
Add support for retaining all Megatron-Bridge distillation checkpoints via
distill.py --checkpoint_keep_last -1and exporting all or selected iterations withexport_distilled_megatron_to_hf.py --export_iterations. -
Add the
prepare_megatron_data_blendutility to prepare weighted Megatron data blends from YAML configs, including optional token-budgeted subsets for distillation workflows. See the Megatron data preparation guide.
Misc
- Add the
day0-releaseagent skill, a deterministic end-to-end driver that chains the PTQ → evaluation → comparison skills with an enforced gate after each stage (validating checkpoint coverage, evaluation-run completeness, and the baseline-vs-candidate accuracy threshold) and returns a publish decision (ACCEPT / REGRESSION / ANOMALOUS / INFEASIBLE). v1 reports and stops on regression; the recipe-search loop is deferred. - Add support for ONNX Q/DQ node placement for DLA via the new flag
--target_dla. - (Experimental) Add pruning examples for Qwen3.5-9B and Nemotron3-Nano using the new experimental puzzletron branch, this branch uses AutoModel for better parallelization and efficiency.
Backward Breaking Changes
- Remove the
examples/diffusers/evalimage-quality evaluation example (ImageReward / CLIP-IQA / CLIP metrics) and its references inexamples/diffusers/README.md. The example was deprecated in 0.45 and is no longer maintained. - Remove the deprecated
examples/llm_autodeployexample (deprecated in 0.45). Use TensorRT-LLM's AutoDeploy directly together with ModelOpt PTQ inexamples/hf_ptq. - Remove the deprecated
examples/llm_qadMegatron-LM QAD example (deprecated in 0.45). Use the megatron_bridge QAD example instead, which provides a simpler Python-based interface and better model coverage. - Dropped VILA / NVILA vision-language model support in
examples/hf_ptq. VILA's modeling code requires[transformers](=4.50.0, which conflicts with ModelOpt's minimum supportedtransformersversion. The VILA-specific bootstrap (repo clone,requirements-vila.txt) and loading paths inexample_utils.pyhave been removed. - Dropped Phi-4-multimodal and Phi-3-vision PTQ support in
examples/hf_ptq. Phi-4-multimodal's bundled remote code needstransformers<4.52, below ModelOpt's minimum of4.57; Phi-3-vision, the superseded predecessor in the same family, is dropped alongside it and is likewise broken on Transformers 5.x. The support-matrix row, thephi4mmmodel type, the multimodal-detection heuristics that only ever matched these two, thePhi3Image/PhiImageembedding-export exclusions, and themodelopt_recipes/huggingface/phi4mm/recipes have been removed. Text-only Phi-3/Phi-4 and Phi-3.5-MoE are unaffected.
Deprecations
examples/hf_ptqAutoQuantize is now driven by an AutoQuantize recipe (--recipe). The--auto_quantize_bits,--auto_quantize_method,--auto_quantize_score_size,--auto_quantize_cost_model, and--auto_quantize_active_moe_expert_ratioflags are deprecated but still work: they are converted into anAutoQuantizeConfigon the fly (emitting aDeprecationWarning) and will be removed in a future release. Prefer a recipe undermodelopt_recipes/general/auto_quantize/. Seeexamples/hf_ptq/README.md.- Renamed
examples/llm_ptqtoexamples/hf_ptqto reflect that it covers Hugging Face LLM and VLM PTQ. A relative symlinkexamples/llm_ptqtohf_ptqkeeps existing paths and commands working; it will be removed in a future release. Please update references to the newexamples/hf_ptqpath. - Consolidated
examples/vlm_ptqintoexamples/hf_ptq. Vision-language model PTQ now shares thehf_ptq.pyentry point andscripts/huggingface_example.sh; pass--vlmto run the TensorRT-LLM multimodal quickstart smoke test. Theexamples/vlm_ptq/scripts/huggingface_example.shentry point is deprecated: it now prints a warning and forwards to thehf_ptqscript with--vlm, and will be removed in a future release. See `examples/hf_ptq/README.md <https://github.com/NVIDIA/Model-Optimizer/tree/main/examples/hf_ptq#vlm-quantization). - Bump minimum transformers version to
4.57instead of4.56. Transformers 4.x support will be dropped in a future release. - Bump minimum nemo container requirement to
nemo:26.04(recommendednemo:26.06) for Megatron-Bridge / Megatron-LM optimization features. - Python 3.10 support will be dropped in the next release as it is reaching EOL.
Bug Fixes
- Fix NemotronH dense MLP quantization with the
nvfp4_mlp_onlyandnvfp4_omlp_onlyrecipe families. NemotronH registers these projections asmixer.up_proj/mixer.down_proj, which the previous*mlp*selector missed, producing checkpoints with a nullquant_algo. - Fix
ShapeInferenceErrorduring ONNX INT8 + FP16 quantization (--high_precision_dtype fp16) of weakly-typed models (e.g. TensorFlow exports) that carry stale rank-0graph.outputshapes or ops such asTopKthat ONNX's static shape inference cannot resolve. Stale output shapes are now reconciled via symbolic shape inference, and AutoCast falls back to schema-based type inference so unresolved ops no longer leave tensors untyped. - Fix fused MoE expert auto-detection (
register_fused_experts_on_the_fly) skipping modules without anact_fnattribute. Modules applying a custom gated activation between the twoF.linearcalls (e.g.MiniMaxM3VLExperts) were silently skipped, leaving routed experts unquantized and failing HF export. Enables NVFP4/FP8 quantization and export for MiniMax-M2 / MiniMax-M3. - Fix unified HF export emitting transformers' in-memory (post-
conversion_mapping) tensor names instead of the original model-hub names, breaking the unified-checkpoint contract (observed on MiniMax-M3). A new quant-aware reverse conversion derives the rename/split rules from the model's conversion mapping and carries each weight's companion scale tensors through the renames and un-fusions, so quantized exports round-trip to the hub names. Mapping ops that cannot be reversed quant-aware yet (e.g. still-stacked fused experts) fall back to the in-memory names instead of aborting the export. - Fix unified HF export of already-compressed NVFP4 weights, i.e.
mtq.compressandhf_ptq.py --low_memory_mode, writing aweight_scaleof half the required size with meaningless values (the per-block scale cannot be recomputed from packed nibbles). The export now reuses the per-block scale captured at compression time. The internal_scale/_double_scalequantizer buffers are also removed after use; they previously leaked into the checkpoint and made downstream loaders (vLLM, TensorRT-LLM PyTorch backend) fail withKeyError. - Fix ONNX FP16/BF16 conversion (
--high_precision_dtype fp16) producing inconsistent tensor types on models with control-flow subgraphs. Subgraph nodes now only run in low precision when all their float inputs are subgraph initializers, outer-scope captures and precision boundaries are reconciled withCastnodes, andConstantfolding refreshesvalue_infoso strongly-typed parsers (TensorRT) no longer reject the model. Behavioral change: a weight inside a branch that also reads an outer-scope FP32 activation now stays FP32 instead of being converted. - Nested submodel reverse mappings are now scoped against registered model namespaces, preventing text-only mappings from capturing an already nested VLM's
model.visual.*namespace or double-prefixingmodel.language_model.*(observed on Qwen3.5). - Fix vLLM 0.24+ support, where
FusedMoEbecame a factory function and the expert weights moved onto aRoutedExpertssubmodule, breaking everyQuantModuleRegistrylookup withTypeError: issubclass() arg 2 must be a class. The plugin now registers whichever fused-MoE module class the installed release provides. The registry key movesvllm_FusedMoEtovllm_RoutedExpertsand quantizer paths gain.routed_experts, so an oldermodelopt_statedoes not restore onto 0.24+ as-is. - Fix
examples/vllm_serveserving shared experts uncalibrated: theirgate_proj/up_projquantizer keys were not merged intogate_up_projon reload, so they matched no module and were dropped. - Fix Qwen3-VL MoE PTQ failing on
transformers>=5.12withAttributeError: 'QuantQwen3VLMoeTextExperts' object has no attribute 'hidden_size'. transformers 5.12 movedQwen3VLMoeTextExpertsonto the standard fused-experts layout, but the legacy static wrapper shadowed on-the-fly detection. The new layout is now claimed byregister_fused_experts_on_the_fly; the legacy wrapper is still registered ontransformers<5.12, whosetorch.bmm-based forward the generic wrapper cannot intercept. - Fix
examples/hf_ptqmulti-node FSDP2 export (--use_fsdp2) failing withRuntimeError: Cannot set version_counter for inference tensor.export_quantizednow runs undertorch.no_grad()instead oftorch.inference_mode(), so the gathered full params stay normal tensors. - Fix HF checkpoint export failing with
AttributeError: 'list' object has no attribute 'keys'for models whose modeling code still declares tied weights in thetransformers<5list format (common amongtrust_remote_codecheckpoints, e.g.stepfun-ai/Step-3.7-Flash). Such models load fine but died at the end of PTQ, after calibration. ModelOpt'ssave_pretrainedpatch now normalizes a list-style declaration to the equivalent dict for the duration of the save. - Fix unified HF export of multimodal models whose vision tower carries its own
PrefixChangeconversion (LlavaForConditionalGenerationandGemma3ForConditionalGenerationontransformers>=5.12). The quant-aware reverse conversion ignored transformers'scope_prefix, so the vision tower's prefix rule was applied to every key in the state dict and vLLM rejected the checkpoint withValueError: There is no module or parameter named 'vision_model'. Reverse rename rules now carry their scope and are applied only to keys under it. - Fix QLoRA export in
examples/llm_qat/export.pyfailing withAssertionError: Model already has modelopt state!:enable_huggingface_checkpointingalready restores the quantized base model's state, so the export now restores only when the model is not already converted. Two further breakages on the same path are also fixed:_restore_qtensor_wrappersmatched no modules because PEFT re-parents the quantized linear as<name>.base_layer, andpostprocess_state_dictsilently dropped everybase_layer.*key missing from a hand-maintained rename map (losing the NVFP4weight_scale_2global scale and any linearbias) — the rename is now a generic.base_layer.strip. - Fix
--use_fsdp2PTQ (examples/hf_ptq) failing on models that hold a few parameters in a dtype other than the model's own, withAssertionError: FSDP expects uniform original parameter dtypeon the first calibration forward. Nemotron-3-Nano is one such model: its MoE router gates are declaredfloat32while the rest of the checkpoint is bfloat16, so each decoder layer's FSDP2 shard group mixed dtypes.fsdp2_wrapnow passes those off-dtype parameters tofully_shard(ignored_params=...), leaving them replicated in their original dtype instead of casting them, and warns with their names and their share of the model. - Fix
--use_fsdp2HF export making no progress for hours on large MoE checkpoints.create_fsdp_param_mappingresolved eachFSDPParam's module by scanning everymodel.named_parameters(), and export calls it once per quantized module, so the cost was quadratic in (parameters x modules): harmless for dense models, intractable for a MoE with many experts. Exporting Nemotron-3-Nano-30B-A3B (6,243 parameter tensors, 6,004 quantized modules) spent an estimated 1.9 hours there with every GPU idle. The parameter index is now built once per mapping instead of once perFSDPParam(1151 ms -> 5.1 ms per call), preserving the previous `named_parameters()``-order resolution for tied weights.