From 92ccd2c30679d53418399be71f8ff7c0afef9790 Mon Sep 17 00:00:00 2001 From: Liang Lv Date: Tue, 1 Sep 2026 18:40:47 +0800 Subject: [PATCH] [Bugifx][INC] Fix INC quantization method selection for non-quantized layers (#47237) Signed-off-by: lvliang-intel Co-authored-by: Kunshang Ji Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- tests/quantization/test_auto_round.py | 89 ++++++++++++++++++- .../layers/quantization/inc/inc.py | 4 +- 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/tests/quantization/test_auto_round.py b/tests/quantization/test_auto_round.py index df409740fc..906f213160 100644 --- a/tests/quantization/test_auto_round.py +++ b/tests/quantization/test_auto_round.py @@ -333,12 +333,99 @@ def test_inc_model_prefix_early_exit() -> None: }, } ) + layer = object.__new__(LinearBase) # get_quant_method checks model. prefix for unquantized early-exit - result = config.get_quant_method(DummyLayer(), "layers.1.mlp.gate_proj") + result = config.get_quant_method(layer, "layers.1.mlp.gate_proj") assert isinstance(result, UnquantizedLinearMethod) +def test_inc_get_quant_method_unquantized_parallel_lm_head_returns_unquantized() -> ( + None +): + """ParallelLMHead with bits >= 16 returns UnquantizedLinearMethod via the + early-exit path (parallel_lm_head is explicitly handled alongside LinearBase). + """ + config = make_config(extra_config={"lm_head": {"bits": 16}}) + layer = object.__new__(ParallelLMHead) + + method = config.get_quant_method(layer, "lm_head") + + assert isinstance(method, UnquantizedLinearMethod) + + +def test_inc_get_quant_method_unquantized_unknown_layer_returns_none() -> None: + """Regression test: non-Linear/non-MoE layers with bits >= 16 must return + None from the early-exit path instead of being misclassified as linear. + """ + config = make_config(extra_config={"layer": {"bits": 16}}) + + method = config.get_quant_method(DummyLayer(), "layer") + + assert method is None + + +@pytest.mark.parametrize( + "layer_factory", + [ + pytest.param( + lambda: object.__new__(LinearBase), + id="LinearBase", + ), + pytest.param( + lambda: object.__new__(ParallelLMHead), + id="ParallelLMHead", + ), + ], +) +def test_inc_get_quant_method_unquantized_layer_with_model_prefix( + layer_factory, +) -> None: + """``model.``-prefixed extra_config entries trigger early exit for both + LinearBase and ParallelLMHead layers.""" + config = make_config(extra_config={"model.layer": {"bits": 16}}) + layer = layer_factory() + + method = config.get_quant_method(layer, "layer") + + assert isinstance(method, UnquantizedLinearMethod) + + +def test_inc_get_quant_method_unquantized_routed_experts_with_model_prefix( + monkeypatch, +) -> None: + """``model.``-prefixed extra_config entries trigger early exit for + RoutedExperts layers, returning UnquantizedFusedMoEMethod.""" + + class DummyUnquantizedFusedMoEMethod: + def __init__(self, moe_config) -> None: + self.moe_config = moe_config + + monkeypatch.setattr( + "vllm.model_executor.layers.quantization.inc.inc.UnquantizedFusedMoEMethod", + DummyUnquantizedFusedMoEMethod, + ) + + config = make_config(extra_config={"model.moe_layer": {"bits": 16}}) + layer = object.__new__(RoutedExperts) + layer.moe_config = None + + method = config.get_quant_method(layer, "moe_layer") + + assert isinstance(method, DummyUnquantizedFusedMoEMethod) + assert method.moe_config is None + + +def test_inc_get_quant_method_unknown_layer_with_model_prefix_returns_none() -> None: + """``model.``-prefixed extra_config entries return None for unhandled + layer types (non-Linear, non-MoE).""" + config = make_config(extra_config={"model.unknown": {"bits": 16}}) + + method = config.get_quant_method(DummyLayer(), "unknown") + + assert method is None + + def test_inc_config_parser_regex_match() -> None: config = make_config( extra_config={ diff --git a/vllm/model_executor/layers/quantization/inc/inc.py b/vllm/model_executor/layers/quantization/inc/inc.py index 8e5fd49c57..2ffc2add25 100644 --- a/vllm/model_executor/layers/quantization/inc/inc.py +++ b/vllm/model_executor/layers/quantization/inc/inc.py @@ -328,9 +328,11 @@ class INCConfig(QuantizationConfig): if ( layer_name == prefix or layer_name == f"model.{prefix}" ) and self.extra_config[layer_name].get("bits", 16) >= 16: + if isinstance(layer, (LinearBase, ParallelLMHead)): + return UnquantizedLinearMethod() if isinstance(layer, RoutedExperts): return UnquantizedFusedMoEMethod(layer.moe_config) - return UnquantizedLinearMethod() + return None layer_config = self.config_parser.resolve(layer, prefix) if not layer_config.quantized: