main
py 69 lines 2.02 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 import torch
5
6 from vllm._custom_ops import scaled_fp4_quant
7 from vllm.model_executor.layers.quantization.utils.nvfp4_utils import (
8 slice_nvfp4_output,
9 swizzle_blockscale,
10 )
11 from vllm.utils.import_utils import has_fbgemm_gpu
12
13 from .base import NvFp4LinearKernel, NvFp4LinearLayerConfig
14
15
16 class FbgemmNvFp4LinearKernel(NvFp4LinearKernel):
17 """NVFP4 GEMM via FBGEMM."""
18
19 @classmethod
20 def is_supported(
21 cls, compute_capability: int | None = None
22 ) -> tuple[bool, str | None]:
23 if has_fbgemm_gpu():
24 return True, None
25 return False, "fbgemm_gpu required"
26
27 @classmethod
28 def can_implement(cls, config: NvFp4LinearLayerConfig) -> tuple[bool, str | None]:
29 return True, None
30
31 def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
32 swizzled = swizzle_blockscale(layer.weight_scale.data)
33 layer.weight_scale = torch.nn.Parameter(
34 swizzled.view(-1).view(torch.uint8), requires_grad=False
35 )
36
37 def apply_weights(
38 self,
39 layer: torch.nn.Module,
40 x: torch.Tensor,
41 bias: torch.Tensor | None = None,
42 ) -> torch.Tensor:
43 import fbgemm_gpu # noqa: F401 - registers torch.ops.fbgemm.*
44
45 output_size = layer.output_size_per_partition
46 output_dtype = x.dtype
47 output_shape = [*x.shape[:-1], output_size]
48
49 x_fp4, x_blockscale = scaled_fp4_quant(
50 x,
51 layer.input_global_scale_inv,
52 is_sf_swizzled_layout=True,
53 backend="fbgemm",
54 )
55
56 out = torch.ops.fbgemm.f4f4bf16(
57 x_fp4,
58 layer.weight,
59 x_blockscale.view(-1).view(torch.uint8),
60 layer.weight_scale,
61 layer.alpha,
62 use_mx=False,
63 ).to(output_dtype)
64
65 out = slice_nvfp4_output(out, output_size)
66
67 if bias is not None:
68 out = out + bias
69 return out.view(*output_shape)