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 11, 03:45 UTC
[MoE Refactor][4/N] Marlin Fp8 Mk (#31036)
Robert Shaw committed
Dec 21, 2025 at 12:37 UTC
b471092d3a983485243dd153777d026bf5f49183
4 files changed
+85
-63
tests/quantization/test_fp8.py
+4
@@ -15,6 +15,7 @@ from vllm.model_executor.layers.quantization.fp8 import (
15
Fp8Config,
16
Fp8KVCacheMethod,
17
Fp8LinearMethod,
18
+ Fp8MoeBackend,
19
Fp8MoEMethod,
20
)
21
from vllm.model_executor.model_loader.weight_utils import default_weight_loader
@@ -324,7 +325,10 @@ def test_fp8_reloading(
325
weight_loader=default_weight_loader,
326
)
327
328
+ # Fp8LinearMethod uses use_marlin
329
+ # Fp8MoEMethod uses fp8_backend
330
method.use_marlin = use_marlin
331
+ method.fp8_backend = Fp8MoeBackend.MARLIN if use_marlin else None
332
333
# capture weights format during loading
334
original_metadata = [
vllm/model_executor/layers/fused_moe/config.py
+30
-2
@@ -19,6 +19,7 @@ from vllm.model_executor.layers.quantization.utils.ocp_mx_utils import (
19
OCP_MX_Scheme,
20
)
21
from vllm.model_executor.layers.quantization.utils.quant_utils import GroupShape
22
+from vllm.platforms import current_platform
23
from vllm.utils.flashinfer import has_flashinfer_cutlass_fused_moe
24
from vllm.utils.import_utils import has_triton_kernels
25
from vllm.utils.math_utils import cdiv
@@ -39,6 +40,7 @@ if has_triton_kernels():
40
def _get_config_dtype_str(
41
dtype: torch.dtype,
42
use_fp8_w8a8: bool = False,
43
+ use_fp8_w8a16: bool = False,
44
use_int8_w8a16: bool = False,
45
use_int4_w4a16: bool = False,
46
ocp_mx_scheme: str | None = None,
@@ -50,6 +52,8 @@ def _get_config_dtype_str(
52
"""
53
if use_fp8_w8a8:
54
return "fp8_w8a8"
55
+ elif use_fp8_w8a16:
56
+ return "fp8_w8a16"
57
elif use_int8_w8a16:
58
return "int8_w8a16"
59
elif use_int4_w4a16:
@@ -319,6 +323,10 @@ class FusedMoEQuantConfig:
323
def use_int8_w8a16(self) -> bool:
324
return self._a1.dtype is None and self._w1.dtype == torch.int8
325
326
+ @property
327
+ def use_fp8_w8a16(self) -> bool:
328
+ return self._a1.dtype is None and self._w1.dtype == current_platform.fp8_dtype()
329
+
330
@property
331
def use_int4_w4a16(self) -> bool:
332
return self._a1.dtype is None and self._w1.dtype == "int4"
@@ -362,6 +370,7 @@ class FusedMoEQuantConfig:
370
"""
371
return _get_config_dtype_str(
372
use_fp8_w8a8=self.use_fp8_w8a8,
373
+ use_fp8_w8a16=self.use_fp8_w8a16,
374
use_int8_w8a16=self.use_int8_w8a16,
375
use_int4_w4a16=self.use_int4_w4a16,
376
ocp_mx_scheme=self.ocp_mx_scheme,
@@ -680,7 +689,6 @@ def int4_w4a16_moe_quant_config(
689
) -> FusedMoEQuantConfig:
690
"""
691
Construct a quant config for 16-bit float activations and int4 weights.
683
- Note: Activations are pre-quantized.
692
"""
693
group_shape = GroupShape(*block_shape) if block_shape is not None else None
694
return FusedMoEQuantConfig(
@@ -691,6 +699,27 @@ def int4_w4a16_moe_quant_config(
699
)
700
701
702
+def fp8_w8a16_moe_quant_config(
703
+ w1_scale: torch.Tensor,
704
+ w2_scale: torch.Tensor,
705
+ block_shape: list[int] | None = None,
706
+) -> FusedMoEQuantConfig:
707
+ """
708
+ Construct a quant config for 16-bit float activations and fp8 weights.
709
+ """
710
+ group_shape = GroupShape(*block_shape) if block_shape is not None else None
711
+ return FusedMoEQuantConfig(
712
+ _a1=FusedMoEQuantDesc(),
713
+ _a2=FusedMoEQuantDesc(),
714
+ _w1=FusedMoEQuantDesc(
715
+ current_platform.fp8_dtype(), group_shape, w1_scale, None, None
716
+ ),
717
+ _w2=FusedMoEQuantDesc(
718
+ current_platform.fp8_dtype(), group_shape, w2_scale, None, None
719
+ ),
720
+ )
721
+
722
+
723
def int8_w8a16_moe_quant_config(
724
w1_scale: torch.Tensor,
725
w2_scale: torch.Tensor,
@@ -700,7 +729,6 @@ def int8_w8a16_moe_quant_config(
729
) -> FusedMoEQuantConfig:
730
"""
731
Construct a quant config for 16-bit float activations and int8 weights.
703
- Note: Activations are pre-quantized.
732
"""
733
group_shape = GroupShape(*block_shape) if block_shape is not None else None
734
return FusedMoEQuantConfig(
vllm/model_executor/layers/fused_moe/fused_marlin_moe.py
+17
-21
@@ -13,9 +13,6 @@ from vllm.model_executor.layers.fused_moe.moe_align_block_size import (
13
batched_moe_align_block_size,
14
moe_align_block_size,
15
)
16
-from vllm.model_executor.layers.fused_moe.prepare_finalize import (
17
- MoEPrepareAndFinalizeNoEP,
18
-)
16
from vllm.model_executor.layers.fused_moe.topk_weight_and_reduce import (
17
TopKWeightAndReduceDelegate,
18
TopKWeightAndReduceNoOP,
@@ -26,6 +23,7 @@ from vllm.model_executor.layers.quantization.utils.marlin_utils import (
23
marlin_moe_intermediate_size,
24
marlin_quant_input,
25
)
26
+from vllm.platforms import current_platform
27
from vllm.scalar_type import ScalarType, scalar_types
28
29
@@ -542,9 +540,11 @@ class MarlinExpertsBase(mk.FusedMoEPermuteExpertsUnpermute):
540
is_k_full: bool = True,
541
):
542
# TODO (varun) : Enable activation quantization
545
- assert quant_config.use_mxfp4_w4a16 or quant_config.use_int4_w4a16, (
546
- "Supports only mxfp4_w4a16 or int4_w4a16"
547
- )
543
+ assert (
544
+ quant_config.use_mxfp4_w4a16
545
+ or quant_config.use_int4_w4a16
546
+ or quant_config.use_fp8_w8a16
547
+ ), "Supports only mxfp4_w4a16, int4_w4a16 or fp8_w8a16"
548
self.w13_g_idx = w13_g_idx
549
self.w2_g_idx = w2_g_idx
550
self.w13_g_idx_sort_indices = w13_g_idx_sort_indices
@@ -555,11 +555,17 @@ class MarlinExpertsBase(mk.FusedMoEPermuteExpertsUnpermute):
555
@property
556
def quant_type_id(self) -> int:
557
# uint4b8 will be set for int4 weight and float4_e2m1f will be used for mxfp4
558
- return (
559
- scalar_types.uint4b8.id
560
- if self.quant_config.use_int4_w4a16
561
- else scalar_types.float4_e2m1f.id
562
- )
558
+ if self.quant_config.use_int4_w4a16:
559
+ return scalar_types.uint4b8.id
560
+ elif self.quant_config.use_mxfp4_w4a16:
561
+ return scalar_types.float4_e2m1f.id
562
+ elif (
563
+ self.quant_config.use_fp8_w8a16
564
+ and current_platform.fp8_dtype() == torch.float8_e4m3fn
565
+ ):
566
+ return scalar_types.float8_e4m3fn.id
567
+ else:
568
+ raise NotImplementedError("Unsupported quantization type.")
569
570
def moe_problem_size(
571
self,
@@ -711,16 +717,6 @@ class MarlinExperts(MarlinExpertsBase):
717
ops.moe_sum(input, output)
718
719
714
-def modular_marlin_fused_moe(
715
- quant_config: FusedMoEQuantConfig, shared_experts: torch.nn.Module | None = None
716
-) -> mk.FusedMoEModularKernel:
717
- return mk.FusedMoEModularKernel(
718
- MoEPrepareAndFinalizeNoEP(),
719
- MarlinExperts(quant_config),
720
- shared_experts,
721
- )
722
-
723
-
720
class BatchedMarlinExperts(MarlinExpertsBase):
721
def __init__(
722
self,
vllm/model_executor/layers/quantization/fp8.py
+34
-40
@@ -32,8 +32,8 @@ from vllm.model_executor.layers.fused_moe.config import (
32
FusedMoEQuantConfig,
33
RoutingMethodType,
34
fp8_w8a8_moe_quant_config,
35
+ fp8_w8a16_moe_quant_config,
36
)
36
-from vllm.model_executor.layers.fused_moe.fused_marlin_moe import fused_marlin_moe
37
from vllm.model_executor.layers.fused_moe.layer import UnquantizedFusedMoEMethod
38
from vllm.model_executor.layers.linear import (
39
LinearBase,
@@ -95,7 +95,6 @@ from vllm.model_executor.parameter import (
95
)
96
from vllm.model_executor.utils import replace_parameter, set_weight_attrs
97
from vllm.platforms import current_platform
98
-from vllm.scalar_type import scalar_types
98
from vllm.utils.deep_gemm import (
99
is_deep_gemm_e8m0_used,
100
is_deep_gemm_supported,
@@ -729,7 +728,6 @@ class Fp8MoEMethod(FusedMoEMethodBase):
728
)
729
730
self.marlin_input_dtype = None
732
- self.use_marlin = self.fp8_backend == Fp8MoeBackend.MARLIN
731
self.flashinfer_moe_backend: FlashinferMoeBackend | None = None
732
if self.fp8_backend == Fp8MoeBackend.FLASHINFER_TRTLLM:
733
self.flashinfer_moe_backend = FlashinferMoeBackend.TENSORRT_LLM
@@ -1048,7 +1046,7 @@ class Fp8MoEMethod(FusedMoEMethodBase):
1046
rotate_flashinfer_fp8_moe_weights(w13_weight, w2_weight)
1047
layer.w13_weight.data = w13_weight.data
1048
1051
- if self.use_marlin:
1049
+ if self.fp8_backend == Fp8MoeBackend.MARLIN:
1050
prepare_moe_fp8_layer_for_marlin(
1051
layer, False, input_dtype=self.marlin_input_dtype
1052
)
@@ -1091,10 +1089,17 @@ class Fp8MoEMethod(FusedMoEMethodBase):
1089
)
1090
self.use_inplace = False
1091
1094
- elif self.fp8_backend in [Fp8MoeBackend.DEEPGEMM, Fp8MoeBackend.TRITON]:
1092
+ elif self.fp8_backend in [
1093
+ Fp8MoeBackend.DEEPGEMM,
1094
+ Fp8MoeBackend.TRITON,
1095
+ Fp8MoeBackend.MARLIN,
1096
+ ]:
1097
from vllm.model_executor.layers.fused_moe import (
1098
TritonOrDeepGemmExperts,
1099
)
1100
+ from vllm.model_executor.layers.fused_moe.fused_marlin_moe import (
1101
+ MarlinExperts,
1102
+ )
1103
from vllm.model_executor.layers.fused_moe.prepare_finalize import (
1104
MoEPrepareAndFinalizeNoEP,
1105
)
@@ -1102,12 +1107,19 @@ class Fp8MoEMethod(FusedMoEMethodBase):
1107
config = self.get_fused_moe_quant_config(layer)
1108
assert config is not None
1109
self.moe_quant_config = config
1105
- self.kernel = mk.FusedMoEModularKernel(
1106
- MoEPrepareAndFinalizeNoEP(),
1107
- TritonOrDeepGemmExperts(
1110
+ use_marlin = self.fp8_backend == Fp8MoeBackend.MARLIN
1111
+ allow_deep_gemm = self.fp8_backend == Fp8MoeBackend.DEEPGEMM
1112
+ moe_kernel = (
1113
+ MarlinExperts(quant_config=self.moe_quant_config)
1114
+ if use_marlin
1115
+ else TritonOrDeepGemmExperts(
1116
quant_config=self.moe_quant_config,
1109
- allow_deep_gemm=(self.fp8_backend == Fp8MoeBackend.DEEPGEMM),
1110
- ),
1117
+ allow_deep_gemm=allow_deep_gemm,
1118
+ )
1119
+ )
1120
+
1121
+ self.kernel = mk.FusedMoEModularKernel(
1122
+ MoEPrepareAndFinalizeNoEP(), moe_kernel
1123
)
1124
self.use_inplace = True
1125
@@ -1116,9 +1128,8 @@ class Fp8MoEMethod(FusedMoEMethodBase):
1128
routing_tables: tuple[torch.Tensor, torch.Tensor, torch.Tensor] | None = None,
1129
) -> mk.FusedMoEPrepareAndFinalize | None:
1130
if (
1119
- current_platform.is_xpu()
1120
- or self.rocm_aiter_moe_enabled
1121
- or self.use_marlin
1131
+ self.rocm_aiter_moe_enabled
1132
+ or self.fp8_backend == Fp8MoeBackend.MARLIN
1133
or self.flashinfer_moe_backend == FlashinferMoeBackend.TENSORRT_LLM
1134
):
1135
return None
@@ -1150,7 +1161,9 @@ class Fp8MoEMethod(FusedMoEMethodBase):
1161
TritonOrDeepGemmExperts,
1162
)
1163
1153
- assert not self.use_marlin and not self.rocm_aiter_moe_enabled, (
1164
+ assert (
1165
+ self.fp8_backend != Fp8MoeBackend.MARLIN
1166
+ ) and not self.rocm_aiter_moe_enabled, (
1167
"Marlin and ROCm AITER are not supported with all2all yet."
1168
)
1169
@@ -1207,8 +1220,12 @@ class Fp8MoEMethod(FusedMoEMethodBase):
1220
def get_fused_moe_quant_config(
1221
self, layer: torch.nn.Module
1222
) -> FusedMoEQuantConfig | None:
1210
- if self.use_marlin:
1211
- return None
1223
+ if self.fp8_backend == Fp8MoeBackend.MARLIN:
1224
+ return fp8_w8a16_moe_quant_config(
1225
+ w1_scale=layer.w13_weight_scale,
1226
+ w2_scale=layer.w2_weight_scale,
1227
+ block_shape=self.weight_block_size,
1228
+ )
1229
1230
return fp8_w8a8_moe_quant_config(
1231
w1_scale=(
@@ -1314,29 +1331,6 @@ class Fp8MoEMethod(FusedMoEMethodBase):
1331
expert_map=layer.expert_map,
1332
quant_config=self.moe_quant_config,
1333
)
1317
- elif self.use_marlin:
1318
- # TODO(rob): convert this to MK.
1319
- assert layer.activation == "silu", (
1320
- f"{layer.activation} not supported for Marlin MoE."
1321
- )
1322
- result = fused_marlin_moe(
1323
- x,
1324
- layer.w13_weight,
1325
- layer.w2_weight,
1326
- None,
1327
- None,
1328
- layer.w13_weight_scale,
1329
- layer.w2_weight_scale,
1330
- router_logits,
1331
- topk_weights,
1332
- topk_ids,
1333
- quant_type_id=scalar_types.float8_e4m3fn.id,
1334
- apply_router_weight_on_input=layer.apply_router_weight_on_input,
1335
- global_num_experts=layer.global_num_experts,
1336
- expert_map=layer.expert_map,
1337
- input_dtype=self.marlin_input_dtype,
1338
- workspace=layer.workspace,
1339
- )
1334
else:
1335
result = self.kernel(
1336
x,
@@ -1495,7 +1489,7 @@ class Fp8OnlineMoEMethod(Fp8MoEMethod):
1489
replace_parameter(layer, "w2_weight", shuffled_w2)
1490
1491
# Rushuffle weights for MARLIN if needed.
1498
- if self.use_marlin:
1492
+ if self.fp8_backend == Fp8MoeBackend.MARLIN:
1493
prepare_moe_fp8_layer_for_marlin(
1494
layer, False, input_dtype=self.marlin_input_dtype
1495
)