Skip to content
Open
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 @@ -36,6 +36,7 @@ Changelog
- Add a reusable local-Hessian NVFP4 PTQ recipe and the quantization recipe used for ``nvidia/Qwen3.8-27B-NVFP4``.
- Add experimental dynamic FP8 fake quantization of GatedDeltaNet chunk-boundary states and WY activations for training through the standard ``quant_cfg`` interface. The fused GDN path requires ``fla-core==0.5.1`` and chunk size 64; state emulation requires SM89 or newer.
- Add fake quantization of the sparse-attention indexer key cache and query for DeepSeek-V4 (vLLM and Megatron-Core) and GLM-5.3-Flash (vLLM) through the new ``indexer_k_quantizer`` and ``indexer_q_quantizer``. Enable them by importing the ``configs/ptq/units/indexer_k_nvfp4`` and ``configs/ptq/units/indexer_q_nvfp4`` units (NVFP4 with the global scale fixed to 1) into a recipe.
- Add ``indexer_scorer_kwargs_quantizer`` to pass keyword arguments, such as the numerics options of a DeepGEMM build, to the DeepGEMM indexer scorer kernel of GLM-5.3-Flash per layer in vLLM fake-quant serving; see `examples/vllm_serve/README.md <https://github.com/NVIDIA/Model-Optimizer/tree/main/examples/vllm_serve>`_.
- Add the ``configs/ptq/units/kv_nvfp4_mla`` recipe unit for fake quantization of the MLA KV cache (DeepSeek-V3, GLM-5.3-Flash, ...) in vLLM fake-quant serving: NVFP4 for the latent and FP8 for the RoPE key. See `examples/vllm_serve/README.md <https://github.com/NVIDIA/Model-Optimizer/tree/main/examples/vllm_serve>`_ for an example recipe.
- Add fake quantization of MoE expert-parallel communication to vLLM fake-quant serving through the new ``dispatch_quantizer`` and ``combine_quantizer`` on vLLM's routed experts, for MoE layers built on vLLM's fused-MoE layer and any all-to-all backend, and for the DeepGEMM Mega-MoE kernel of DeepSeek-V4 and Kimi-K3 (``--moe-backend deep_gemm_mega_moe``). Enable them by importing the ``configs/ptq/units/moe_dispatch_nvfp4`` and ``configs/ptq/units/moe_combine_nvfp4`` units into a recipe; see ``examples/vllm_serve/README.md``.
- vLLM fake-quant serving now runs on pre-quantized checkpoints such as FP8 when the recipe leaves those layers unquantized (for example a KV-cache-only recipe), and on MLA models with an FP8 KV cache; both previously failed during quantization.
Expand Down
45 changes: 45 additions & 0 deletions examples/vllm_serve/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,51 @@ Notes:
- vLLM quantizes the DeepSeek-V4 indexer key and query without a Hadamard rotation and the
GLM-5.3-Flash ones after one, so the fake quantization applies in that basis.

### Indexer scorer kernel arguments

GLM-5.3-Flash's indexer scores each key as `k_scale * sum_h W[h] * ReLU(q_h . k)` in DeepGEMM, from
the FP8 query and key and the effective head weights `W` (with the query scale folded in).
`indexer_scorer_kwargs_quantizer` passes keyword arguments to that scorer kernel, per layer, e.g. the
numerics options of a DeepGEMM build. It stays disabled unless a recipe enables it with
`backend: scorer_kwargs`; its `backend_extra_args` are the arguments. For example, this recipe sums
the heads in BF16:

```yaml
# modelopt-schema: modelopt.recipe.config.ModelOptPTQRecipe
imports:
base_disable_all: configs/ptq/units/base_disable_all

metadata:
description: BF16 head sum in the indexer scorer.
quantize:
algorithm: max
quant_cfg:
- $import: base_disable_all
- quantizer_name: '*indexer_scorer_kwargs_quantizer'
cfg:
backend: scorer_kwargs
backend_extra_args: {logits_dtype: bfloat16}
```

Plugins can add quantizers that turn their own configs into such arguments with
`register_indexer_scorer_kwargs_quantizer` of `modelopt.torch.quantization.plugins.vllm_indexer`.
Stock DeepGEMM takes `logits_dtype` (on SM100 GPUs); other arguments need a DeepGEMM build that takes
them and declares them, with their values, in `deep_gemm.MQA_LOGITS_NUMERICS`, such as a DeepGEMM
fork. ModelOpt ships none. vLLM imports an installed `deep_gemm` before its own copy, so install
such a build into the serving environment and serve:

