@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 8becf146bd
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 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,