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
88 changes: 88 additions & 0 deletions tests/quantization/test_quark.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
from vllm.model_executor.layers.quantization.quark.quark_moe import ( # noqa: E501
QuarkW8A8Int8MoEMethod,
)
from vllm.model_executor.layers.quantization.utils.quant_utils import (
is_layer_skipped,
)
from vllm.platforms import current_platform

from .reference_mxfp4 import dq_mxfp4_torch, qdq_mxfp4_torch
Expand Down Expand Up @@ -437,3 +440,88 @@ def test_mxfp4_dequant_kernel_match_quark(
out_torch = dq_mxfp4_torch(w_mxfp4, scale, float_dtype)

assert torch.equal(out_hip, out_torch)


# Unit tests for ``is_layer_skipped`` fused-name handling.

FUSED_MAPPING = {
"qkv_proj": ["q_proj", "k_proj", "v_proj"],
"gate_up_proj": ["gate_proj", "up_proj"],
}


def test_fused_name_listed_directly_is_skipped():
# Regression for Step-3.5-Flash-FP8: the checkpoint lists the fused
# name (``qkv_proj``) directly in ``modules_to_not_convert``. When a
# ``packed_modules_mapping`` is registered on the model, the fused
# match must still win over per-shard expansion.
ignored = ["model.layers.0.self_attn.qkv_proj"]
assert is_layer_skipped(
prefix="model.layers.0.self_attn.qkv_proj",
ignored_layers=ignored,
fused_mapping=FUSED_MAPPING,
)
assert is_layer_skipped(
prefix="model.layers.0.mlp.gate_up_proj",
ignored_layers=["model.layers.0.mlp.gate_up_proj"],
fused_mapping=FUSED_MAPPING,
)


def test_unfused_shards_listed_is_skipped():
# Quark INT8 style: per-shard names listed; all shards present means
# the fused layer is skipped via expansion.
ignored = [
"model.layers.0.self_attn.q_proj",
"model.layers.0.self_attn.k_proj",
"model.layers.0.self_attn.v_proj",
]
assert is_layer_skipped(
prefix="model.layers.0.self_attn.qkv_proj",
ignored_layers=ignored,
fused_mapping=FUSED_MAPPING,
)


def test_partial_shards_raises():
# Only some shards listed -> ambiguous, must raise. Fused name is
# not in ignored_layers, so we fall through to per-shard expansion.
ignored = ["model.layers.0.self_attn.q_proj"]
with pytest.raises(ValueError):
is_layer_skipped(
prefix="model.layers.0.self_attn.qkv_proj",
ignored_layers=ignored,
fused_mapping=FUSED_MAPPING,
)


def test_not_skipped_when_nothing_listed():
assert not is_layer_skipped(
prefix="model.layers.0.self_attn.qkv_proj",
ignored_layers=["model.layers.0.mlp.gate_up_proj"],
fused_mapping=FUSED_MAPPING,
)


def test_non_fused_layer_unaffected():
assert is_layer_skipped(
prefix="model.layers.0.self_attn.o_proj",
ignored_layers=["model.layers.0.self_attn.o_proj"],
fused_mapping=FUSED_MAPPING,
)
assert not is_layer_skipped(
prefix="model.layers.0.self_attn.o_proj",
ignored_layers=["model.layers.1.self_attn.o_proj"],
fused_mapping=FUSED_MAPPING,
)


def test_substr_match_on_fused_name():
# skip_with_substr=True path: fused-name substring match should also
# short-circuit before shard expansion.
assert is_layer_skipped(
prefix="model.layers.0.self_attn.qkv_proj",
ignored_layers=["self_attn.qkv_proj"],
fused_mapping=FUSED_MAPPING,
skip_with_substr=True,
)
10 changes: 9 additions & 1 deletion vllm/model_executor/layers/quantization/utils/quant_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,15 @@ def substr_match(prefix: str, ignored_layers: list[str]) -> bool:
# in the safetensors checkpoint. So, we convert the name
# from the fused version to unfused + check to make sure that
# each shard of the fused layer has the same scheme.
if proj_name in fused_mapping:
#
# Some checkpoints (e.g. block-FP8 Step-3.5-Flash) already list the
# fused name (e.g. ``self_attn.qkv_proj``) directly in
# ``modules_to_not_convert``. Honor that fused-name match first so
# those layers are still correctly skipped even when a
# ``packed_modules_mapping`` is registered on the model.
if proj_name in fused_mapping and match_func(prefix, ignored_layers):
Comment thread
ZiguanWang marked this conversation as resolved.
is_skipped = True
elif proj_name in fused_mapping:
shard_prefixes = [
prefix.replace(proj_name, shard_proj_name)
for shard_proj_name in fused_mapping[proj_name]
Expand Down
Loading