main
py 149 lines 5.08 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 import torch
5
6 import vllm.envs as envs
7 from vllm.config import get_current_vllm_config
8 from vllm.model_executor.layers.quantization.input_quant_fp8 import QuantFP8
9 from vllm.model_executor.layers.quantization.utils.fp8_utils import (
10 deepgemm_post_process_fp8_weight_block,
11 )
12 from vllm.model_executor.layers.quantization.utils.quant_utils import (
13 GroupShape,
14 )
15 from vllm.model_executor.utils import replace_parameter
16 from vllm.platforms import current_platform
17 from vllm.utils.deep_gemm import (
18 fp8_gemm_nt,
19 is_deep_gemm_e8m0_used,
20 is_deep_gemm_supported,
21 should_auto_disable_deep_gemm,
22 should_use_deepgemm_for_fp8_linear,
23 )
24 from vllm.utils.torch_utils import direct_register_custom_op
25
26 from .BlockScaledMMLinearKernel import (
27 Fp8BlockScaledMMLinearKernel,
28 FP8ScaledMMLinearLayerConfig,
29 )
30
31
32 class DeepGemmFp8BlockScaledMMKernel(Fp8BlockScaledMMLinearKernel):
33 def __init__(self, config: FP8ScaledMMLinearLayerConfig):
34 super().__init__(config)
35 self.use_deep_gemm_e8m0 = is_deep_gemm_e8m0_used()
36 act_scale_descriptor = config.activation_quant_key.scale
37 self.is_deep_gemm_supported = is_deep_gemm_supported()
38 self.quant_fp8 = QuantFP8(
39 static=False,
40 group_shape=act_scale_descriptor.group_shape,
41 use_ue8m0=self.use_deep_gemm_e8m0,
42 tma_aligned_scales=envs.VLLM_USE_DEEP_GEMM_TMA_ALIGNED_SCALES,
43 column_major_scales=True,
44 )
45
46 @classmethod
47 def is_supported(cls, compute_capability=None):
48 if not current_platform.is_cuda():
49 return False, "DeepGEMM is only supported on cuda platform"
50 if not is_deep_gemm_supported():
51 return False, "Currently, only Hopper and Blackwell GPUs are supported."
52 return True, None
53
54 @classmethod
55 def can_implement(cls, config):
56 can_implement_base, reason = super().can_implement(config)
57 if not can_implement_base:
58 return can_implement_base, reason
59 if config.out_dtype != torch.bfloat16:
60 return (False, "Supports only output dtype of bfloat16")
61
62 act_quant_desc = config.activation_quant_key.scale
63 if act_quant_desc.group_shape != GroupShape(1, 128):
64 return (
65 False,
66 "Supports only dynamic per token group activation "
67 "quantization with group_shape=(1,128).",
68 )
69 model_config = get_current_vllm_config().model_config
70
71 if model_config is None:
72 return False, "Model configuration is required."
73
74 model_type = getattr(model_config.hf_text_config, "model_type", None)
75 if should_auto_disable_deep_gemm(model_type):
76 return False, f"Should not use deepgemm for model {model_type}"
77
78 if not should_use_deepgemm_for_fp8_linear(
79 config.out_dtype, config.weight_shape
80 ):
81 return False, "The provided metadata is not supported."
82 return True, None
83
84 def process_weights_after_loading(self, layer):
85 super().process_weights_after_loading(layer)
86 params = self._get_layer_params(layer)
87 assert layer.weight_block_size is not None
88
89 is_bmm = getattr(layer, "is_bmm", False)
90
91 if self.is_deep_gemm_supported:
92 dg_weight, dg_weight_scale = deepgemm_post_process_fp8_weight_block(
93 wq=params.weight,
94 ws=params.block_scale,
95 quant_block_shape=tuple(layer.weight_block_size),
96 use_e8m0=self.use_deep_gemm_e8m0,
97 is_bmm=is_bmm,
98 bmm_batch_size=getattr(layer, "bmm_batch_size", 0),
99 )
100 replace_parameter(layer, params.WEIGHT, dg_weight)
101 replace_parameter(layer, params.block_scale_attr, dg_weight_scale)
102 # bmm layers bypass this kernel and run through fp8_einsum.
103 if not is_bmm:
104 layer.deep_gemm_warmup_provider = self
105
106 def get_deep_gemm_warmup_weights(
107 self, layer: torch.nn.Module
108 ) -> tuple[torch.Tensor, torch.Tensor]:
109 params = self._get_layer_params(layer)
110 return params.weight, params.block_scale
111
112 def apply_block_scaled_mm(
113 self,
114 A: torch.Tensor,
115 B: torch.Tensor,
116 As: torch.Tensor,
117 Bs: torch.Tensor,
118 ) -> torch.Tensor:
119 out_dtype = self.config.out_dtype
120 output = torch.empty(
121 (A.shape[0], B.shape[0]),
122 dtype=out_dtype,
123 device=A.device,
124 )
125 torch.ops.vllm.fp8_gemm_nt_op(A, As, B, Bs, output, self.use_deep_gemm_e8m0)
126 return output
127
128
129 def _fp8_gemm_nt_op(
130 q_input: torch.Tensor,
131 input_scale: torch.Tensor,
132 weight: torch.Tensor,
133 weight_scale: torch.Tensor,
134 output: torch.Tensor,
135 use_deep_gemm_e8m0: bool,
136 ) -> None:
137 fp8_gemm_nt(
138 (q_input, input_scale),
139 (weight, weight_scale),
140 output,
141 is_deep_gemm_e8m0_used=use_deep_gemm_e8m0,
142 )
143
144
145 direct_register_custom_op(
146 "fp8_gemm_nt_op",
147 _fp8_gemm_nt_op,
148 mutates_args=["output"],
149 )