[Bugifx][INC] Fix INC quantization method selection for non-quantized layers (#47237)
Signed-off-by: lvliang-intel <liang1.lv@intel.com> Co-authored-by: Kunshang Ji <kunshang.ji@intel.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Liang Lv committed
Sep 1, 2026 at 18:40 UTC
92ccd2c30679d53418399be71f8ff7c0afef9790
2 files changed
+91
-2
tests/quantization/test_auto_round.py
+88
-1
@@ -333,12 +333,99 @@ def test_inc_model_prefix_early_exit() -> None:
333
},
334
}
335
)
336
+ layer = object.__new__(LinearBase)
337
338
# get_quant_method checks model. prefix for unquantized early-exit
338
- result = config.get_quant_method(DummyLayer(), "layers.1.mlp.gate_proj")
339
+ result = config.get_quant_method(layer, "layers.1.mlp.gate_proj")
340
assert isinstance(result, UnquantizedLinearMethod)
341
342
343
+def test_inc_get_quant_method_unquantized_parallel_lm_head_returns_unquantized() -> (
344
+ None
345
+):
346
+ """ParallelLMHead with bits >= 16 returns UnquantizedLinearMethod via the
347
+ early-exit path (parallel_lm_head is explicitly handled alongside LinearBase).
348
+ """
349
+ config = make_config(extra_config={"lm_head": {"bits": 16}})
350
+ layer = object.__new__(ParallelLMHead)
351
+
352
+ method = config.get_quant_method(layer, "lm_head")
353
+
354
+ assert isinstance(method, UnquantizedLinearMethod)
355
+
356
+
357
+def test_inc_get_quant_method_unquantized_unknown_layer_returns_none() -> None:
358
+ """Regression test: non-Linear/non-MoE layers with bits >= 16 must return
359
+ None from the early-exit path instead of being misclassified as linear.
360
+ """
361
+ config = make_config(extra_config={"layer": {"bits": 16}})
362
+
363
+ method = config.get_quant_method(DummyLayer(), "layer")
364
+
365
+ assert method is None
366
+
367
+
368
+@pytest.mark.parametrize(
369
+ "layer_factory",
370
+ [
371
+ pytest.param(
372
+ lambda: object.__new__(LinearBase),
373
+ id="LinearBase",
374
+ ),
375
+ pytest.param(
376
+ lambda: object.__new__(ParallelLMHead),
377
+ id="ParallelLMHead",
378
+ ),
379
+ ],
380
+)
381
+def test_inc_get_quant_method_unquantized_layer_with_model_prefix(
382
+ layer_factory,
383
+) -> None:
384
+ """``model.``-prefixed extra_config entries trigger early exit for both
385
+ LinearBase and ParallelLMHead layers."""
386
+ config = make_config(extra_config={"model.layer": {"bits": 16}})
387
+ layer = layer_factory()
388
+
389
+ method = config.get_quant_method(layer, "layer")
390
+
391
+ assert isinstance(method, UnquantizedLinearMethod)
392
+
393
+
394
+def test_inc_get_quant_method_unquantized_routed_experts_with_model_prefix(
395
+ monkeypatch,
396
+) -> None:
397
+ """``model.``-prefixed extra_config entries trigger early exit for
398
+ RoutedExperts layers, returning UnquantizedFusedMoEMethod."""
399
+
400
+ class DummyUnquantizedFusedMoEMethod:
401
+ def __init__(self, moe_config) -> None:
402
+ self.moe_config = moe_config
403
+
404
+ monkeypatch.setattr(
405
+ "vllm.model_executor.layers.quantization.inc.inc.UnquantizedFusedMoEMethod",
406
+ DummyUnquantizedFusedMoEMethod,
407
+ )
408
+
409
+ config = make_config(extra_config={"model.moe_layer": {"bits": 16}})
410
+ layer = object.__new__(RoutedExperts)
411
+ layer.moe_config = None
412
+
413
+ method = config.get_quant_method(layer, "moe_layer")
414
+
415
+ assert isinstance(method, DummyUnquantizedFusedMoEMethod)
416
+ assert method.moe_config is None
417
+
418
+
419
+def test_inc_get_quant_method_unknown_layer_with_model_prefix_returns_none() -> None:
420
+ """``model.``-prefixed extra_config entries return None for unhandled
421
+ layer types (non-Linear, non-MoE)."""
422
+ config = make_config(extra_config={"model.unknown": {"bits": 16}})
423
+
424
+ method = config.get_quant_method(DummyLayer(), "unknown")
425
+
426
+ assert method is None
427
+
428
+
429
def test_inc_config_parser_regex_match() -> None:
430
config = make_config(
431
extra_config={
vllm/model_executor/layers/quantization/inc/inc.py
+3
-1
@@ -328,9 +328,11 @@ class INCConfig(QuantizationConfig):
328
if (
329
layer_name == prefix or layer_name == f"model.{prefix}"
330
) and self.extra_config[layer_name].get("bits", 16) >= 16:
331
+ if isinstance(layer, (LinearBase, ParallelLMHead)):
332
+ return UnquantizedLinearMethod()
333
if isinstance(layer, RoutedExperts):
334
return UnquantizedFusedMoEMethod(layer.moe_config)
333
- return UnquantizedLinearMethod()
335
+ return None
336
337
layer_config = self.config_parser.resolve(layer, prefix)
338
if not layer_config.quantized: