@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 352c0c8a28
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 14, 05:30 UTC

[Quantization] Automatically infer AWQ `modules_to_not_convert` field (#26909)

Signed-off-by: Isotr0py <mozf@mail2.sysu.edu.cn>

Isotr0py committed Oct 21, 2025 at 09:49 UTC 352c0c8a285414b11373e65fef095af7b07b94d8
6 files changed +96 -45
vllm/model_executor/layers/quantization/awq.py
+34 -6
@@ -1,9 +1,10 @@
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 -from typing import Any, Union
4 +from typing import TYPE_CHECKING, Any, Union
5
6 import torch
7 +from safetensors.torch import _TYPES as _SAFETENSORS_TO_TORCH_DTYPE
8
9 from vllm import _custom_ops as ops
10 from vllm.logger import init_logger
@@ -13,12 +14,17 @@ from vllm.model_executor.layers.linear import (
14 LinearMethodBase,
15 UnquantizedLinearMethod,
16 )
16 -from vllm.model_executor.layers.quantization import QuantizationMethods
17 from vllm.model_executor.layers.quantization.base_config import (
18 QuantizationConfig,
19 QuantizeMethodBase,
20 )
21 +from vllm.model_executor.layers.quantization.utils.quant_utils import is_layer_skipped
22 from vllm.model_executor.parameter import GroupQuantScaleParameter, PackedvLLMParameter
23 +from vllm.transformers_utils.config import get_safetensors_params_metadata
24 +
25 +if TYPE_CHECKING:
26 + from vllm.model_executor.layers.quantization import QuantizationMethods
27 + from vllm.model_executor.models.utils import WeightsMapper
28
29 logger = init_logger(__name__)
30
@@ -57,7 +63,7 @@ class AWQConfig(QuantizationConfig):
63 f"modules_to_not_convert={self.modules_to_not_convert})"
64 )
65
60 - def get_name(self) -> QuantizationMethods:
66 + def get_name(self) -> "QuantizationMethods":
67 return "awq"
68
69 def get_supported_act_dtypes(self) -> list[torch.dtype]:
@@ -90,7 +96,12 @@ class AWQConfig(QuantizationConfig):
96 self, layer: torch.nn.Module, prefix: str
97 ) -> Union["LinearMethodBase", "QuantizeMethodBase"] | None:
98 if isinstance(layer, LinearBase):
93 - if is_layer_skipped_awq(prefix, self.modules_to_not_convert):
99 + if is_layer_skipped(
100 + prefix,
101 + self.modules_to_not_convert,
102 + self.packed_modules_mapping,
103 + skip_with_substr=True,
104 + ):
105 return UnquantizedLinearMethod()
106 return AWQLinearMethod(self)
107 elif isinstance(layer, FusedMoE):
@@ -128,9 +139,26 @@ class AWQConfig(QuantizationConfig):
139 return AWQMoEMethod(awq_marlin_config, layer.moe_config)
140 return None
141
142 + def apply_vllm_mapper(self, hf_to_vllm_mapper: "WeightsMapper"):
143 + if self.modules_to_not_convert:
144 + self.modules_to_not_convert = hf_to_vllm_mapper.apply_list(
145 + self.modules_to_not_convert
146 + )
147
132 -def is_layer_skipped_awq(prefix: str, modules_to_not_convert: list[str]):
133 - return any(module_name in prefix for module_name in modules_to_not_convert)
148 + def maybe_update_config(self, model_name: str, revision: str | None = None):
149 + if self.modules_to_not_convert:
150 + return
151 +
152 + unquant_dtypes = [torch.float16, torch.bfloat16, torch.float32]
153 + metadata = get_safetensors_params_metadata(model_name, revision=revision)
154 + layers = {param_name.rsplit(".", 1)[0] for param_name in metadata}
155 + quant_layers: set[str] = {
156 + param_name.rsplit(".", 1)[0]
157 + for param_name, info in metadata.items()
158 + if (dtype := info.get("dtype", None))
159 + and _SAFETENSORS_TO_TORCH_DTYPE[dtype] not in unquant_dtypes
160 + }
161 + self.modules_to_not_convert = list(layers - quant_layers)
162
163
164 class AWQLinearMethod(LinearMethodBase):
vllm/model_executor/layers/quantization/awq_marlin.py
+36 -9
@@ -2,9 +2,10 @@
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 from collections.abc import Callable
5 -from typing import Any, Optional
5 +from typing import TYPE_CHECKING, Any, Optional
6
7 import torch
8 +from safetensors.torch import _TYPES as _SAFETENSORS_TO_TORCH_DTYPE
9 from torch.nn import Parameter
10
11 import vllm.model_executor.layers.fused_moe # noqa
@@ -27,8 +28,7 @@ from vllm.model_executor.layers.linear import (
28 UnquantizedLinearMethod,
29 set_weight_attrs,
30 )
30 -from vllm.model_executor.layers.quantization import QuantizationMethods
31 -from vllm.model_executor.layers.quantization.awq import AWQConfig, is_layer_skipped_awq
31 +from vllm.model_executor.layers.quantization.awq import AWQConfig
32 from vllm.model_executor.layers.quantization.base_config import (
33 QuantizationConfig,
34 QuantizeMethodBase,
@@ -49,10 +49,16 @@ from vllm.model_executor.layers.quantization.utils.marlin_utils import (
49 verify_marlin_supported,
50 verify_marlin_supports_shape,
51 )
52 +from vllm.model_executor.layers.quantization.utils.quant_utils import is_layer_skipped
53 from vllm.model_executor.layers.vocab_parallel_embedding import ParallelLMHead
54 from vllm.model_executor.parameter import GroupQuantScaleParameter, PackedvLLMParameter
55 from vllm.platforms import current_platform
56 from vllm.scalar_type import scalar_types
57 +from vllm.transformers_utils.config import get_safetensors_params_metadata
58 +
59 +if TYPE_CHECKING:
60 + from vllm.model_executor.layers.quantization import QuantizationMethods
61 + from vllm.model_executor.models.utils import WeightsMapper
62
63 logger = init_logger(__name__)
64
@@ -106,7 +112,7 @@ class AWQMarlinConfig(QuantizationConfig):
112 )
113
114 @classmethod
109 - def get_name(cls) -> QuantizationMethods:
115 + def get_name(cls) -> "QuantizationMethods":
116 return "awq_marlin"
117
118 @classmethod
@@ -142,7 +148,7 @@ class AWQMarlinConfig(QuantizationConfig):
148 @classmethod
149 def override_quantization_method(
150 cls, hf_quant_cfg, user_quant
145 - ) -> QuantizationMethods | None:
151 + ) -> Optional["QuantizationMethods"]:
152 can_convert = cls.is_awq_marlin_compatible(hf_quant_cfg)
153 is_valid_user_quant = (
154 user_quant is None or user_quant == "marlin" or user_quant == "awq_marlin"
@@ -171,7 +177,9 @@ class AWQMarlinConfig(QuantizationConfig):
177 if isinstance(layer, LinearBase) or (
178 isinstance(layer, ParallelLMHead) and self.lm_head_quantized
179 ):
174 - if is_layer_skipped_awq(prefix, self.modules_to_not_convert):
180 + if is_layer_skipped(
181 + prefix, self.modules_to_not_convert, self.packed_modules_mapping
182 + ):
183 return UnquantizedLinearMethod()
184 # Check if the layer is supported by AWQMarlin.
185 if not check_marlin_supports_layer(layer, self.group_size):
@@ -186,9 +194,7 @@ class AWQMarlinConfig(QuantizationConfig):
194 elif isinstance(layer, FusedMoE):
195 from vllm.model_executor.layers.quantization.moe_wna16 import MoeWNA16Config
196
189 - if is_layer_skipped_awq(
190 - prefix, getattr(self, "modules_to_not_convert", [])
191 - ):
197 + if is_layer_skipped(prefix, getattr(self, "modules_to_not_convert", [])):
198 return UnquantizedFusedMoEMethod(layer.moe_config)
199 if not check_moe_marlin_supports_layer(layer, self.group_size):
200 logger.warning_once(
@@ -226,6 +232,27 @@ class AWQMarlinConfig(QuantizationConfig):
232 quant_type=cls.TYPE_MAP[num_bits], group_size=group_size, has_zp=zero_point
233 )
234
235 + def apply_vllm_mapper(self, hf_to_vllm_mapper: "WeightsMapper"):
236 + if self.modules_to_not_convert:
237 + self.modules_to_not_convert = hf_to_vllm_mapper.apply_list(
238 + self.modules_to_not_convert
239 + )
240 +
241 + def maybe_update_config(self, model_name: str, revision: str | None = None):
242 + if self.modules_to_not_convert:
243 + return
244 +
245 + unquant_dtypes = [torch.float16, torch.bfloat16, torch.float32]
246 + metadata = get_safetensors_params_metadata(model_name, revision=revision)
247 + layers = {param_name.rsplit(".", 1)[0] for param_name in metadata}
248 + quant_layers: set[str] = {
249 + param_name.rsplit(".", 1)[0]
250 + for param_name, info in metadata.items()
251 + if (dtype := info.get("dtype", None))
252 + and _SAFETENSORS_TO_TORCH_DTYPE[dtype] not in unquant_dtypes
253 + }
254 + self.modules_to_not_convert = list(layers - quant_layers)
255 +
256
257 class AWQMarlinLinearMethod(LinearMethodBase):
258 """Linear method for AWQ Marlin.
vllm/model_executor/layers/quantization/gptq.py
+2 -1
@@ -32,6 +32,7 @@ from vllm.utils.collection_utils import is_list_of
32
33 if TYPE_CHECKING:
34 from vllm.model_executor.layers.quantization import QuantizationMethods
35 + from vllm.model_executor.models.utils import WeightsMapper
36 else:
37 QuantizationMethods = str
38
@@ -164,7 +165,7 @@ class GPTQConfig(QuantizationConfig):
165
166 return get_linear_quant_method(self, layer, prefix, GPTQLinearMethod)
167
167 - def apply_vllm_mapper(self, hf_to_vllm_mapper):
168 + def apply_vllm_mapper(self, hf_to_vllm_mapper: "WeightsMapper"):
169 if self.modules_in_block_to_quantize is not None:
170 self.modules_in_block_to_quantize = hf_to_vllm_mapper.apply_list(
171 self.modules_in_block_to_quantize
vllm/model_executor/layers/quantization/ipex_quant.py
+5 -5
@@ -24,12 +24,10 @@ from vllm.model_executor.layers.quantization import (
24 QuantizationConfig,
25 QuantizationMethods,
26 )
27 -from vllm.model_executor.layers.quantization.awq import (
28 - AWQLinearMethod,
29 - is_layer_skipped_awq,
30 -)
27 +from vllm.model_executor.layers.quantization.awq import AWQLinearMethod
28 from vllm.model_executor.layers.quantization.fp8 import Fp8Config, Fp8LinearMethod
29 from vllm.model_executor.layers.quantization.gptq import GPTQLinearMethod
30 +from vllm.model_executor.layers.quantization.utils.quant_utils import is_layer_skipped
31 from vllm.model_executor.utils import set_weight_attrs
32 from vllm.platforms import current_platform
33
@@ -139,7 +137,9 @@ class IPEXConfig(QuantizationConfig):
137 ) -> Optional["LinearMethodBase"]:
138 if isinstance(layer, LinearBase):
139 if self.method == "awq":
142 - if is_layer_skipped_awq(prefix, self.modules_to_not_convert):
140 + if is_layer_skipped(
141 + prefix, self.modules_to_not_convert, self.packed_modules_mapping
142 + ):
143 return UnquantizedLinearMethod()
144 return IPEXAWQLinearMethod(self)
145 if self.method == "gptq":
vllm/model_executor/layers/quantization/utils/quant_utils.py
+19 -8
@@ -285,7 +285,18 @@ def is_layer_skipped(
285 prefix: str,
286 ignored_layers: list[str],
287 fused_mapping: Mapping[str, list[str]] = MappingProxyType({}),
288 + *,
289 + skip_with_substr: bool = False,
290 ) -> bool:
291 + def prefix_full_match(prefix: str, ignored_layers: list[str]) -> bool:
292 + return prefix in ignored_layers
293 +
294 + # For case like: ignored_layers = ["self_attn"]
295 + def substr_match(prefix: str, ignored_layers: list[str]) -> bool:
296 + return any(layer in prefix for layer in ignored_layers)
297 +
298 + match_func = substr_match if skip_with_substr else prefix_full_match
299 +
300 # prefix: model.layers.0.self_attn.q_proj
301 # proj_name: q_proj
302 proj_name = prefix.split(".")[-1]
@@ -302,7 +313,7 @@ def is_layer_skipped(
313
314 is_skipped = None
315 for shard_prefix in shard_prefixes:
305 - is_shard_skipped = shard_prefix in ignored_layers
316 + is_shard_skipped = match_func(shard_prefix, ignored_layers)
317
318 if is_skipped is None:
319 is_skipped = is_shard_skipped
@@ -312,16 +323,16 @@ def is_layer_skipped(
323 "are quantized. All shards of fused layers "
324 "to have the same precision."
325 )
315 - elif "experts" in prefix:
326 + elif "experts" in prefix and not skip_with_substr:
327 + expert_ignore_layers = filter(
328 + lambda layer_name: "experts" in layer_name, ignored_layers
329 + )
330 return any(
317 - [
318 - prefix in layer_name
319 - for layer_name in ignored_layers
320 - if "experts" in layer_name
321 - ]
331 + prefix in layer_name if not skip_with_substr else layer_name in prefix
332 + for layer_name in expert_ignore_layers
333 )
334 else:
324 - is_skipped = prefix in ignored_layers
335 + is_skipped = match_func(prefix, ignored_layers)
336
337 assert is_skipped is not None
338 return is_skipped
vllm/model_executor/models/minicpmv.py
-16
@@ -42,8 +42,6 @@ from typing_extensions import TypeVar
42 from vllm.config import VllmConfig
43 from vllm.config.multimodal import BaseDummyOptions
44 from vllm.model_executor.layers.quantization import QuantizationConfig
45 -from vllm.model_executor.layers.quantization.awq import AWQConfig
46 -from vllm.model_executor.layers.quantization.awq_marlin import AWQMarlinConfig
45 from vllm.model_executor.layers.resampler import (
46 BaseResampler,
47 Resampler2,
@@ -1514,11 +1512,6 @@ class MiniCPMV4_0(MiniCPMVBaseModel, SupportsLoRA):
1512 super().__init__(vllm_config=vllm_config, prefix=prefix)
1513 assert self.version == (4, 0)
1514
1517 - def _maybe_ignore_quant_config(self, quant_config: QuantizationConfig):
1518 - if isinstance(quant_config, (AWQConfig, AWQMarlinConfig)):
1519 - return None
1520 - return quant_config
1521 -
1515 def init_llm(
1516 self,
1517 vllm_config: VllmConfig,
@@ -1532,7 +1525,6 @@ class MiniCPMV4_0(MiniCPMVBaseModel, SupportsLoRA):
1525 quant_config: QuantizationConfig | None = None,
1526 prefix: str = "",
1527 ) -> nn.Module:
1535 - quant_config = self._maybe_ignore_quant_config(quant_config)
1528 model = Idefics2VisionTransformer(
1529 config.vision_config,
1530 quant_config=quant_config,
@@ -1550,7 +1542,6 @@ class MiniCPMV4_0(MiniCPMVBaseModel, SupportsLoRA):
1542 quant_config: QuantizationConfig | None = None,
1543 prefix: str = "",
1544 ) -> nn.Module:
1553 - quant_config = self._maybe_ignore_quant_config(quant_config)
1545 with set_default_torch_dtype(torch.float16):
1546 # The resampler in 4.0 remains consistent with the one in 2.5/2.6.
1547 resampler = Resampler2_5(
@@ -1619,11 +1610,6 @@ class MiniCPMV4_5(MiniCPMVBaseModel, SupportsLoRA):
1610 super().__init__(vllm_config=vllm_config, prefix=prefix)
1611 assert self.version == (4, 5)
1612
1622 - def _maybe_ignore_quant_config(self, quant_config: QuantizationConfig):
1623 - if isinstance(quant_config, (AWQConfig, AWQMarlinConfig)):
1624 - return None
1625 - return quant_config
1626 -
1613 def init_llm(
1614 self,
1615 vllm_config: VllmConfig,
@@ -1637,7 +1623,6 @@ class MiniCPMV4_5(MiniCPMVBaseModel, SupportsLoRA):
1623 quant_config: QuantizationConfig | None = None,
1624 prefix: str = "",
1625 ) -> nn.Module:
1640 - quant_config = self._maybe_ignore_quant_config(quant_config)
1626 model = Idefics2VisionTransformer(
1627 config.vision_config,
1628 quant_config=quant_config,
@@ -1655,7 +1640,6 @@ class MiniCPMV4_5(MiniCPMVBaseModel, SupportsLoRA):
1640 quant_config: QuantizationConfig | None = None,
1641 prefix: str = "",
1642 ) -> nn.Module:
1658 - quant_config = self._maybe_ignore_quant_config(quant_config)
1643 with set_default_torch_dtype(torch.float16):
1644 # The resampler in 4.0 remains consistent with the one in 2.5/2.6.
1645 resampler = Resampler4_5(