main
py 126 lines 4.36 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4
5 import torch
6
7 from vllm import _custom_ops as ops
8 from vllm.model_executor.layers.quantization.utils.machete_utils import (
9 check_machete_supports_shape,
10 query_machete_supported_group_sizes,
11 query_machete_supported_quant_types,
12 )
13 from vllm.model_executor.layers.quantization.utils.quant_utils import (
14 unpack_quantized_values_into_int32,
15 )
16 from vllm.model_executor.parameter import BasevLLMParameter, permute_param_layout_
17 from vllm.platforms import current_platform
18
19 from .MPLinearKernel import MPLinearKernel, MPLinearLayerConfig
20
21
22 class MacheteLinearKernel(MPLinearKernel):
23 @classmethod
24 def get_min_capability(cls) -> int:
25 return 90
26
27 @classmethod
28 def can_implement(cls, c: MPLinearLayerConfig) -> tuple[bool, str | None]:
29 # Machete uses CUTLASS, so it can only be compatible with Nvidia
30 if not current_platform.is_cuda():
31 return False, "Machete only supported on CUDA"
32
33 if not current_platform.is_device_capability(90):
34 return False, "Machete requires compute capability of 90 (Hopper)"
35
36 if c.weight_type not in query_machete_supported_quant_types(c.zero_points):
37 return (
38 False,
39 f"Quant type ({c.weight_type}) not supported by "
40 "Machete, supported types are: "
41 f"{query_machete_supported_quant_types(c.zero_points)}",
42 )
43
44 if c.group_size not in query_machete_supported_group_sizes(c.act_type):
45 return (
46 False,
47 f"Group size ({c.group_size}) not supported by "
48 "Machete, supported group sizes are: "
49 f"{query_machete_supported_group_sizes(c.act_type)}",
50 )
51
52 return check_machete_supports_shape(
53 c.partition_weight_shape[0], c.partition_weight_shape[1]
54 )
55
56 # note assumes that
57 # `weight_packed` is: {input_dim = 0, output_dim = 1, packed_dim = 0}
58 # `weight_scale` is: {input_dim = 0, output_dim = 1}
59 # `weight_zp` is: {input_dim = 0, output_dim = 1, packed_dim = 1}
60 def process_weights_after_loading(self, layer: torch.nn.Module):
61 c = self.config
62
63 def transform_w_q(x):
64 assert isinstance(x, BasevLLMParameter)
65 permute_param_layout_(x, input_dim=0, output_dim=1, packed_dim=0)
66 x.data = ops.machete_prepack_B(
67 x.data.t().contiguous().t(),
68 a_type=c.act_type,
69 b_type=c.weight_type,
70 group_scales_type=c.act_type,
71 )
72 return x
73
74 def transform_w_s(x):
75 assert isinstance(x, BasevLLMParameter)
76 permute_param_layout_(x, input_dim=0, output_dim=1)
77 x.data = x.data.contiguous()
78 return x
79
80 def transform_w_zp(x):
81 assert isinstance(x, BasevLLMParameter)
82 permute_param_layout_(x, input_dim=0, output_dim=1, packed_dim=1)
83 x_unpacked = unpack_quantized_values_into_int32(
84 x.data, c.weight_type, packed_dim=1
85 )
86 w_s = getattr(layer, self.w_s_name).data
87 # pre-apply scales to zero-points
88 x.data = (-1.0 * w_s * (x_unpacked.to(w_s.dtype))).contiguous()
89 return x
90
91 # Repack weights and scales for Machete
92 self._transform_param(layer, self.w_q_name, transform_w_q)
93 self._transform_param(layer, self.w_s_name, transform_w_s)
94 if c.zero_points:
95 self._transform_param(layer, self.w_zp_name, transform_w_zp)
96
97 def apply_weights(
98 self,
99 layer: torch.nn.Module,
100 x: torch.Tensor,
101 bias: torch.Tensor | None = None,
102 ) -> torch.Tensor:
103 c = self.config
104 w_q, w_s, w_zp = self._get_weight_params(layer)
105
106 x_2d = x.reshape(-1, x.shape[-1])
107 out_shape = x.shape[:-1] + (c.partition_weight_shape[1],)
108
109 if c.zero_points:
110 assert w_zp is not None
111 else:
112 w_zp = None
113
114 output = ops.machete_mm(
115 a=x_2d,
116 b_q=w_q,
117 b_type=c.weight_type,
118 b_group_zeros=w_zp,
119 b_group_scales=w_s,
120 b_group_size=c.group_size,
121 )
122
123 if bias is not None:
124 output.add_(bias) # In-place add
125
126 return output.reshape(out_shape)