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 15, 17:15 UTC
[Quantization][FP8] Adding support for fp8 gemm layer input in fp8 (#14578)
Signed-off-by: Gregory Shtrasberg <Gregory.Shtrasberg@amd.com> Co-authored-by: Luka Govedič <ProExpertProg@users.noreply.github.com>
Gregory Shtrasberg committed
Mar 27, 2025 at 22:58 UTC
4d0ec37267afaf988e32174ebc31f24268076491
5 files changed
+41
-9
vllm/model_executor/layers/quantization/compressed_tensors/schemes/compressed_tensors_w8a8_fp8.py
+2
@@ -23,6 +23,7 @@ class CompressedTensorsW8A8Fp8(CompressedTensorsScheme):
23
24
def __init__(self, strategy: str, is_static_input_scheme: bool):
25
self.strategy = strategy
26
+ self.out_dtype = torch.get_default_dtype()
27
self.is_static_input_scheme = is_static_input_scheme
28
self.fp8_linear = Fp8LinearOp(use_per_token_if_dynamic=True)
29
@@ -143,5 +144,6 @@ class CompressedTensorsW8A8Fp8(CompressedTensorsScheme):
144
return self.fp8_linear.apply(input=x,
145
weight=layer.weight,
146
weight_scale=layer.weight_scale,
147
+ out_dtype=self.out_dtype,
148
input_scale=layer.input_scale,
149
bias=bias)
vllm/model_executor/layers/quantization/fbgemm_fp8.py
+2
@@ -73,6 +73,7 @@ class FBGEMMFp8LinearMethod(LinearMethodBase):
73
def __init__(self, quant_config: FBGEMMFp8Config):
74
self.quant_config = quant_config
75
self.fp8_linear = Fp8LinearOp(use_per_token_if_dynamic=True)
76
+ self.out_dtype = torch.get_default_dtype()
77
78
def create_weights(
79
self,
@@ -161,6 +162,7 @@ class FBGEMMFp8LinearMethod(LinearMethodBase):
162
return self.fp8_linear.apply(input=x,
163
weight=layer.weight,
164
weight_scale=layer.weight_scale,
165
+ out_dtype=self.out_dtype,
166
input_scale=None,
167
input_scale_ub=layer.input_scale_ub,
168
bias=bias)
vllm/model_executor/layers/quantization/fp8.py
+17
@@ -116,6 +116,21 @@ class Fp8Config(QuantizationConfig):
116
return Fp8KVCacheMethod(self)
117
return None
118
119
+ def get_cache_scale(self, name: str) -> Optional[str]:
120
+ """
121
+ Check whether the param name matches the format for k/v cache scales
122
+ in compressed-tensors. If this is the case, return its equivalent
123
+ param name expected by vLLM
124
+
125
+ :param name: param name
126
+ :return: matching param name for KV cache scale in vLLM
127
+ """
128
+ if name.endswith(".output_scale") and ".k_proj" in name:
129
+ return name.replace(".k_proj.output_scale", ".attn.k_scale")
130
+ if name.endswith(".output_scale") and ".v_proj" in name:
131
+ return name.replace(".v_proj.output_scale", ".attn.v_scale")
132
+ return None
133
+
134
135
class Fp8LinearMethod(LinearMethodBase):
136
"""Linear method for FP8.
@@ -138,6 +153,7 @@ class Fp8LinearMethod(LinearMethodBase):
153
def __init__(self, quant_config: Fp8Config):
154
self.quant_config = quant_config
155
self.cutlass_block_fp8_supported = cutlass_block_fp8_supported()
156
+ self.out_dtype = torch.get_default_dtype()
157
158
# For GPUs that lack FP8 hardware support, we can leverage the Marlin
159
# kernel for fast weight-only FP8 quantization
@@ -386,6 +402,7 @@ class Fp8LinearMethod(LinearMethodBase):
402
return self.fp8_linear.apply(input=x,
403
weight=layer.weight,
404
weight_scale=layer.weight_scale,
405
+ out_dtype=self.out_dtype,
406
input_scale=layer.input_scale,
407
bias=bias)
408
vllm/model_executor/layers/quantization/quark/schemes/quark_w8a8_fp8.py
+2
@@ -22,6 +22,7 @@ class QuarkW8A8Fp8(QuarkScheme):
22
self.qscheme = qscheme
23
self.is_static_input_scheme = is_static_input_scheme
24
self.fp8_linear = Fp8LinearOp(use_per_token_if_dynamic=True)
25
+ self.out_dtype = torch.get_default_dtype()
26
27
@classmethod
28
def get_min_capability(cls) -> int:
@@ -134,5 +135,6 @@ class QuarkW8A8Fp8(QuarkScheme):
135
return self.fp8_linear.apply(input=x,
136
weight=layer.weight,
137
weight_scale=layer.weight_scale,
138
+ out_dtype=self.out_dtype,
139
input_scale=layer.input_scale,
140
bias=bias)
vllm/model_executor/layers/quantization/utils/w8a8_utils.py
+18
-9
@@ -163,6 +163,7 @@ class Fp8LinearOp:
163
input: torch.Tensor,
164
weight: torch.Tensor,
165
weight_scale: torch.Tensor,
166
+ out_dtype: Optional[torch.dtype] = None,
167
input_scale: Optional[torch.Tensor] = None,
168
input_scale_ub: Optional[torch.Tensor] = None,
169
bias: Optional[torch.Tensor] = None,
@@ -182,8 +183,13 @@ class Fp8LinearOp:
183
if use_per_token_if_dynamic is None:
184
use_per_token_if_dynamic = self.use_per_token_if_dynamic
185
186
+ if out_dtype is None:
187
+ out_dtype = input.dtype
188
+
189
# cutlass_scaled_mm supports per tensor/channel W and per tensor/token A
190
if self.cutlass_fp8_supported:
191
+ assert input.dtype != current_platform.fp8_dtype(
192
+ ), "FP8 input to cutlass is not currently implemented"
193
qinput, x_scale = ops.scaled_fp8_quant(
194
input_2d,
195
input_scale,
@@ -193,7 +199,7 @@ class Fp8LinearOp:
199
# Fused GEMM_DQ
200
output = ops.cutlass_scaled_mm(qinput,
201
weight,
196
- out_dtype=input.dtype,
202
+ out_dtype=out_dtype,
203
scale_a=x_scale,
204
scale_b=weight_scale,
205
bias=bias)
@@ -202,12 +208,15 @@ class Fp8LinearOp:
208
# torch.scaled_mm supports per tensor weights + activations only
209
# so fallback to naive if per channel or per token
210
else:
205
- # Maybe apply padding to output, see comment in __init__
206
- qinput, x_scale = ops.scaled_fp8_quant(
207
- input_2d,
208
- input_scale,
209
- num_token_padding=self.output_padding,
210
- use_per_token_if_dynamic=use_per_token_if_dynamic)
211
+ if input.dtype != current_platform.fp8_dtype():
212
+ # Maybe apply padding to output, see comment in __init__
213
+ qinput, x_scale = ops.scaled_fp8_quant(
214
+ input_2d,
215
+ input_scale,
216
+ num_token_padding=self.output_padding,
217
+ use_per_token_if_dynamic=use_per_token_if_dynamic)
218
+ else:
219
+ qinput, x_scale = input_2d, input_scale
220
221
per_tensor_weights = (weight_scale.numel() == 1)
222
per_tensor_activations = (x_scale.numel() == 1)
@@ -216,7 +225,7 @@ class Fp8LinearOp:
225
# Fused GEMM_DQ
226
output = torch._scaled_mm(qinput,
227
weight,
219
- out_dtype=input.dtype,
228
+ out_dtype=out_dtype,
229
scale_a=x_scale,
230
scale_b=weight_scale,
231
bias=bias)
@@ -240,7 +249,7 @@ class Fp8LinearOp:
249
# Fused GEMM_DQ Rowwise GEMM
250
output = torch._scaled_mm(qinput,
251
weight,
243
- out_dtype=input.dtype,
252
+ out_dtype=out_dtype,
253
scale_a=x_scale,
254
scale_b=weight_scale.t(),
255
bias=bias)