Skip to content
Merged
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
35 changes: 35 additions & 0 deletions tests/quantization/test_nvfp4_nf3_hybrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
import pytest
import torch

from vllm.config.quantization import resolve_quantization_config
from vllm.model_executor.layers.quantization import get_quantization_config
from vllm.model_executor.layers.quantization.nvfp4_nf3_hybrid import (
NvFp4Nf3HybridConfig,
_combined_tier_local_descriptors,
_read_hybrid_keys,
_unpack_nf3_codes,
)
from vllm.model_executor.layers.quantization.utils.quant_utils import kMxfp8Dynamic


@pytest.mark.parametrize(
Expand Down Expand Up @@ -65,6 +68,21 @@ def test_config_rejects_missing_hybrid_bit_map():
)


def test_config_accepts_dense_mxfp8_online_overlay():
resolved = resolve_quantization_config(
"nvfp4_nf3_hybrid",
{
"linear": {"weight": "mxfp8"},
"ignore": ["re:.*kv_b_proj"],
},
)

assert resolved is not None
assert resolved.linear is not None
assert resolved.linear.weight == kMxfp8Dynamic
assert resolved.ignore == ["re:.*kv_b_proj"]


def test_unpack_nf3_codes():
expected = torch.tensor([[[0, 1, 2, 3, 4, 5, 6, 7]]], dtype=torch.int32)
word = sum(int(code) << (index * 3) for index, code in enumerate(expected[0, 0]))
Expand All @@ -74,3 +92,20 @@ def test_unpack_nf3_codes():
)

torch.testing.assert_close(_unpack_nf3_codes(packed, size_k=8), expected)


def test_grid188_tier_descriptors_encode_exact_partition():
remap = {
**{global_id: (0, global_id) for global_id in range(64)},
**{global_id: (1, global_id - 64) for global_id in range(64, 256)},
}

descriptors = _combined_tier_local_descriptors(remap)

assert descriptors[:64] == list(range(64))
assert descriptors[64:] == [0x100 | local_id for local_id in range(192)]


def test_grid188_tier_descriptors_reject_incomplete_partition():
with pytest.raises(ValueError, match="does not cover all 256"):
_combined_tier_local_descriptors({0: (0, 0)})
13 changes: 13 additions & 0 deletions tests/v1/attention/test_indexer_dcp_localize.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,19 @@ def test_get_dcp_local_seq_lens_preserves_mtp_bounds_shape():
torch.testing.assert_close(actual, expected)


def test_get_dcp_local_seq_lens_rank_does_not_allocate_cuda_scalar(monkeypatch):
seq_lens = torch.tensor([17, 33, 65], dtype=torch.int32)

def fail_tensor_allocation(*args, **kwargs):
raise AssertionError("rank localization must not allocate a scalar tensor")

monkeypatch.setattr(torch, "tensor", fail_tensor_allocation)

actual = get_dcp_local_seq_lens(seq_lens, dcp_size=4, dcp_rank=2)

assert actual.tolist() == [4, 8, 16]


def test_get_dcp_local_seq_lens_must_run_after_decode_expansion():
world = 2
rank = 1
Expand Down
9 changes: 8 additions & 1 deletion vllm/config/quantization.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,14 @@ def _coerce_spec(cls, v: Any, info: ValidationInfo) -> Any:
# which the checkpoint explicitly leaves unquantized (shared experts via
# `shared_experts`, other dense linears via `linear`).
_MODELOPT_ONLINE_OVERLAY_NAMES = frozenset(
{"modelopt", "modelopt_fp4", "modelopt_mxfp8", "modelopt_mixed", "mxfp4"}
{
"modelopt",
"modelopt_fp4",
"modelopt_mxfp8",
"modelopt_mixed",
"mxfp4",
"nvfp4_nf3_hybrid",
}
)


Expand Down
5 changes: 5 additions & 0 deletions vllm/envs.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
VLLM_USE_B12X_FP8_GEMM: bool = False
VLLM_USE_B12X_WO_PROJECTION: bool = False
VLLM_USE_B12X_MOE: bool = False
VLLM_NF3_GRID188_DECODE: bool = True
VLLM_USE_B12X_MINIMAX_M3_MSA: bool = False
VLLM_USE_B12X_DCP_A2A: bool = False
VLLM_DCP_PROJECT_BEFORE_MERGE: bool = False
Expand Down Expand Up @@ -1091,6 +1092,10 @@ def _resolve_rust_frontend_path() -> str | None:
# Use b12x for FP4 MoE experts.
# This is opt-in while the b12x subsystems are brought over one at a time.
"VLLM_USE_B12X_MOE": lambda: bool(int(os.getenv("VLLM_USE_B12X_MOE", "0"))),
# Exact TP4 GLM-5.2 E64-NVFP4/E192-NF3 one-grid decode specialization.
"VLLM_NF3_GRID188_DECODE": lambda: bool(
int(os.getenv("VLLM_NF3_GRID188_DECODE", "1"))
),
# Use b12x for MiniMax M3's block-sparse MSA attention.
# This is opt-in while page-128 MSA support is integrated.
"VLLM_USE_B12X_MINIMAX_M3_MSA": lambda: bool(
Expand Down
Loading
Loading