add flashinfer cute-dsl backend for mxfp8 gemm (#34042)
Co-authored-by: Brayden Zhong <brayden@radixark.ai>
This commit is contained in:
co-authored by
Brayden Zhong
parent
40eaf34428
commit
6a5a9eccaa
@@ -773,7 +773,7 @@ class Fp8LinearMethod(LinearMethodBase):
|
||||
.reshape_as(scale_u8)
|
||||
.contiguous(),
|
||||
)
|
||||
elif backend.is_flashinfer_cutlass():
|
||||
elif backend.is_flashinfer_cutlass() or backend.is_flashinfer_cutedsl():
|
||||
from flashinfer import block_scale_interleave
|
||||
|
||||
scale_u8 = layer.weight_scale_inv.data
|
||||
@@ -974,7 +974,7 @@ class Fp8LinearMethod(LinearMethodBase):
|
||||
if self.use_mxfp8:
|
||||
backend = self.mxfp8_dense_backend
|
||||
extra_kwargs = {}
|
||||
if backend.is_flashinfer_cutlass():
|
||||
if backend.is_flashinfer_cutlass() or backend.is_flashinfer_cutedsl():
|
||||
weight_scale = layer.weight_scale_inv_swizzled
|
||||
elif backend.is_flashinfer_trtllm():
|
||||
weight_scale = layer.weight_scale_inv_shuffled
|
||||
|
||||
@@ -38,6 +38,7 @@ from sglang.srt.utils import (
|
||||
get_bool_env_var,
|
||||
get_cuda_version,
|
||||
get_device_capability,
|
||||
get_device_sm,
|
||||
get_hip_version,
|
||||
is_blackwell_supported,
|
||||
is_cuda,
|
||||
@@ -276,6 +277,7 @@ class Fp8GemmRunnerBackend(Enum):
|
||||
AUTO = "auto"
|
||||
FLASHINFER_TRTLLM = "flashinfer_trtllm"
|
||||
FLASHINFER_CUTLASS = "flashinfer_cutlass"
|
||||
FLASHINFER_CUTEDSL = "flashinfer_cutedsl"
|
||||
FLASHINFER_DEEPGEMM = "flashinfer_deepgemm"
|
||||
CUTLASS = "cutlass"
|
||||
DEEP_GEMM = "deep_gemm"
|
||||
@@ -291,6 +293,9 @@ class Fp8GemmRunnerBackend(Enum):
|
||||
def is_flashinfer_cutlass(self) -> bool:
|
||||
return self == Fp8GemmRunnerBackend.FLASHINFER_CUTLASS
|
||||
|
||||
def is_flashinfer_cutedsl(self) -> bool:
|
||||
return self == Fp8GemmRunnerBackend.FLASHINFER_CUTEDSL
|
||||
|
||||
def is_flashinfer_deepgemm(self) -> bool:
|
||||
return self == Fp8GemmRunnerBackend.FLASHINFER_DEEPGEMM
|
||||
|
||||
@@ -312,6 +317,7 @@ class Mxfp8DenseGemmBackend(Enum):
|
||||
`Fp8GemmRunnerBackend`."""
|
||||
|
||||
FLASHINFER_CUTLASS = "flashinfer_cutlass"
|
||||
FLASHINFER_CUTEDSL = "flashinfer_cutedsl"
|
||||
FLASHINFER_TRTLLM = "flashinfer_trtllm"
|
||||
DEEP_GEMM = "deep_gemm"
|
||||
GFX95_DOT_SCALED = "gfx95_dot_scaled"
|
||||
@@ -320,9 +326,15 @@ class Mxfp8DenseGemmBackend(Enum):
|
||||
def is_flashinfer_cutlass(self) -> bool:
|
||||
return self == Mxfp8DenseGemmBackend.FLASHINFER_CUTLASS
|
||||
|
||||
def is_flashinfer_cutedsl(self) -> bool:
|
||||
return self == Mxfp8DenseGemmBackend.FLASHINFER_CUTEDSL
|
||||
|
||||
def is_flashinfer_trtllm(self) -> bool:
|
||||
return self == Mxfp8DenseGemmBackend.FLASHINFER_TRTLLM
|
||||
|
||||
def is_flashinfer(self) -> bool:
|
||||
return self.value.startswith("flashinfer_")
|
||||
|
||||
def is_deep_gemm(self) -> bool:
|
||||
return self == Mxfp8DenseGemmBackend.DEEP_GEMM
|
||||
|
||||
@@ -533,6 +545,28 @@ def resolve_mxfp8_dense_gemm_backend() -> Mxfp8DenseGemmBackend:
|
||||
)
|
||||
return Mxfp8DenseGemmBackend.FLASHINFER_TRTLLM
|
||||
|
||||
if backend.is_flashinfer_cutedsl():
|
||||
if not (
|
||||
is_blackwell_supported()
|
||||
and is_flashinfer_available()
|
||||
and _raw_flashinfer_mm_mxfp8.is_backend_supported(
|
||||
"cute-dsl", get_device_sm()
|
||||
)
|
||||
):
|
||||
raise RuntimeError(
|
||||
"MXFP8 dense GEMM requested via --fp8-gemm-backend=flashinfer_cutedsl, "
|
||||
"but that kernel requires an SM100/SM103 GPU and FlashInfer."
|
||||
)
|
||||
return Mxfp8DenseGemmBackend.FLASHINFER_CUTEDSL
|
||||
|
||||
if backend.is_flashinfer_cutlass():
|
||||
if not (is_blackwell_supported() and is_flashinfer_available()):
|
||||
raise RuntimeError(
|
||||
"MXFP8 dense GEMM requested via --fp8-gemm-backend=flashinfer_cutlass, "
|
||||
"but that kernel requires Blackwell GPUs and FlashInfer."
|
||||
)
|
||||
return Mxfp8DenseGemmBackend.FLASHINFER_CUTLASS
|
||||
|
||||
if backend.is_deep_gemm():
|
||||
if not deep_gemm_wrapper.ENABLE_JIT_DEEPGEMM:
|
||||
raise RuntimeError(
|
||||
@@ -546,6 +580,8 @@ def resolve_mxfp8_dense_gemm_backend() -> Mxfp8DenseGemmBackend:
|
||||
return Mxfp8DenseGemmBackend.GFX95_DOT_SCALED
|
||||
|
||||
if is_blackwell_supported() and is_flashinfer_available():
|
||||
if _raw_flashinfer_mm_mxfp8.is_backend_supported("cute-dsl", get_device_sm()):
|
||||
return Mxfp8DenseGemmBackend.FLASHINFER_CUTEDSL
|
||||
return Mxfp8DenseGemmBackend.FLASHINFER_CUTLASS
|
||||
|
||||
if deep_gemm_wrapper.ENABLE_JIT_DEEPGEMM:
|
||||
@@ -570,6 +606,8 @@ def dispatch_w8a8_mxfp8_linear() -> Callable:
|
||||
return partial(flashinfer_mxfp8_blockscaled_linear, backend="trtllm")
|
||||
elif backend.is_flashinfer_cutlass():
|
||||
return partial(flashinfer_mxfp8_blockscaled_linear, backend="cutlass")
|
||||
elif backend.is_flashinfer_cutedsl():
|
||||
return partial(flashinfer_mxfp8_blockscaled_linear, backend="cute-dsl")
|
||||
elif backend.is_unsupported():
|
||||
return _unsupported_mxfp8_linear
|
||||
|
||||
@@ -729,14 +767,6 @@ def initialize_fp8_gemm_config(server_args: ServerArgs) -> None:
|
||||
|
||||
backend = Fp8GemmRunnerBackend(backend)
|
||||
|
||||
if (
|
||||
backend.is_auto()
|
||||
and server_args.quantization == "mxfp8"
|
||||
and _is_sm100_supported
|
||||
and is_flashinfer_available()
|
||||
):
|
||||
backend = Fp8GemmRunnerBackend.FLASHINFER_CUTLASS
|
||||
|
||||
FP8_GEMM_RUNNER_BACKEND = backend
|
||||
|
||||
|
||||
@@ -1247,13 +1277,6 @@ def flashinfer_mxfp8_blockscaled_linear(
|
||||
else:
|
||||
output_dtype = torch.bfloat16
|
||||
|
||||
# At small M the persistent CUTLASS kernel is 2-5x slower than the
|
||||
# CuTe-DSL swap-AB/split-K kernels (both consume the same swizzled
|
||||
# 1D scales).
|
||||
# CuTe-DSL has no mm_mxfp8 kernel on SM120, so the swap is SM100-only there.
|
||||
if backend == "cutlass" and q_input.shape[0] <= 64 and _is_sm100_supported:
|
||||
backend = "cute-dsl"
|
||||
|
||||
if backend == "trtllm":
|
||||
weight_scale_t = weight_scale.view(-1)
|
||||
else:
|
||||
|
||||
@@ -99,21 +99,16 @@ def should_run_flashinfer_autotune(
|
||||
)
|
||||
|
||||
from sglang.srt.layers.quantization.fp8_utils import (
|
||||
get_fp8_gemm_runner_backend,
|
||||
flashinfer_per_tensor_fp8_supported,
|
||||
resolve_mxfp8_dense_gemm_backend,
|
||||
)
|
||||
from sglang.srt.utils import is_sm100_supported, is_sm120_supported
|
||||
|
||||
model_uses_modelopt_fp8 = model_quantization in (
|
||||
"modelopt",
|
||||
"modelopt_fp8",
|
||||
"modelopt_mixed",
|
||||
)
|
||||
# SM120 satisfies is_blackwell_supported(), so resolve_mxfp8_dense_gemm_backend
|
||||
# sends it to the same tunable FlashInfer CUTLASS MXFP8 dense GEMM as SM100;
|
||||
# without this the kernel always runs at tactic=-1.
|
||||
fp8_gemm_needs_autotune = get_fp8_gemm_runner_backend().is_flashinfer_cutlass() or (
|
||||
model_uses_modelopt_fp8 and (is_sm100_supported() or is_sm120_supported())
|
||||
)
|
||||
if model_quantization == "mxfp8":
|
||||
fp8_gemm_needs_autotune = resolve_mxfp8_dense_gemm_backend().is_flashinfer()
|
||||
elif model_quantization in ("modelopt", "modelopt_fp8", "modelopt_mixed"):
|
||||
fp8_gemm_needs_autotune = flashinfer_per_tensor_fp8_supported()
|
||||
else:
|
||||
fp8_gemm_needs_autotune = False
|
||||
|
||||
if not (moe_needs_autotune or fp4_gemm_needs_autotune or fp8_gemm_needs_autotune):
|
||||
return False
|
||||
|
||||
@@ -295,6 +295,7 @@ FP8_GEMM_RUNNER_BACKEND_CHOICES = [
|
||||
"flashinfer_trtllm",
|
||||
"flashinfer_cutlass",
|
||||
"flashinfer_deepgemm",
|
||||
"flashinfer_cutedsl",
|
||||
"cutlass",
|
||||
"triton",
|
||||
"aiter",
|
||||
@@ -1734,7 +1735,7 @@ class ServerArgs:
|
||||
fp8_gemm_runner_backend: A[
|
||||
str,
|
||||
Arg(
|
||||
help="Choose the runner backend for Blockwise FP8 GEMM operations. Options: 'auto' (default, auto-selects based on hardware), 'deep_gemm' (JIT-compiled; enabled by default on NVIDIA Hopper (SM90) and Blackwell (SM100) when DeepGEMM is installed), 'flashinfer_trtllm' (optimal for Blackwell and low-latency), 'flashinfer_cutlass' (FlashInfer CUTLASS groupwise FP8 GEMM), 'flashinfer_deepgemm' (Hopper SM90 only; uses swapAB optimization for small M dimensions in decoding), 'cutlass' (optimal for SM120 GPUs), 'triton' (fallback, widely compatible), 'aiter' (ROCm only). ",
|
||||
help="Choose the runner backend for Blockwise FP8 GEMM operations. Options: 'auto' (default, auto-selects based on hardware; MXFP8 dense picks flashinfer_cutedsl on SM100/SM103 and FlashInfer CUTLASS on other supported Blackwell GPUs), 'deep_gemm' (JIT-compiled; enabled by default on NVIDIA Hopper (SM90) and Blackwell (SM100) when DeepGEMM is installed), 'flashinfer_trtllm' (optimal for Blackwell and low-latency), 'flashinfer_cutlass' (FlashInfer CUTLASS groupwise FP8 GEMM), 'flashinfer_cutedsl' (FlashInfer CuTe DSL MXFP8 GEMM on SM100/SM103), 'flashinfer_deepgemm' (Hopper SM90 only; uses swapAB optimization for small M dimensions in decoding), 'cutlass' (optimal for SM120 GPUs), 'triton' (fallback, widely compatible), 'aiter' (ROCm only). ",
|
||||
cli_name="--fp8-gemm-backend",
|
||||
choices=FP8_GEMM_RUNNER_BACKEND_CHOICES,
|
||||
resolvable=True,
|
||||
|
||||
Reference in New Issue
Block a user