```bash
pip install --no-deps --no-build-isolation <DeepGEMM source directory or git URL>
RECIPE_PATH=<recipe>.yaml \
python3 examples/vllm_serve/vllm_serve_fakequant.py <model_path> -tp 8 --host 0.0.0.0 --port 8000
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Notes:

- Scores that come out NaN, e.g. from overflowing reduced-precision arithmetic in the scorer, are set
to `-inf` before top-k, as vLLM's prefill top-k mishandles NaN.
- DeepSeek-V4 rejects the scorer quantizers.

## Fake-quantize MoE expert-parallel communication

To study compressed expert-parallel (EP) communication, fake-quantize what the MoE layers send
Expand Down
21 changes: 14 additions & 7 deletions modelopt/torch/quantization/model_quant.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,20 @@ def _check_weight_quantization_took_effect(model: nn.Module, config: QuantizeCon
)


_INDEXER_UNITS = "the configs/ptq/units/indexer_*_nvfp4 recipe units"
_MOE_COMM_UNITS = "the configs/ptq/units/moe_*_nvfp4 recipe units"
# Quantizers that only framework plugins add: (class-name patterns of the modules they belong on,
# what those modules are, recipe units listing the supported models).
# what those modules are, where the supported models are listed).
_PLUGIN_QUANTIZERS = {
"indexer_q_quantizer": (("*Indexer",), "sparse-attention indexer", "indexer_*_nvfp4"),
"indexer_k_quantizer": (("*Indexer",), "sparse-attention indexer", "indexer_*_nvfp4"),
"dispatch_quantizer": (("*Experts*", "*FusedMoE"), "MoE experts module", "moe_*_nvfp4"),
"combine_quantizer": (("*Experts*", "*FusedMoE"), "MoE experts module", "moe_*_nvfp4"),
"indexer_q_quantizer": (("*Indexer",), "sparse-attention indexer", _INDEXER_UNITS),
"indexer_k_quantizer": (("*Indexer",), "sparse-attention indexer", _INDEXER_UNITS),
"indexer_scorer_kwargs_quantizer": (
("*Indexer",),
"sparse-attention indexer",
'the "Indexer scorer kernel arguments" section of examples/vllm_serve/README.md',
),
"dispatch_quantizer": (("*Experts*", "*FusedMoE"), "MoE experts module", _MOE_COMM_UNITS),
"combine_quantizer": (("*Experts*", "*FusedMoE"), "MoE experts module", _MOE_COMM_UNITS),
}


Expand All @@ -256,7 +263,7 @@ def _check_plugin_quantization_took_effect(model: nn.Module, config: QuantizeCon
some waiting in calibration for the others.
"""
last_entry_per_pattern = {entry.quantizer_name: entry for entry in config.quant_cfg}
for quantizer_name, (owner_patterns, owner_kind, units) in _PLUGIN_QUANTIZERS.items():
for quantizer_name, (owner_patterns, owner_kind, supported) in _PLUGIN_QUANTIZERS.items():
if not any(
entry.enable and quantizer_name in pattern
for pattern, entry in last_entry_per_pattern.items()
Expand Down Expand Up @@ -290,7 +297,7 @@ def _check_plugin_quantization_took_effect(model: nn.Module, config: QuantizeCon
f"The quantization config enables {quantizer_name}, but no {owner_kind} of this "
f"model ({', '.join(unsupported)}) has one: the ModelOpt plugins do not support "
"this model, its runtime backend or the installed vLLM / Megatron-Core version "
f"(supported models: see the configs/ptq/units/{units} recipe units)."
f"(supported models: see {supported})."
)
if any(has for _, has, _ in per_rank) and not any(on for _, _, on in per_rank):
raise RuntimeError(
Expand Down
1 change: 1 addition & 0 deletions modelopt/torch/quantization/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
with import_plugin("vllm"):
from .vllm import *
from .vllm_indexer import *
from .vllm_layer_scope import *
from .vllm_mega_moe import *

with import_plugin("trl"):
Expand Down
Loading
Loading