[Quantization] Route per-tensor FP8 checkpoints to FlashInfer on SM90 (#33148)

Co-authored-by: Brayden Zhong <b8zhong@uwaterloo.ca>
This commit is contained in:
Aditya Kamat
2026-08-06 00:54:10 +00:00
committed by GitHub
co-authored by Brayden Zhong
parent 4c0a8940fa
commit c9506d023f
2 changed files with 27 additions and 15 deletions
@@ -311,14 +311,15 @@ class Fp8GemmRunnerBackend(Enum):
FP8_GEMM_RUNNER_BACKEND: Fp8GemmRunnerBackend | None = None
if is_blackwell_supported() and is_flashinfer_available():
from flashinfer import SfLayout
from flashinfer import bmm_fp8 as _raw_flashinfer_bmm_fp8
from flashinfer import mm_mxfp8 as _raw_flashinfer_mm_mxfp8
from flashinfer import mxfp8_quantize as _raw_flashinfer_mxfp8_quantize
from flashinfer.gemm import gemm_fp8_nt_groupwise as _raw_gemm_fp8_nt_groupwise
@lru_cache(maxsize=1)
def flashinfer_per_tensor_fp8_supported() -> bool:
return is_flashinfer_available() and (
is_sm90_supported() or is_sm100_supported() or is_sm120_supported()
)
from sglang.srt.utils.custom_op import register_custom_op
if flashinfer_per_tensor_fp8_supported():
from flashinfer import bmm_fp8 as _raw_flashinfer_bmm_fp8
@register_custom_op(
op_name="flashinfer_bmm_fp8",
@@ -344,6 +345,13 @@ if is_blackwell_supported() and is_flashinfer_available():
backend="cublas",
).view(m, n)
if is_blackwell_supported() and is_flashinfer_available():
from flashinfer import SfLayout
from flashinfer import mm_mxfp8 as _raw_flashinfer_mm_mxfp8
from flashinfer import mxfp8_quantize as _raw_flashinfer_mxfp8_quantize
from flashinfer.gemm import gemm_fp8_nt_groupwise as _raw_gemm_fp8_nt_groupwise
@lru_cache(maxsize=1)
def _get_flashinfer_groupwise_backend() -> str:
if get_fp8_gemm_runner_backend().is_flashinfer_cutlass():
@@ -1820,7 +1828,7 @@ def apply_fp8_linear_bmm_flashinfer(
input_scale: torch.Tensor,
bias: Optional[torch.Tensor] = None,
) -> torch.Tensor:
"""Per-tensor static fp8 linear via flashinfer bmm_fp8 (SM100/SM120 Blackwell)."""
"""Per-tensor static fp8 linear via flashinfer bmm_fp8 (SM90 and newer)."""
output_shape = [*input.shape[:-1], weight.shape[1]]
input_2d = input.view(-1, input.shape[-1])
qinput, x_scale = static_quant_fp8(input_2d, input_scale, repeat_scale=False)
@@ -42,6 +42,7 @@ from sglang.srt.layers.quantization.fp8_utils import (
apply_fp8_linear_bmm_flashinfer,
can_auto_enable_marlin_fp8,
cutlass_fp8_supported,
flashinfer_per_tensor_fp8_supported,
is_blackwell_supported,
)
from sglang.srt.layers.quantization.kv_cache import BaseKVCacheMethod
@@ -66,8 +67,6 @@ from sglang.srt.layers.utils import alias_or_bind_derived_param, copy_or_rebind_
from sglang.srt.utils.common import (
get_device_capability,
is_cuda,
is_flashinfer_available,
is_sm100_supported,
is_sm120_supported,
round_up,
set_weight_attrs,
@@ -505,9 +504,7 @@ class ModelOptFp8LinearMethod(LinearMethodBase):
super().__init__()
self.quant_config = quant_config
self.cutlass_fp8_supported = cutlass_fp8_supported()
self.enable_flashinfer_bmm = (
is_sm100_supported() or is_sm120_supported()
) and is_flashinfer_available()
self.enable_flashinfer_bmm = flashinfer_per_tensor_fp8_supported()
self.use_marlin = False
if is_cuda():
self.use_marlin = (
@@ -565,13 +562,20 @@ class ModelOptFp8LinearMethod(LinearMethodBase):
)
layer.register_parameter(scale_name, scale)
def _can_use_flashinfer_bmm(self, layer: torch.nn.Module) -> bool:
if not self.enable_flashinfer_bmm or layer.input_scale is None:
return False
k, n = layer.weight.shape
return k % 16 == 0 and n % 16 == 0
def process_weights_after_loading(self, layer: torch.nn.Module) -> None:
"""Requantizes weights after loading using the maximum scale."""
max_w_scale, quantized_weight = requantize_with_max_scale(
layer.weight, layer.weight_scale, layer.logical_widths
)
layer.weight = Parameter(quantized_weight.t(), requires_grad=False)
if self.cutlass_fp8_supported and not self.enable_flashinfer_bmm:
layer.use_flashinfer_bmm = self._can_use_flashinfer_bmm(layer)
if self.cutlass_fp8_supported and not layer.use_flashinfer_bmm:
max_w_scale = convert_to_channelwise(max_w_scale, layer.logical_widths)
layer.weight_scale = Parameter(max_w_scale, requires_grad=False)
layer.input_scale = Parameter(layer.input_scale.max(), requires_grad=False)
@@ -597,7 +601,7 @@ class ModelOptFp8LinearMethod(LinearMethodBase):
size_k=layer.input_size_per_partition,
bias=bias,
)
if self.enable_flashinfer_bmm and layer.input_scale is not None:
if layer.use_flashinfer_bmm:
return apply_fp8_linear_bmm_flashinfer(
input=x,
weight=layer.weight,