[Bug][Quantization] Fix humming is_layer_skipped for compressed-tensors "re:" ignore entries (#48507)
Signed-off-by: Zhongdongming Dai <zhongdongmin@nvidia.com>
Zhongdongming Dai committed
Jul 16, 2026 at 07:47 UTC
75bdad40b5e96517c7f7645ce3199a8557817e17
2 files changed
+67
-2
tests/quantization/test_humming_ignore.py
new
+56
@@ -0,0 +1,56 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+"""Tests for humming's is_layer_skipped handling of compressed-tensors
4
+regex ("re:") ignore entries.
5
+
6
+Regression test: compressed-tensors checkpoints (e.g. Kimi-K2.6) list ignored
7
+layers as regex patterns prefixed with "re:" (e.g. "re:vision_tower.*").
8
+humming previously substring-matched these literals, so ignored layers were
9
+never skipped and got (incorrectly) quantized -- which then diverged between
10
+the real weight-load path (falls back to unquantized) and the dummy-load path
11
+(stays quantized), breaking any consumer that byte-compares the two.
12
+"""
13
+
14
+import pytest
15
+
16
+from vllm.model_executor.layers.quantization.humming import HummingConfig
17
+
18
+# The real ignore list from Kimi-K2.6's compressed-tensors quantization_config.
19
+K26_IGNORE = [
20
+ "re:.*self_attn.*",
21
+ "re:.*shared_experts.*",
22
+ r"re:.*mlp\.(gate|up|gate_up|down)_proj.*",
23
+ "re:.*lm_head.*",
24
+ "re:vision_tower.*",
25
+ "re:mm_projector.*",
26
+]
27
+
28
+
29
+@pytest.mark.parametrize(
30
+ "prefix,expected",
31
+ [
32
+ # ignored layers (must be skipped -> stay unquantized)
33
+ ("vision_tower.encoder.blocks.0.mlp.fc0", True),
34
+ ("vision_tower.encoder.blocks.16.wo", True),
35
+ ("mm_projector.linear_1", True),
36
+ ("language_model.model.layers.0.self_attn.o_proj", True),
37
+ ("language_model.model.layers.0.mlp.gate_up_proj", True),
38
+ ("language_model.model.layers.0.mlp.down_proj", True),
39
+ ("language_model.model.layers.3.mlp.shared_experts.gate_proj", True),
40
+ ("model.lm_head", True),
41
+ # routed experts are NOT ignored -> must be quantized
42
+ ("language_model.model.layers.3.mlp.experts.383.up_proj", False),
43
+ ("language_model.model.layers.3.mlp.experts.0.down_proj", False),
44
+ ],
45
+)
46
+def test_is_layer_skipped_regex_ignore(prefix, expected):
47
+ cfg = HummingConfig(full_config={"ignore": K26_IGNORE})
48
+ assert cfg.is_layer_skipped({"ignore": K26_IGNORE}, prefix) is expected
49
+
50
+
51
+def test_plain_substring_entries_still_work():
52
+ # bitsandbytes-style modules_to_not_convert use plain substrings.
53
+ cfg = HummingConfig()
54
+ cfg_dict = {"modules_to_not_convert": ["lm_head", "vision"]}
55
+ assert cfg.is_layer_skipped(cfg_dict, "model.vision.encoder.fc") is True
56
+ assert cfg.is_layer_skipped(cfg_dict, "model.layers.0.mlp.up_proj") is False
vllm/model_executor/layers/quantization/humming.py
+11
-2
@@ -217,8 +217,17 @@ class HummingConfig(QuantizationConfig):
217
if hasattr(self, "hf_to_vllm_mapper"):
218
ignored_layers = self.hf_to_vllm_mapper.apply_list(ignored_layers)
219
220
- if any(module_name in prefix for module_name in ignored_layers):
221
- return True
220
+ for module_name in ignored_layers:
221
+ # compressed-tensors style entries may be regex patterns prefixed
222
+ # with "re:" (e.g. "re:vision_tower.*"). These must be regex-matched;
223
+ # plain substring matching never matches the literal "re:..." string,
224
+ # so ignored layers get silently quantized. Non-"re:" entries keep the
225
+ # existing substring behavior (e.g. bitsandbytes modules_to_not_convert).
226
+ if module_name.startswith("re:"):
227
+ if re.match(module_name[3:], prefix):
228
+ return True
229
+ elif module_name in prefix:
230
+ return True
231
if "lm_head" in prefix:
232
return True
233