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 10, 16:30 UTC
[Quantization][Refactor] Move CPU GPTQ kernel into MP linear (#31801)
Signed-off-by: jiang1.li <jiang1.li@intel.com> Signed-off-by: Li, Jiang <bigpyj64@gmail.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Li, Jiang committed
Jan 7, 2026 at 03:10 UTC
8becf146bdc42bb7ad3acb4af374d58de65c4432
9 files changed
+171
-332
tests/quantization/test_cpu_wna16.py
+1
@@ -10,6 +10,7 @@ if not current_platform.is_cpu():
10
MODELS = [
11
"TheBloke/TinyLlama-1.1B-Chat-v1.0-AWQ",
12
"TheBloke/TinyLlama-1.1B-Chat-v1.0-GPTQ", # with g_idx
13
+ "Qwen/Qwen1.5-0.5B-Chat-GPTQ-Int4", # without g_idx
14
]
15
DTYPE = ["bfloat16"]
16
vllm/config/model.py
-1
@@ -876,7 +876,6 @@ class ModelConfig:
876
# Ensure heavy backends are probed last to avoid unnecessary
877
# imports during override detection (e.g., MXFP4 imports Triton)
878
"mxfp4",
879
- "cpu_gptq",
879
"cpu_awq",
880
]
881
quantization_methods = [
vllm/model_executor/layers/quantization/__init__.py
+1
-3
@@ -38,7 +38,6 @@ QuantizationMethods = Literal[
38
"inc",
39
"mxfp4",
40
"petit_nvfp4",
41
- "cpu_gptq",
41
"cpu_awq",
42
]
43
QUANTIZATION_METHODS: list[str] = list(get_args(QuantizationMethods))
@@ -109,7 +108,7 @@ def get_quantization_config(quantization: str) -> type[QuantizationConfig]:
108
from .compressed_tensors.compressed_tensors import (
109
CompressedTensorsConfig,
110
)
112
- from .cpu_wna16 import CPUAWQConfig, CPUGPTQConfig
111
+ from .cpu_wna16 import CPUAWQConfig
112
from .deepspeedfp import DeepSpeedFPConfig
113
from .experts_int8 import ExpertsInt8Config
114
from .fbgemm_fp8 import FBGEMMFp8Config
@@ -162,7 +161,6 @@ def get_quantization_config(quantization: str) -> type[QuantizationConfig]:
161
"inc": INCConfig,
162
"mxfp4": Mxfp4Config,
163
"petit_nvfp4": PetitNvFp4Config,
165
- "cpu_gptq": CPUGPTQConfig,
164
"cpu_awq": CPUAWQConfig,
165
}
166
# Update the `method_to_config` with customized quantization methods.
vllm/model_executor/layers/quantization/cpu_wna16.py
-326
@@ -20,12 +20,6 @@ from vllm.model_executor.layers.quantization.base_config import (
20
QuantizationConfig,
21
QuantizeMethodBase,
22
)
23
-from vllm.model_executor.layers.quantization.utils.gptq_utils import (
24
- get_linear_quant_method,
25
-)
26
-from vllm.model_executor.layers.quantization.utils.marlin_utils import (
27
- marlin_repeat_scales_on_all_ranks,
28
-)
23
from vllm.model_executor.layers.quantization.utils.quant_utils import (
24
is_layer_skipped,
25
pack_cols,
@@ -34,335 +28,15 @@ from vllm.model_executor.layers.quantization.utils.quant_utils import (
28
from vllm.model_executor.layers.vocab_parallel_embedding import ParallelLMHead
29
from vllm.model_executor.models.utils import WeightsMapper
30
from vllm.model_executor.parameter import (
37
- ChannelQuantScaleParameter,
31
GroupQuantScaleParameter,
39
- PackedColumnParameter,
32
PackedvLLMParameter,
41
- RowvLLMParameter,
33
)
43
-from vllm.model_executor.utils import set_weight_attrs
34
from vllm.platforms import current_platform
35
from vllm.transformers_utils.config import get_safetensors_params_metadata
46
-from vllm.utils.collection_utils import is_list_of
36
37
logger = init_logger(__name__)
38
39
51
-class CPUGPTQConfig(QuantizationConfig):
52
- """Config class for CPU GPTQ quant"""
53
-
54
- def __init__(
55
- self,
56
- weight_bits: int,
57
- group_size: int,
58
- desc_act: bool,
59
- is_sym: bool,
60
- lm_head_quantized: bool,
61
- dynamic: dict[str, dict[str, int | bool]],
62
- full_config: dict[str, Any],
63
- modules_in_block_to_quantize: list[str] | None = None,
64
- ) -> None:
65
- super().__init__()
66
- if desc_act and group_size == -1:
67
- # In this case, act_order == True is the same as act_order == False
68
- # (since we have only one group per output channel)
69
- desc_act = False
70
-
71
- # GPTQModel use `dynamic` config property to allow per module
72
- # quantization config so each module can be individually optimized.
73
- # Format is dict[str, dict] where key is a regex string that can
74
- # perform both positive ("+:" prefixed) or negative ("-:" prefixed)
75
- # matching of a module.
76
- # Default to positive match, override base quant config mode, if no
77
- # prefix is used. Value is in dict format of field key and override
78
- # value.
79
- # Negative matching will skip quantization init for this module
80
- # entirely:
81
- # non-quantized inference. More details and quantization examples can be
82
- # found at: https://github.com/ModelCloud/GPTQModel
83
- # Example:
84
- # # last 1/2 of the layers 10-21 has 8bit vs 4bit for 0-9
85
- # # last 1/4 of the layers 16-21 has 8bit and group_size 64
86
- # dynamic = {
87
- # #`.*\.` matches the layers_node prefix
88
- # # positive match layer 10-15
89
- # r"+:.*\.(?:1[0-5])\..*": {"bits": 8,},
90
- # # positive match layer 16-21
91
- # r"+:.*\.(?:1[6-9]|20|21)\..*": {"bits": 8, "group_size": 64,},
92
- # r"-:.*\.moe\..*": {}, # negative match (skip) all `moe` layers
93
- # }
94
- assert weight_bits == 4
95
- self.dynamic = dynamic
96
- self.weight_bits = weight_bits
97
- self.is_sym = is_sym
98
- self.pack_factor = 32 // weight_bits # packed into int32
99
- self.group_size = group_size
100
- self.desc_act = desc_act
101
- self.lm_head_quantized = lm_head_quantized
102
- self.full_config = full_config
103
- self.modules_in_block_to_quantize = modules_in_block_to_quantize or []
104
-
105
- def __repr__(self) -> str:
106
- return (
107
- f"CPUWNA16Config("
108
- f"group_size={self.group_size}, "
109
- f"desc_act={self.desc_act}, "
110
- f"lm_head_quantized={self.lm_head_quantized}, "
111
- f"dynamic={self.dynamic}, "
112
- f"modules_in_block_to_quantize={self.modules_in_block_to_quantize})"
113
- )
114
-
115
- @classmethod
116
- def get_name(cls) -> QuantizationMethods:
117
- return "cpu_gptq"
118
-
119
- @classmethod
120
- def get_supported_act_dtypes(cls) -> list[torch.dtype]:
121
- return [torch.half, torch.bfloat16]
122
-
123
- @classmethod
124
- def get_min_capability(cls) -> int:
125
- return -1
126
-
127
- @classmethod
128
- def get_config_filenames(cls) -> list[str]:
129
- return ["quantize_config.json"]
130
-
131
- @classmethod
132
- def from_config(cls, config: dict[str, Any]) -> "CPUGPTQConfig":
133
- weight_bits = cls.get_from_keys(config, ["bits"])
134
- desc_act = cls.get_from_keys_or(config, ["desc_act"], default=False)
135
- dynamic = cls.get_from_keys_or(config, ["dynamic"], default={})
136
- group_size = cls.get_from_keys(config, ["group_size"])
137
- is_sym = cls.get_from_keys(config, ["sym"])
138
- lm_head_quantized = cls.get_from_keys_or(config, ["lm_head"], default=False)
139
- modules_in_block_to_quantize = cls.get_from_keys_or(
140
- config, ["modules_in_block_to_quantize"], default=None
141
- )
142
- return cls(
143
- weight_bits,
144
- group_size,
145
- desc_act,
146
- is_sym,
147
- lm_head_quantized,
148
- dynamic,
149
- config,
150
- modules_in_block_to_quantize,
151
- )
152
-
153
- @classmethod
154
- def override_quantization_method(
155
- cls, hf_quant_cfg, user_quant
156
- ) -> QuantizationMethods | None:
157
- quant_method = hf_quant_cfg.get("quant_method", "").lower()
158
- if current_platform.is_cpu() and (quant_method == "gptq"):
159
- return cls.get_name()
160
- return None
161
-
162
- def get_quant_method(
163
- self, layer: torch.nn.Module, prefix: str
164
- ) -> Optional["QuantizeMethodBase"]:
165
- return get_linear_quant_method(self, layer, prefix, CPUGPTQLinearMethod) # type: ignore
166
-
167
- def apply_vllm_mapper(self, hf_to_vllm_mapper):
168
- if self.modules_in_block_to_quantize is not None:
169
- self.modules_in_block_to_quantize = hf_to_vllm_mapper.apply_list(
170
- self.modules_in_block_to_quantize
171
- )
172
-
173
- def maybe_update_config(self, model_name: str, revision: str | None = None):
174
- if self.modules_in_block_to_quantize:
175
- if is_list_of(self.modules_in_block_to_quantize, list):
176
- # original modules_in_block_to_quantize: list[list[str]]
177
- # flatten original modules_in_block_to_quantize
178
- self.modules_in_block_to_quantize = [
179
- item
180
- for sublist in self.modules_in_block_to_quantize
181
- for item in sublist
182
- ]
183
- return
184
-
185
- unquant_dtypes = [torch.float16, torch.bfloat16, torch.float32]
186
- metadata = get_safetensors_params_metadata(model_name, revision=revision)
187
- quant_layers: set[str] = {
188
- param_name.rsplit(".", 1)[0]
189
- for param_name, info in metadata.items()
190
- if (dtype := info.get("dtype", None))
191
- and _SAFETENSORS_TO_TORCH_DTYPE[dtype] not in unquant_dtypes
192
- }
193
- self.modules_in_block_to_quantize = list(quant_layers)
194
-
195
-
196
-class CPUGPTQLinearMethod(LinearMethodBase):
197
- """Linear method for GPTQ on CPU.
198
-
199
- Args:
200
- quant_config: The CPUWNA16 quantization config.
201
- """
202
-
203
- def __init__(self, quant_config: CPUGPTQConfig) -> None:
204
- self.quant_config = quant_config
205
- assert self.quant_config.is_sym, "GPTQ asym quant is not supported on CPU"
206
-
207
- def create_weights(
208
- self,
209
- layer: torch.nn.Module,
210
- input_size_per_partition: int,
211
- output_partition_sizes: list[int],
212
- input_size: int,
213
- output_size: int,
214
- params_dtype: torch.dtype,
215
- **extra_weight_attrs,
216
- ) -> None:
217
- output_size_per_partition = sum(output_partition_sizes)
218
- assert output_size_per_partition * self.quant_config.weight_bits % 32 == 0
219
- assert output_size_per_partition % 32 == 0
220
- assert input_size_per_partition % 32 == 0
221
-
222
- is_row_parallel = input_size != input_size_per_partition
223
- weight_loader = extra_weight_attrs.get("weight_loader")
224
-
225
- # Normalize group_size
226
- if self.quant_config.group_size != -1:
227
- group_size = self.quant_config.group_size
228
- else:
229
- group_size = input_size
230
-
231
- # Determine sharding
232
- if marlin_repeat_scales_on_all_ranks(
233
- self.quant_config.desc_act, self.quant_config.group_size, is_row_parallel
234
- ):
235
- # By setting scale_dim == None, weight_loader will
236
- # repeat the scales on each rank in TP>1 case.
237
- scales_and_zp_input_dim = None
238
- scales_and_zp_size = input_size // group_size
239
- else:
240
- # By setting scale_dim == 0, weight_loader will
241
- # shard the scales in TP>1 case.
242
- scales_and_zp_input_dim = 0
243
- scales_and_zp_size = input_size_per_partition // group_size
244
-
245
- # Quantized weights
246
- qweight = PackedvLLMParameter(
247
- data=torch.empty(
248
- input_size_per_partition // self.quant_config.pack_factor,
249
- output_size_per_partition,
250
- dtype=torch.int32,
251
- ),
252
- input_dim=0,
253
- output_dim=1,
254
- packed_dim=0,
255
- packed_factor=self.quant_config.pack_factor,
256
- weight_loader=weight_loader,
257
- )
258
-
259
- # Activation order
260
- g_idx = RowvLLMParameter(
261
- data=torch.empty(
262
- input_size_per_partition,
263
- dtype=torch.int32,
264
- ),
265
- input_dim=0,
266
- weight_loader=weight_loader,
267
- )
268
- set_weight_attrs(
269
- g_idx,
270
- {"ignore_warning": True},
271
- )
272
-
273
- qzeros_args = {
274
- "data": torch.empty(
275
- scales_and_zp_size,
276
- output_size_per_partition // self.quant_config.pack_factor,
277
- dtype=torch.int32,
278
- ),
279
- "weight_loader": weight_loader,
280
- }
281
- weight_scale_args = {
282
- "data": torch.empty(
283
- scales_and_zp_size,
284
- output_size_per_partition,
285
- dtype=params_dtype,
286
- ),
287
- "weight_loader": weight_loader,
288
- }
289
-
290
- if scales_and_zp_input_dim is None:
291
- scales = ChannelQuantScaleParameter(output_dim=1, **weight_scale_args)
292
- qzeros = PackedColumnParameter(
293
- output_dim=1,
294
- packed_dim=1,
295
- packed_factor=self.quant_config.pack_factor,
296
- **qzeros_args,
297
- )
298
-
299
- else:
300
- scales = GroupQuantScaleParameter(
301
- output_dim=1, input_dim=0, **weight_scale_args
302
- )
303
- qzeros = PackedvLLMParameter(
304
- input_dim=0,
305
- output_dim=1,
306
- packed_dim=1,
307
- packed_factor=self.quant_config.pack_factor,
308
- **qzeros_args,
309
- )
310
-
311
- layer.register_parameter("qweight", qweight)
312
- layer.register_parameter("g_idx", g_idx)
313
- layer.register_parameter("scales", scales)
314
- layer.register_parameter("qzeros", qzeros)
315
-
316
- def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
317
- torch.set_printoptions(profile="full", linewidth=5000, sci_mode=False)
318
- packed_weight = layer.qweight.data
319
- bits = self.quant_config.weight_bits
320
- pack_factor = int(self.quant_config.pack_factor)
321
- p_w_k, p_w_n = packed_weight.size()
322
- input_size = p_w_k * pack_factor
323
- output_size = p_w_n
324
- isa_hint = _get_isa_hint(layer.scales.dtype)
325
- layer.isa_hint = isa_hint
326
-
327
- layer.qzeros = None
328
- if not self.quant_config.desc_act:
329
- layer.g_idx = None
330
-
331
- # convert input dim packed to output dim packed
332
- weight = unpack_cols(packed_weight, bits, p_w_k, p_w_n * pack_factor).view(
333
- p_w_k, p_w_n, pack_factor
334
- )
335
- weight = weight.permute(0, 2, 1).reshape(input_size, output_size).contiguous()
336
- weight = pack_cols(weight, bits, input_size, output_size)
337
- # make 16 output channel as a block and transpose to the make
338
- # the block contigous
339
- weight = (
340
- weight.view(input_size, -1, 16 // pack_factor)
341
- .permute(1, 0, 2)
342
- .reshape(-1, input_size * 16 // pack_factor)
343
- .contiguous()
344
- )
345
- layer.qweight.data = weight
346
-
347
- def apply(
348
- self,
349
- layer: torch.nn.Module,
350
- x: torch.Tensor,
351
- bias: torch.Tensor | None = None,
352
- ) -> torch.Tensor:
353
- x = cpu_gemm_wna16(
354
- input=x,
355
- q_weight=layer.qweight,
356
- scales=layer.scales,
357
- zeros=layer.qzeros,
358
- g_idx=layer.g_idx,
359
- bias=bias,
360
- pack_factor=8,
361
- isa_hint=layer.isa_hint,
362
- )
363
- return x
364
-
365
-
40
class CPUAWQConfig(QuantizationConfig):
41
"""Config class for CPU AWQ"""
42
vllm/model_executor/layers/quantization/gptq_marlin.py
+1
-1
@@ -276,7 +276,7 @@ class GPTQMarlinConfig(QuantizationConfig):
276
sym = quant_config.get("sym")
277
desc_act = quant_config.get("desc_act")
278
279
- if not current_platform.is_cuda():
279
+ if not (current_platform.is_cuda() or current_platform.is_cpu()):
280
return False
281
282
if quant_method != "gptq":
vllm/model_executor/layers/quantization/kernels/mixed_precision/__init__.py
+4
@@ -11,6 +11,9 @@ from vllm.model_executor.layers.quantization.kernels.mixed_precision.bitblas imp
11
from vllm.model_executor.layers.quantization.kernels.mixed_precision.conch import ( # noqa: E501
12
ConchLinearKernel,
13
)
14
+from vllm.model_executor.layers.quantization.kernels.mixed_precision.cpu import ( # noqa: E501
15
+ CPUWNA16LinearKernel,
16
+)
17
from vllm.model_executor.layers.quantization.kernels.mixed_precision.cutlass import ( # noqa: E501
18
CutlassW4A8LinearKernel,
19
)
@@ -46,6 +49,7 @@ _POSSIBLE_KERNELS: list[type[MPLinearKernel]] = [
49
ConchLinearKernel,
50
ExllamaLinearKernel,
51
XPUwNa16LinearKernel,
52
+ CPUWNA16LinearKernel,
53
]
54
55
vllm/model_executor/layers/quantization/kernels/mixed_precision/cpu.py
new
+126
@@ -0,0 +1,126 @@
1
+# SPDX-License-Identifier: Apache-2.0
2
+# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
+
4
+import torch
5
+
6
+from vllm import _custom_ops as ops
7
+from vllm.model_executor.layers.quantization.utils.quant_utils import (
8
+ pack_quantized_values_into_int32,
9
+ unpack_quantized_values_into_int32,
10
+)
11
+from vllm.platforms import current_platform
12
+from vllm.scalar_type import scalar_types
13
+
14
+from .MPLinearKernel import MPLinearKernel, MPLinearLayerConfig
15
+
16
+_CPUWNA16_SUPPORTED_QUANT_TYPES = (scalar_types.uint4, scalar_types.uint4b8)
17
+
18
+
19
+class CPUWNA16LinearKernel(MPLinearKernel):
20
+ @classmethod
21
+ def get_min_capability(cls) -> int:
22
+ return -1
23
+
24
+ @classmethod
25
+ def can_implement(cls, c: MPLinearLayerConfig) -> tuple[bool, str | None]:
26
+ if not current_platform.is_cpu():
27
+ return False, "CPUWNA16 only supported on CPU"
28
+
29
+ if c.weight_type not in _CPUWNA16_SUPPORTED_QUANT_TYPES:
30
+ return (
31
+ False,
32
+ f"Quant type ({c.weight_type}) not supported by "
33
+ "CPUWNA16, supported types are: "
34
+ f"{_CPUWNA16_SUPPORTED_QUANT_TYPES}",
35
+ )
36
+
37
+ if c.group_size != -1 and c.group_size % 2 != 0:
38
+ return (
39
+ False,
40
+ f"Group size ({c.group_size}) not supported by "
41
+ "CPUWNA16, supported group sizes are multiples of 2",
42
+ )
43
+
44
+ if c.partition_weight_shape[0] % 32 != 0:
45
+ return (
46
+ False,
47
+ f"Input size ({c.partition_weight_shape[0]}) not supported by "
48
+ "CPUWNA16, supported sizes are multiples of 32",
49
+ )
50
+
51
+ if c.partition_weight_shape[1] % 32 != 0:
52
+ return (
53
+ False,
54
+ f"Output size ({c.partition_weight_shape[1]}) not supported by "
55
+ "CPUWNA16, supported sizes are multiples of 32",
56
+ )
57
+
58
+ return True, None
59
+
60
+ # note assumes that
61
+ # `weight_packed` is: {input_dim = 0, output_dim = 1, packed_dim = 0}
62
+ # `weight_scale` is: {input_dim = 0, output_dim = 1}
63
+ # `weight_zp` is: {input_dim = 0, output_dim = 1, packed_dim = 1}
64
+ def _process_gptq_weights(self, layer: torch.nn.Module):
65
+ packed_weight = layer.qweight.data
66
+ bits = self.config.weight_type.mantissa
67
+ pack_factor = 32 // bits
68
+ p_w_k, p_w_n = packed_weight.size()
69
+ input_size = p_w_k * pack_factor
70
+ output_size = p_w_n
71
+ isa_hint = _get_isa_hint(layer.scales.dtype)
72
+ layer.isa_hint = isa_hint
73
+
74
+ layer.qzeros = None
75
+ if not self.config.has_g_idx:
76
+ layer.g_idx = None
77
+
78
+ # convert input dim packed to output dim packed
79
+ weight = unpack_quantized_values_into_int32(
80
+ packed_weight, self.config.weight_type, 1
81
+ ).view(p_w_k, p_w_n, pack_factor)
82
+ weight = weight.permute(0, 2, 1).reshape(input_size, output_size).contiguous()
83
+ weight = pack_quantized_values_into_int32(weight, self.config.weight_type, 1)
84
+ # make 16 output channel as a block and transpose to the make
85
+ # the block contigous
86
+ weight = (
87
+ weight.view(input_size, -1, 16 // pack_factor)
88
+ .permute(1, 0, 2)
89
+ .reshape(-1, input_size * 16 // pack_factor)
90
+ .contiguous()
91
+ )
92
+ layer.qweight.data = weight
93
+
94
+ def process_weights_after_loading(self, layer: torch.nn.Module):
95
+ if not self.config.zero_points:
96
+ # GPTQ
97
+ self._process_gptq_weights(layer)
98
+ else:
99
+ # AWQ
100
+ raise NotImplementedError("AWQ is not supported in CPUWNA16LinearKernel")
101
+
102
+ def apply_weights(
103
+ self,
104
+ layer: torch.nn.Module,
105
+ x: torch.Tensor,
106
+ bias: torch.Tensor | None = None,
107
+ ) -> torch.Tensor:
108
+ x = ops.cpu_gemm_wna16(
109
+ input=x,
110
+ q_weight=layer.qweight,
111
+ scales=layer.scales,
112
+ zeros=layer.qzeros,
113
+ g_idx=layer.g_idx,
114
+ bias=bias,
115
+ pack_factor=8, # 32 // 4
116
+ isa_hint=layer.isa_hint,
117
+ )
118
+ return x
119
+
120
+
121
+def _get_isa_hint(dtype: torch.dtype) -> str:
122
+ supports_amx = torch._C._cpu._is_amx_tile_supported()
123
+ if supports_amx and dtype in (torch.bfloat16,):
124
+ return "amx"
125
+ else:
126
+ return "vec"
vllm/model_executor/layers/quantization/kernels/mixed_precision/exllama.py
+8
-1
@@ -9,6 +9,7 @@ from vllm.model_executor.layers.quantization.utils.quant_utils import (
9
pack_quantized_values_into_int32,
10
)
11
from vllm.model_executor.parameter import BasevLLMParameter, permute_param_layout_
12
+from vllm.platforms import current_platform
13
from vllm.scalar_type import scalar_types
14
15
from .MPLinearKernel import MPLinearKernel, MPLinearLayerConfig
@@ -25,6 +26,12 @@ class ExllamaLinearKernel(MPLinearKernel):
26
27
@classmethod
28
def can_implement(cls, c: MPLinearLayerConfig) -> tuple[bool, str | None]:
29
+ if not current_platform.is_cuda_alike():
30
+ return (
31
+ False,
32
+ "Exllama is only supported on CUDA and ROCm",
33
+ )
34
+
35
if c.has_g_idx and c.partition_weight_shape[0] != c.full_weight_shape[0]:
36
return (
37
False,
@@ -104,7 +111,7 @@ class ExllamaLinearKernel(MPLinearKernel):
111
# indices
112
return torch.argsort(x).to(torch.int)
113
107
- self._transform_param(layer, self.w_gidx_name, transform_w_g_idx)
114
+ self._transform_param(layer, self.w_gidx_name, transform_w_g_idx) # type: ignore
115
else:
116
self.w_gidx_name = "g_idx"
117
empty_g_idx = torch.nn.Parameter(
vllm/model_executor/layers/quantization/utils/marlin_utils.py
+30
@@ -42,6 +42,9 @@ def query_marlin_supported_quant_types(
42
include_fp_type: bool = True,
43
device_capability: int | None = None,
44
):
45
+ if current_platform.is_cpu():
46
+ return _query_cpu_marlin_supported_quant_types(has_zp, include_fp_type)
47
+
48
if device_capability is None:
49
capability_tuple = current_platform.get_device_capability()
50
device_capability = (
@@ -74,6 +77,33 @@ def query_marlin_supported_quant_types(
77
return res
78
79
80
+def _query_cpu_marlin_supported_quant_types(
81
+ has_zp: bool | None = None,
82
+ include_fp_type: bool = True,
83
+):
84
+ # - has_zp is True: return quant_types that has zero points
85
+ # - has_zp is False: return quant_types that has not zero points
86
+ # - has_zp is None: both
87
+ if has_zp is None:
88
+ types0 = _query_cpu_marlin_supported_quant_types(
89
+ False,
90
+ include_fp_type,
91
+ )
92
+ types1 = _query_cpu_marlin_supported_quant_types(
93
+ True,
94
+ include_fp_type,
95
+ )
96
+ return types0 + types1
97
+
98
+ if has_zp:
99
+ # AWQ style, unsigned + runtime zero-point
100
+ return [scalar_types.uint4]
101
+ else:
102
+ # GPTQ style, unsigned + symmetric bias, only supports 4-bits for now
103
+ res = [scalar_types.uint4b8]
104
+ return res
105
+
106
+
107
def _check_marlin_supported(
108
quant_type: ScalarType,
109
group_size: int | None,