Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Changelog
*Quantization*

- Add the ``nvfp4_act_headroom`` calibration algorithm for NVFP4 **activation** global scales. Instead of setting the global scale from the largest per-block amax seen during calibration (plain ``max``, which leaves no room above it so any larger activation saturates), it anchors the scale to a low percentile of the per-block amax distribution, leaving the rest of the FP8 block-scale range as headroom: ``amax = max(rho * anchor, upper)``, where ``anchor`` and ``upper`` are the per-block amaxes at ``anchor_percentile`` (default 1) and ``upper_percentile`` (default 99.99; set to 100 to never clip calibration data), and ``rho`` (default 16384) is the headroom factor. Applies only to NVFP4 dynamic-block input quantizers; ``SequentialQuantizer`` activation quantizers raise. Weight scales are an orthogonal axis selected by a nested ``weight_scale_algorithm`` (``max`` by default, or ``mse`` / ``local_hessian``), so one recipe can combine a weight calibration with this activation policy in a single pass. Ships ``modelopt_recipes/general/ptq/nvfp4_act_headroom-kv_fp8_cast.yaml``, which mirrors ``nvfp4_default-kv_fp8_cast`` with only the calibration algorithm swapped and exports a standard NVFP4 checkpoint.
- Add layer-wise KV-cache AutoQuantize through ``mtq.auto_quantize_kv_cache`` and ``constraints.kv_effective_bits``. It measures isolated full-vocabulary forward KL for caller-supplied K/V formats, solves a width-weighted additive storage-constrained recipe across eligible layers, preserves search-disabled layers in their existing format, exports the selected per-attention mapping in unified HF checkpoints, and writes a JSON sensitivity report alongside the checkpoint. A cast-mode FP8/NVFP4 recipe at 5.4 bits/scalar is included.

*Megatron Framework (M-LM / M-Bridge)*

Expand Down
53 changes: 49 additions & 4 deletions examples/hf_ptq/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -422,11 +422,54 @@ leaving the original recipe unchanged.
For models without backprop support (e.g. Llama-4), use the `kl_div` scoring method — see the shipped
`general/auto_quantize/nvfp4_fp8_kl_div_at_5p4bits` recipe.

KV cache is applied as a uniform post-step, not part of the per-layer search. An AutoQuantize recipe
falls back to `--kv_cache_qformat` (default `fp8_cast`) unless it sets an explicit `kv_cache` field.
Weight AutoQuantize recipes still apply KV cache as a uniform post-step and fall back to
`--kv_cache_qformat` (default `fp8_cast`) unless they set an explicit `kv_cache` field.

To optimize GEMM and KV cache in one invocation, compose ordered stages in the same recipe. A fixed
`quantize` block followed by a KV-domain `auto_quantize` first calibrates the GEMM weight/activation
configuration, then searches K/V while the existing GEMM QDQ remains enabled with calibration
frozen. See `general/auto_quantize/fp8_ptq_then_kv_fp8_nvfp4_cast_kl_div_at_5p4bits`.

A weight-domain `auto_quantize` can instead add a `kv_auto_quantize` follow-up with its own method,
constraints, candidates, score size, and disabled layers. This supports, for example, a
gradient-based GEMM search followed by a KL-divergence KV search; see
`general/auto_quantize/nvfp4_fp8_gradient_then_kv_fp8_nvfp4_cast_kl_div_at_5p4bits`. When the
follow-up is present, the recipe owns KV configuration and suppresses the CLI's uniform
`--kv_cache_qformat` fallback. Use `--auto_quantize_checkpoint` for the weight search and
`--kv_auto_quantize_checkpoint` for the KV search.

KV-cache AutoQuantize recipes instead set `constraints.kv_effective_bits`. Their
`candidate_formats` are complete K/V cache configs whose config-level `effective_bits` includes
packed scale overhead. The width-weighted budget covers eligible layers; `disabled_layers` are
preserved and excluded. BF16 is used only as the isolated-KL reference, not as a solver choice.
The shipped canary recipe searches calibrated FP8 K/V (8.0 bits/scalar) and packed NVFP4 K/V
(4.5 bits/scalar) at 5.4 bits/scalar. It intentionally excludes FP8-K/NVFP4-V because the
companion vLLM implementation does not support that asymmetric per-layer format:

The one runtime flag is `--auto_quantize_checkpoint` — save/restore the search state to resume an
interrupted search (skips re-scoring):
```bash
python hf_ptq.py \
--pyt_ckpt_path Qwen/Qwen3-1.7B \
--recipe general/auto_quantize/kv_fp8_nvfp4_cast_kl_div_at_5p4bits \
--auto_quantize_checkpoint /path/to/kv_autoquant.pth \
--export_path /path/to/qwen3-1.7b-mixed-kv
```

Each candidate uses max calibration so its persistent K/V scales are present in the unified HF
checkpoint. Unified export records the selected formats in `kv_cache_quantized_layers` and writes
the JSON-safe sensitivity report to `kv_cache_auto_quantize_report.json`;
`--auto_quantize_checkpoint` stores the resumable raw search state.

> [!NOTE]
> Layer-wise KV checkpoints require the companion
> [vLLM mixed-KV metadata consumer](https://github.com/vllm-project/vllm/pull/52813) or a later
> vLLM release containing it. The repository's currently pinned vLLM 0.26.0 does not consume
> `kv_cache_quantized_layers`, so these checkpoints are export-only in that stock environment.
> Do not deploy them with the pinned runtime. Full FP8 K/V and full NVFP4 K/V use existing vLLM
> kernels once the layer-wise metadata consumer is available.

For a single-stage search, `--auto_quantize_checkpoint` saves/restores the search state to resume an
interrupted search (skips re-scoring). Composed weight-plus-KV recipes additionally use
`--kv_auto_quantize_checkpoint` for the independent KV search state:

```bash
scripts/huggingface_example.sh --model $HF_PATH --recipe general/auto_quantize/nvfp4_fp8_at_5p4bits \
Expand Down Expand Up @@ -460,6 +503,8 @@ mtq.calibrate(model, algorithm="max", forward_loop=calibrate_loop)

ModelOpt enables quantization of LLMs across multiple GPU nodes using FSDP2 for distributed model sharding and calibration, exposed via the `--use_fsdp2` flag on the standard `hf_ptq.py` entry point.

> *AutoQuantize recipes are not supported with `--use_fsdp2` and are rejected before model loading. Distributed sensitivity scoring, selection, and checkpoint writes must be synchronized before this combination can be enabled safely. Use a PTQ recipe with FSDP2.*

### Usage

#### Slurm (recommended)
Expand Down
Loading
Loading