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 13, 20:45 UTC
[Kernels] Isolate modular kernel code from FusedMoEMethodBase subclasses. (#27123)
bnellnm committed
Nov 4, 2025 at 08:59 UTC
938772af03ce01590c7e92b0d3fd0a5bdc899d19
16 files changed
+271
-311
vllm/distributed/device_communicators/base_device_communicator.py
+2
-2
@@ -266,14 +266,14 @@ class DeviceCommunicatorBase:
266
module
267
for module in model.modules()
268
# TODO(bnell): Should use isinstance but can't. Maybe search for
269
- # presence of quant_method.init_prepare_finalize?
269
+ # presence of quant_method.maybe_init_modular_kernel?
270
if (
271
module.__class__.__name__ == "FusedMoE"
272
or module.__class__.__name__ == "SharedFusedMoE"
273
)
274
]
275
for module in moe_modules:
276
- module.quant_method.init_prepare_finalize(module)
276
+ module.maybe_init_modular_kernel()
277
278
def dispatch(
279
self,
vllm/model_executor/layers/fused_moe/layer.py
+199
-62
@@ -117,10 +117,8 @@ class FusedMoeWeightScaleSupported(Enum):
117
class FusedMoEMethodBase(QuantizeMethodBase):
118
def __init__(self, moe: FusedMoEConfig):
119
super().__init__()
120
- self.moe = moe
120
+ self.moe: FusedMoEConfig = moe
121
self.moe_quant_config: FusedMoEQuantConfig | None = None
122
- self.fused_experts: FusedMoEModularKernel | None = None
123
- self.topk_indices_dtype = None
122
123
@abstractmethod
124
def create_weights(
@@ -245,9 +243,9 @@ class FusedMoEMethodBase(QuantizeMethodBase):
243
else:
244
return None
245
248
- # Note: init_prepare_finalize should only be called by
249
- # prepare_communication_buffer_for_model.
250
- def init_prepare_finalize(self, layer: torch.nn.Module):
246
+ def maybe_init_modular_kernel(
247
+ self, layer: torch.nn.Module
248
+ ) -> FusedMoEModularKernel | None:
249
assert self.moe is not None
250
251
# We must get the quant config here so that the layer is
@@ -261,17 +259,14 @@ class FusedMoEMethodBase(QuantizeMethodBase):
259
logger.debug(
260
"%s for %s(%s)", prepare_finalize.__class__.__name__, self, id(self)
261
)
264
- assert self.topk_indices_dtype is None
265
- assert self.fused_experts is None, (
266
- f"Attempt to override experts for {id(self)}!"
267
- )
268
- self.topk_indices_dtype = prepare_finalize.topk_indices_dtype()
262
experts = self.select_gemm_impl(prepare_finalize, layer)
270
- self.fused_experts = FusedMoEModularKernel(
263
+ return FusedMoEModularKernel(
264
prepare_finalize,
265
experts,
266
layer.shared_experts,
267
)
268
+ else:
269
+ return None
270
271
def select_gemm_impl(
272
self,
@@ -292,8 +287,16 @@ class FusedMoEMethodBase(QuantizeMethodBase):
287
raise NotImplementedError
288
289
@property
295
- def using_modular_kernel(self) -> bool:
296
- return self.fused_experts is not None
290
+ def topk_indices_dtype(self) -> torch.dtype | None:
291
+ return None
292
+
293
+ @property
294
+ def supports_eplb(self) -> bool:
295
+ return False
296
+
297
+ @property
298
+ def allow_inplace(self) -> bool:
299
+ return False
300
301
@abstractmethod
302
def apply(
@@ -322,6 +325,138 @@ class FusedMoEMethodBase(QuantizeMethodBase):
325
raise NotImplementedError
326
327
328
+@CustomOp.register("modular_fused_moe")
329
+class FusedMoEModularMethod(FusedMoEMethodBase, CustomOp):
330
+ def __init__(
331
+ self,
332
+ old_quant_method: FusedMoEMethodBase,
333
+ fused_experts: FusedMoEModularKernel,
334
+ ):
335
+ super().__init__(old_quant_method.moe)
336
+ # Find better way to copy attributes? Should we even copy attributes?
337
+ # self.__dict__.update(old_quant_method.__dict__)
338
+ self.moe_quant_config = old_quant_method.moe_quant_config
339
+ self.fused_experts = fused_experts
340
+ self.disable_expert_map = getattr(
341
+ old_quant_method,
342
+ "disable_expert_map",
343
+ not fused_experts.supports_expert_map(),
344
+ )
345
+ self.old_quant_method = old_quant_method
346
+ logger.debug("Swapping out %s", self.old_quant_method.__class__.__name__)
347
+
348
+ @property
349
+ def topk_indices_dtype(self) -> torch.dtype | None:
350
+ return self.fused_experts.prepare_finalize.topk_indices_dtype()
351
+
352
+ @property
353
+ def supports_eplb(self) -> bool:
354
+ return self.old_quant_method.supports_eplb
355
+
356
+ @property
357
+ def allow_inplace(self) -> bool:
358
+ return self.old_quant_method.allow_inplace
359
+
360
+ def create_weights(
361
+ self,
362
+ layer: torch.nn.Module,
363
+ num_experts: int,
364
+ hidden_size: int,
365
+ intermediate_size_per_partition: int,
366
+ params_dtype: torch.dtype,
367
+ **extra_weight_attrs,
368
+ ):
369
+ raise NotImplementedError
370
+
371
+ def get_fused_moe_quant_config(
372
+ self, layer: torch.nn.Module
373
+ ) -> FusedMoEQuantConfig | None:
374
+ return self.moe_quant_config
375
+
376
+ def apply(
377
+ self,
378
+ layer: torch.nn.Module,
379
+ x: torch.Tensor,
380
+ router_logits: torch.Tensor,
381
+ top_k: int,
382
+ renormalize: bool,
383
+ use_grouped_topk: bool = False,
384
+ topk_group: int | None = None,
385
+ num_expert_group: int | None = None,
386
+ global_num_experts: int = -1,
387
+ expert_map: torch.Tensor | None = None,
388
+ custom_routing_function: Callable | None = None,
389
+ scoring_func: str = "softmax",
390
+ routed_scaling_factor: float = 1.0,
391
+ e_score_correction_bias: torch.Tensor | None = None,
392
+ apply_router_weight_on_input: bool = False,
393
+ activation: str = "silu",
394
+ enable_eplb: bool = False,
395
+ expert_load_view: torch.Tensor | None = None,
396
+ logical_to_physical_map: torch.Tensor | None = None,
397
+ logical_replica_count: torch.Tensor | None = None,
398
+ ) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
399
+ # Is getattr needed?
400
+ zero_expert_num = getattr(layer, "zero_expert_num", 0)
401
+ zero_expert_type = getattr(layer, "zero_expert_type", None)
402
+
403
+ if enable_eplb:
404
+ if self.supports_eplb:
405
+ assert expert_load_view is not None
406
+ assert logical_to_physical_map is not None
407
+ assert logical_replica_count is not None
408
+ assert isinstance(layer, FusedMoE)
409
+ else:
410
+ raise NotImplementedError(
411
+ "EPLB is not supported for "
412
+ f"{self.old_quant_method.__class__.__name__}."
413
+ )
414
+
415
+ topk_weights, topk_ids, zero_expert_result = FusedMoE.select_experts(
416
+ hidden_states=x,
417
+ router_logits=router_logits,
418
+ use_grouped_topk=use_grouped_topk,
419
+ top_k=top_k,
420
+ renormalize=renormalize,
421
+ topk_group=topk_group,
422
+ num_expert_group=num_expert_group,
423
+ custom_routing_function=custom_routing_function,
424
+ scoring_func=scoring_func,
425
+ routed_scaling_factor=routed_scaling_factor,
426
+ e_score_correction_bias=e_score_correction_bias,
427
+ indices_type=self.topk_indices_dtype,
428
+ enable_eplb=enable_eplb,
429
+ expert_map=expert_map,
430
+ expert_load_view=expert_load_view,
431
+ logical_to_physical_map=logical_to_physical_map,
432
+ logical_replica_count=logical_replica_count,
433
+ global_num_experts=global_num_experts,
434
+ zero_expert_num=zero_expert_num,
435
+ zero_expert_type=zero_expert_type,
436
+ )
437
+
438
+ result = self.fused_experts(
439
+ hidden_states=x,
440
+ w1=layer.w13_weight,
441
+ w2=layer.w2_weight,
442
+ topk_weights=topk_weights,
443
+ topk_ids=topk_ids,
444
+ inplace=self.allow_inplace,
445
+ activation=activation,
446
+ global_num_experts=global_num_experts,
447
+ apply_router_weight_on_input=apply_router_weight_on_input,
448
+ expert_map=None if self.disable_expert_map else expert_map,
449
+ )
450
+
451
+ if zero_expert_num != 0 and zero_expert_type is not None:
452
+ assert not isinstance(result, tuple), (
453
+ "Shared + zero experts are mutually exclusive not yet supported"
454
+ )
455
+ return result, zero_expert_result
456
+ else:
457
+ return result
458
+
459
+
460
@CustomOp.register("unquantized_fused_moe")
461
class UnquantizedFusedMoEMethod(FusedMoEMethodBase, CustomOp):
462
"""MoE method without quantization."""
@@ -378,6 +513,14 @@ class UnquantizedFusedMoEMethod(FusedMoEMethodBase, CustomOp):
513
)
514
self.flashinfer_cutlass_moe = None # type: ignore
515
516
+ @property
517
+ def supports_eplb(self) -> bool:
518
+ return True
519
+
520
+ @property
521
+ def allow_inplace(self) -> bool:
522
+ return True
523
+
524
def maybe_make_prepare_finalize(self) -> FusedMoEPrepareAndFinalize | None:
525
if self.rocm_aiter_moe_enabled:
526
return None
@@ -650,7 +793,6 @@ class UnquantizedFusedMoEMethod(FusedMoEMethodBase, CustomOp):
793
)
794
795
if self.rocm_aiter_moe_enabled:
653
- assert self.fused_experts is None
796
result = self.rocm_aiter_fused_experts(
797
hidden_states=x,
798
w1=layer.w13_weight,
@@ -671,21 +813,7 @@ class UnquantizedFusedMoEMethod(FusedMoEMethodBase, CustomOp):
813
activation=activation,
814
apply_router_weight_on_input=apply_router_weight_on_input,
815
)
674
- elif self.fused_experts is not None:
675
- result = self.fused_experts(
676
- hidden_states=x,
677
- w1=layer.w13_weight,
678
- w2=layer.w2_weight,
679
- topk_weights=topk_weights,
680
- topk_ids=topk_ids,
681
- inplace=True,
682
- activation=activation,
683
- apply_router_weight_on_input=apply_router_weight_on_input,
684
- global_num_experts=global_num_experts,
685
- expert_map=expert_map,
686
- )
816
else:
688
- assert fused_experts is not None
817
result = fused_experts(
818
hidden_states=x,
819
w1=layer.w13_weight,
@@ -1267,7 +1395,7 @@ class FusedMoE(CustomOp):
1395
"Only softmax scoring function is supported for non-grouped topk."
1396
)
1397
1270
- moe = FusedMoEConfig(
1398
+ self.moe_config: FusedMoEConfig = FusedMoEConfig(
1399
num_experts=self.global_num_experts,
1400
experts_per_token=top_k,
1401
hidden_dim=hidden_size,
@@ -1279,24 +1407,26 @@ class FusedMoE(CustomOp):
1407
is_act_and_mul=is_act_and_mul,
1408
is_lora_enabled=vllm_config.lora_config is not None,
1409
)
1282
- self.moe_config: FusedMoEConfig = moe
1410
+
1411
self.moe_quant_config: FusedMoEQuantConfig | None = None
1412
self.quant_config = quant_config
1413
1414
+ def _get_quant_method() -> FusedMoEMethodBase:
1415
+ """
1416
+ Helper method to ensure self.quant_method is never None and
1417
+ of the proper type.
1418
+ """
1419
+ quant_method = None
1420
+ if self.quant_config is not None:
1421
+ quant_method = self.quant_config.get_quant_method(self, prefix)
1422
+ if quant_method is None:
1423
+ quant_method = UnquantizedFusedMoEMethod(self.moe_config)
1424
+ assert isinstance(quant_method, FusedMoEMethodBase)
1425
+ return quant_method
1426
+
1427
# Note: get_quant_method will look at the layer's local_num_experts
1428
# for heuristic purposes, so it must be initialized first.
1288
- quant_method: QuantizeMethodBase | None = None
1289
- quant_method = (
1290
- UnquantizedFusedMoEMethod(moe)
1291
- if quant_config is None
1292
- else quant_config.get_quant_method(self, prefix)
1293
- )
1294
- if quant_method is None:
1295
- quant_method = UnquantizedFusedMoEMethod(moe)
1296
-
1297
- assert quant_method is not None
1298
- assert isinstance(quant_method, FusedMoEMethodBase)
1299
- self.quant_method = quant_method
1429
+ self.quant_method: FusedMoEMethodBase = _get_quant_method()
1430
1431
if not self.moe_config.is_act_and_mul:
1432
# Avoid circular import
@@ -1305,7 +1435,7 @@ class FusedMoE(CustomOp):
1435
)
1436
1437
if not isinstance(
1308
- quant_method, (UnquantizedFusedMoEMethod, ModelOptFp8MoEMethod)
1438
+ self.quant_method, (UnquantizedFusedMoEMethod, ModelOptFp8MoEMethod)
1439
):
1440
raise NotImplementedError(
1441
"is_act_and_mul=False is supported only for unquantized "
@@ -1316,20 +1446,18 @@ class FusedMoE(CustomOp):
1446
"is_act_and_mul=False is supported only for CUDA for now"
1447
)
1448
1319
- if self.enable_eplb:
1320
- from vllm.model_executor.layers.quantization.fp8 import Fp8MoEMethod
1321
-
1322
- if not isinstance(quant_method, (Fp8MoEMethod, UnquantizedFusedMoEMethod)):
1323
- # TODO: Add support for additional quantization methods.
1324
- # The implementation for other quantization methods does not
1325
- # contain essential differences, but the current quant API
1326
- # design causes duplicated work when extending to new
1327
- # quantization methods, so I'm leaving it for now.
1328
- # If you plan to add support for more quantization methods,
1329
- # please refer to the implementation in `Fp8MoEMethod`.
1330
- raise NotImplementedError(
1331
- "EPLB is only supported for FP8 quantization for now."
1332
- )
1449
+ if self.enable_eplb and not self.quant_method.supports_eplb:
1450
+ # TODO: Add support for additional quantization methods.
1451
+ # The implementation for other quantization methods does not
1452
+ # contain essential differences, but the current quant API
1453
+ # design causes duplicated work when extending to new
1454
+ # quantization methods, so I'm leaving it for now.
1455
+ # If you plan to add support for more quantization methods,
1456
+ # please refer to the implementation in `Fp8MoEMethod`.
1457
+ raise NotImplementedError(
1458
+ f"EPLB is not supported {self.quant_method.__class__.__name__}. "
1459
+ "EPLB is only supported for FP8 quantization for now."
1460
+ )
1461
1462
moe_quant_params = {
1463
"num_experts": self.local_num_experts,
@@ -1353,6 +1481,15 @@ class FusedMoE(CustomOp):
1481
self.batched_hidden_states: torch.Tensor | None = None
1482
self.batched_router_logits: torch.Tensor | None = None
1483
1484
+ # Note: maybe_init_modular_kernel should only be called by
1485
+ # prepare_communication_buffer_for_model.
1486
+ # This is called after all weight loading and post-processing, so it
1487
+ # should be safe to swap out the quant_method.
1488
+ def maybe_init_modular_kernel(self) -> None:
1489
+ mk = self.quant_method.maybe_init_modular_kernel(self)
1490
+ if mk is not None:
1491
+ self.quant_method = FusedMoEModularMethod(self.quant_method, mk)
1492
+
1493
@property
1494
def shared_experts(self) -> torch.nn.Module | None:
1495
return None
@@ -2167,7 +2304,7 @@ class FusedMoE(CustomOp):
2304
"""
2305
assert self.quant_method is not None
2306
return (
2170
- self.quant_method.fused_experts is not None
2307
+ isinstance(self.quant_method, FusedMoEModularMethod)
2308
and self.quant_method.fused_experts.output_is_reduced()
2309
)
2310
@@ -2403,7 +2540,7 @@ class FusedMoE(CustomOp):
2540
self.ensure_dp_chunking_init()
2541
2542
has_separate_shared_experts = (
2406
- not isinstance(self.quant_method.fused_experts, FusedMoEModularKernel)
2543
+ not isinstance(self.quant_method, FusedMoEModularMethod)
2544
and self.shared_experts is not None
2545
)
2546
@@ -2430,8 +2567,8 @@ class FusedMoE(CustomOp):
2567
hidden_states, router_logits, has_separate_shared_experts
2568
)
2569
2433
- do_naive_dispatch_combine: bool = (
2434
- self.dp_size > 1 and not self.quant_method.using_modular_kernel
2570
+ do_naive_dispatch_combine: bool = self.dp_size > 1 and not isinstance(
2571
+ self.quant_method, FusedMoEModularMethod
2572
)
2573
2574
# If there are shared experts but we are not using a modular kernel, the
vllm/model_executor/layers/fused_moe/modular_kernel.py
+6
@@ -707,6 +707,12 @@ class FusedMoEModularKernel(torch.nn.Module):
707
f"{fused_experts.activation_formats[0]}"
708
)
709
710
+ def supports_expert_map(self) -> bool:
711
+ """
712
+ A flag indicating whether or not this class supports expert maps.
713
+ """
714
+ return self.fused_experts.supports_expert_map()
715
+
716
def output_is_reduced(self) -> bool:
717
"""
718
Indicates whether or not the output of fused MoE kernel
vllm/model_executor/layers/quantization/awq_marlin.py
-2
@@ -617,8 +617,6 @@ class AWQMoEMethod(FusedMoEMethodBase):
617
logical_to_physical_map: torch.Tensor | None = None,
618
logical_replica_count: torch.Tensor | None = None,
619
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
620
- assert self.fused_experts is None
621
-
620
if enable_eplb:
621
raise NotImplementedError("EPLB not supported for `AWQMoEMethod` yet.")
622
vllm/model_executor/layers/quantization/bitsandbytes.py
+1
-2
@@ -518,12 +518,11 @@ class BitsAndBytesMoEMethod(FusedMoEMethodBase):
518
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
519
from vllm.model_executor.layers.fused_moe import fused_experts
520
521
- assert self.fused_experts is None
522
-
521
if enable_eplb:
522
raise NotImplementedError(
523
"EPLB not supported for `BitsAndBytesMoEMethod` yet."
524
)
525
+
526
topk_weights, topk_ids, _ = FusedMoE.select_experts(
527
hidden_states=x,
528
router_logits=router_logits,
vllm/model_executor/layers/quantization/compressed_tensors/compressed_tensors_moe.py
-47
@@ -462,12 +462,7 @@ class CompressedTensorsW4A4MoeMethod(CompressedTensorsMoEMethod):
462
indices_type=self.topk_indices_dtype,
463
)
464
465
- #
466
- # Note: the order here is important. self.fused_experts can override
467
- # flashinfer cutlass, cutlass fp4 or fused_experts but not marlin.
468
- #
465
if self.use_marlin:
470
- assert self.fused_experts is None
466
return fused_marlin_moe(
467
x,
468
layer.w13_weight,
@@ -488,24 +483,6 @@ class CompressedTensorsW4A4MoeMethod(CompressedTensorsMoEMethod):
483
workspace=layer.workspace,
484
)
485
491
- elif self.fused_experts is not None:
492
- assert is_valid_flashinfer_cutlass_fused_moe(
493
- x, layer.w13_weight, layer.w2_weight
494
- ), "Flashinfer CUTLASS Fused MoE not applicable!"
495
-
496
- return self.fused_experts(
497
- hidden_states=x,
498
- w1=layer.w13_weight,
499
- w2=layer.w2_weight,
500
- topk_weights=topk_weights,
501
- topk_ids=topk_ids,
502
- inplace=False, # TODO(shuw): fix later, now output is high prec
503
- activation=activation,
504
- global_num_experts=global_num_experts,
505
- expert_map=expert_map,
506
- apply_router_weight_on_input=apply_router_weight_on_input,
507
- )
508
-
486
# FlashInfer fused experts path
487
elif self.allow_flashinfer:
488
from vllm.model_executor.layers.fused_moe.flashinfer_cutlass_moe import ( # noqa: E501
@@ -1066,13 +1043,8 @@ class CompressedTensorsW8A8Fp8MoEMethod(CompressedTensorsMoEMethod):
1043
per_act_token = self.input_quant.strategy == QuantizationStrategy.TOKEN
1044
per_channel_quant = self.weight_quant.strategy == QuantizationStrategy.CHANNEL
1045
1069
- #
1070
- # Note: the order here is important. self.fused_experts can override
1071
- # cutlass fp8 or fused_experts but not marlin or rocm.
1072
- #
1046
if self.use_marlin:
1047
assert activation == "silu", f"{activation} not supported for Marlin MoE."
1075
- assert self.fused_experts is None
1048
return fused_marlin_moe(
1049
x,
1050
layer.w13_weight,
@@ -1098,7 +1070,6 @@ class CompressedTensorsW8A8Fp8MoEMethod(CompressedTensorsMoEMethod):
1070
1071
assert per_act_token == per_channel_quant
1072
assert self.moe_quant_config is not None
1101
- assert self.fused_experts is None
1073
return rocm_aiter_fused_experts(
1074
hidden_states=x,
1075
w1=layer.w13_weight,
@@ -1111,18 +1082,6 @@ class CompressedTensorsW8A8Fp8MoEMethod(CompressedTensorsMoEMethod):
1082
quant_config=self.moe_quant_config,
1083
)
1084
1114
- elif self.fused_experts is not None:
1115
- return self.fused_experts(
1116
- x,
1117
- layer.w13_weight,
1118
- layer.w2_weight,
1119
- topk_weights,
1120
- topk_ids,
1121
- activation=activation,
1122
- global_num_experts=global_num_experts,
1123
- expert_map=None if self.disable_expert_map else expert_map,
1124
- )
1125
-
1085
# cutlass path
1086
elif self.use_cutlass:
1087
assert self.moe_quant_config is not None
@@ -1318,8 +1277,6 @@ class CompressedTensorsW8A8Int8MoEMethod(CompressedTensorsMoEMethod):
1277
logical_to_physical_map: torch.Tensor | None = None,
1278
logical_replica_count: torch.Tensor | None = None,
1279
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
1321
- assert self.fused_experts is None
1322
-
1280
if enable_eplb:
1281
raise NotImplementedError(
1282
"EPLB not supported for `CompressedTensorsW8A8Int8MoEMethod` yet."
@@ -1636,8 +1593,6 @@ class CompressedTensorsWNA16MarlinMoEMethod(CompressedTensorsMoEMethod):
1593
logical_to_physical_map: torch.Tensor | None = None,
1594
logical_replica_count: torch.Tensor | None = None,
1595
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
1639
- assert self.fused_experts is None
1640
-
1596
if enable_eplb:
1597
raise NotImplementedError(
1598
"EPLB not supported for `CompressedTensorsWNA16MarlinMoEMethod` yet."
@@ -1901,8 +1856,6 @@ class CompressedTensorsWNA16MoEMethod(CompressedTensorsMoEMethod):
1856
logical_to_physical_map: torch.Tensor | None = None,
1857
logical_replica_count: torch.Tensor | None = None,
1858
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
1904
- assert self.fused_experts is None
1905
-
1859
if enable_eplb:
1860
raise NotImplementedError(
1861
"EPLB not supported for `CompressedTensorsWNA16MoEMethod` yet."
vllm/model_executor/layers/quantization/experts_int8.py
-2
@@ -158,8 +158,6 @@ class ExpertsInt8MoEMethod(FusedMoEMethodBase):
158
logical_to_physical_map: torch.Tensor | None = None,
159
logical_replica_count: torch.Tensor | None = None,
160
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
161
- assert self.fused_experts is None
162
-
161
if enable_eplb:
162
raise NotImplementedError(
163
"EPLB not supported for `ExpertsInt8MoEMethod` yet."
vllm/model_executor/layers/quantization/fp8.py
+9
-26
@@ -703,9 +703,6 @@ class Fp8MoEMethod(FusedMoEMethodBase):
703
self.quant_config = quant_config
704
self.weight_block_size = self.quant_config.weight_block_size
705
self.block_quant: bool = self.weight_block_size is not None
706
-
707
- self.fused_experts: mk.FusedMoEModularKernel | None = None # type: ignore
708
-
706
self.fp8_backend = get_fp8_moe_backend(self.block_quant)
707
708
self.use_marlin = self.fp8_backend == Fp8MoeBackend.MARLIN
@@ -1181,6 +1178,14 @@ class Fp8MoEMethod(FusedMoEMethodBase):
1178
block_shape=self.weight_block_size,
1179
)
1180
1181
+ @property
1182
+ def supports_eplb(self) -> bool:
1183
+ return True
1184
+
1185
+ @property
1186
+ def allow_inplace(self) -> bool:
1187
+ return True
1188
+
1189
def apply(
1190
self,
1191
layer: torch.nn.Module,
@@ -1210,10 +1215,7 @@ class Fp8MoEMethod(FusedMoEMethodBase):
1215
assert logical_replica_count is not None
1216
assert isinstance(layer, FusedMoE)
1217
1213
- if (
1214
- self.flashinfer_moe_backend == FlashinferMoeBackend.TENSORRT_LLM
1215
- and self.fused_experts is None
1216
- ):
1218
+ if self.flashinfer_moe_backend == FlashinferMoeBackend.TENSORRT_LLM:
1219
assert activation == "silu", (
1220
f"Expected 'silu' activation but got {activation}"
1221
)
@@ -1290,10 +1292,6 @@ class Fp8MoEMethod(FusedMoEMethodBase):
1292
num_fused_shared_experts=layer.num_fused_shared_experts,
1293
)
1294
1293
- #
1294
- # Note: the order of checks is important since self.fused_experts
1295
- # can override fused_experts or cutlass but not rocm or marlin.
1296
- #
1295
topk_weights, topk_ids, zero_expert_result = select_result
1296
1297
if self.rocm_aiter_moe_enabled:
@@ -1301,7 +1299,6 @@ class Fp8MoEMethod(FusedMoEMethodBase):
1299
rocm_aiter_fused_experts,
1300
)
1301
1304
- assert self.fused_experts is None
1302
result = rocm_aiter_fused_experts(
1303
x,
1304
layer.w13_weight,
@@ -1315,7 +1312,6 @@ class Fp8MoEMethod(FusedMoEMethodBase):
1312
)
1313
elif self.use_marlin:
1314
assert activation == "silu", f"{activation} not supported for Marlin MoE."
1318
- assert self.fused_experts is None
1315
result = fused_marlin_moe(
1316
x,
1317
layer.w13_weight,
@@ -1333,19 +1329,6 @@ class Fp8MoEMethod(FusedMoEMethodBase):
1329
expert_map=expert_map,
1330
workspace=layer.workspace,
1331
)
1336
- elif self.fused_experts:
1337
- result = self.fused_experts(
1338
- hidden_states=x,
1339
- w1=layer.w13_weight,
1340
- w2=layer.w2_weight,
1341
- topk_weights=topk_weights,
1342
- topk_ids=topk_ids,
1343
- inplace=True,
1344
- activation=activation,
1345
- global_num_experts=global_num_experts,
1346
- apply_router_weight_on_input=apply_router_weight_on_input,
1347
- expert_map=expert_map,
1348
- )
1332
elif self.flashinfer_moe_backend == FlashinferMoeBackend.CUTLASS:
1333
assert not self.block_quant
1334
assert not renormalize and custom_routing_function is not None
vllm/model_executor/layers/quantization/gguf.py
-2
@@ -585,8 +585,6 @@ class GGUFMoEMethod(FusedMoEMethodBase):
585
logical_to_physical_map: torch.Tensor | None = None,
586
logical_replica_count: torch.Tensor | None = None,
587
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
588
- assert self.fused_experts is None
589
-
588
if enable_eplb:
589
raise NotImplementedError("EPLB not supported for `GGUFMoEMethod` yet.")
590
vllm/model_executor/layers/quantization/gptq_marlin.py
-2
@@ -742,8 +742,6 @@ class GPTQMarlinMoEMethod(FusedMoEMethodBase):
742
logical_to_physical_map: torch.Tensor | None = None,
743
logical_replica_count: torch.Tensor | None = None,
744
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
745
- assert self.fused_experts is None
746
-
745
if enable_eplb:
746
raise NotImplementedError(
747
"EPLB not supported for `GPTQMarlinMoEMethod` yet."
vllm/model_executor/layers/quantization/modelopt.py
+11
-39
@@ -18,9 +18,6 @@ from vllm.model_executor.layers.fused_moe.config import (
18
fp8_w8a8_moe_quant_config,
19
nvfp4_moe_quant_config,
20
)
21
-from vllm.model_executor.layers.fused_moe.flashinfer_cutlass_moe import (
22
- is_valid_flashinfer_cutlass_fused_moe,
23
-)
21
from vllm.model_executor.layers.fused_moe.fused_marlin_moe import fused_marlin_moe
22
from vllm.model_executor.layers.fused_moe.layer import (
23
FusedMoE,
@@ -605,7 +602,6 @@ class ModelOptFp8MoEMethod(FusedMoEMethodBase):
602
)
603
604
if self.flashinfer_moe_backend == FlashinferMoeBackend.TENSORRT_LLM:
608
- assert self.fused_experts is None
605
assert activation == "silu", (
606
f"Expected 'silu' activation but got {activation}"
607
)
@@ -638,24 +634,7 @@ class ModelOptFp8MoEMethod(FusedMoEMethodBase):
634
indices_type=self.topk_indices_dtype,
635
)
636
641
- #
642
- # Note: the order here is important. self.fused_experts can override
643
- # cutlass or fused_experts.
644
- #
645
- if self.fused_experts is not None:
646
- return self.fused_experts(
647
- x,
648
- layer.w13_weight,
649
- layer.w2_weight,
650
- topk_weights,
651
- topk_ids,
652
- inplace=False,
653
- activation=activation,
654
- global_num_experts=global_num_experts,
655
- expert_map=expert_map,
656
- apply_router_weight_on_input=apply_router_weight_on_input,
657
- )
658
- elif self.flashinfer_moe_backend == FlashinferMoeBackend.CUTLASS:
637
+ if self.flashinfer_moe_backend == FlashinferMoeBackend.CUTLASS:
638
assert not renormalize
639
assert activation == "silu", (
640
f"Expected 'silu' activation but got {activation}"
@@ -1647,8 +1626,6 @@ class ModelOptNvFp4FusedMoE(FusedMoEMethodBase):
1626
1627
from vllm.model_executor.models.llama4 import Llama4MoE
1628
1650
- assert self.fused_experts is None
1651
-
1629
a1_gscale = layer.w13_input_scale_quant
1630
(hidden_states_fp4, hidden_states_scale_linear_fp4) = (
1631
flashinfer.fp4_quantize(
@@ -1720,13 +1697,7 @@ class ModelOptNvFp4FusedMoE(FusedMoEMethodBase):
1697
indices_type=self.topk_indices_dtype,
1698
)
1699
1723
- #
1724
- # Note: the order here is important. self.fused_experts can override
1725
- # flashinfer cutlass, cutlass fp4 or fused_experts but not marlin or
1726
- # trtllm.
1727
- #
1700
if self.use_marlin:
1729
- assert self.fused_experts is None
1701
return fused_marlin_moe(
1702
x,
1703
layer.w13_weight,
@@ -1747,23 +1718,24 @@ class ModelOptNvFp4FusedMoE(FusedMoEMethodBase):
1718
workspace=layer.workspace,
1719
)
1720
1750
- elif self.fused_experts is not None:
1751
- assert (
1752
- self.allow_flashinfer
1753
- and self.flashinfer_moe_backend == FlashinferMoeBackend.CUTLASS
1721
+ elif (
1722
+ self.allow_flashinfer
1723
+ and self.flashinfer_moe_backend == FlashinferMoeBackend.CUTLASS
1724
+ ):
1725
+ from vllm.model_executor.layers.fused_moe.flashinfer_cutlass_moe import ( # noqa: E501
1726
+ flashinfer_cutlass_moe_fp4,
1727
)
1728
1756
- assert is_valid_flashinfer_cutlass_fused_moe(
1757
- x, layer.w13_weight, layer.w2_weight
1758
- ), "Flashinfer CUTLASS Fused MoE not applicable!"
1729
+ assert self.moe_quant_config is not None
1730
1760
- return self.fused_experts(
1731
+ return flashinfer_cutlass_moe_fp4(
1732
hidden_states=x,
1733
w1=layer.w13_weight,
1734
w2=layer.w2_weight,
1735
topk_weights=topk_weights,
1736
topk_ids=topk_ids,
1766
- inplace=False, # TODO(shuw): fix later, now output is high prec
1737
+ quant_config=self.moe_quant_config,
1738
+ inplace=False,
1739
activation=activation,
1740
global_num_experts=global_num_experts,
1741
expert_map=expert_map,
vllm/model_executor/layers/quantization/moe_wna16.py
-2
@@ -226,7 +226,6 @@ class MoeWNA16Method(FusedMoEMethodBase):
226
params_dtype: torch.dtype,
227
**extra_weight_attrs,
228
):
229
- self.moe = layer
229
layer.quant_config = self.quant_config
230
bit8_pack_factor = self.quant_config.bit8_pack_factor
231
group_size = self.quant_config.group_size
@@ -381,7 +380,6 @@ class MoeWNA16Method(FusedMoEMethodBase):
380
logical_to_physical_map: torch.Tensor | None = None,
381
logical_replica_count: torch.Tensor | None = None,
382
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
384
- assert self.fused_experts is None
383
if enable_eplb:
384
raise NotImplementedError("EPLB not supported for `MoeWNA16Method` yet.")
385
vllm/model_executor/layers/quantization/mxfp4.py
+15
-90
@@ -197,8 +197,6 @@ class Mxfp4Config(QuantizationConfig):
197
class Mxfp4MoEMethod(FusedMoEMethodBase):
198
def __init__(self, moe: FusedMoEConfig):
199
super().__init__(moe)
200
- self.topk_indices_dtype = None
201
- self.moe = moe
200
self.mxfp4_backend = get_mxfp4_backend(moe.is_lora_enabled)
201
self.max_capture_size = (
202
get_current_vllm_config().compilation_config.max_cudagraph_capture_size
@@ -815,6 +813,18 @@ class Mxfp4MoEMethod(FusedMoEMethodBase):
813
"EP batched experts format"
814
)
815
else:
816
+ layer.w13_weight = (
817
+ self.w13_weight_triton_tensor
818
+ if layer.w13_weight is None
819
+ else layer.w13_weight
820
+ )
821
+ layer.w2_weight = (
822
+ self.w2_weight_triton_tensor
823
+ if layer.w2_weight is None
824
+ else layer.w2_weight
825
+ )
826
+ assert all([w is not None for w in [layer.w13_weight, layer.w2_weight]])
827
+
828
assert self.moe_quant_config is not None
829
if (
830
self.mxfp4_backend == Mxfp4Backend.SM100_FI_MXFP4_MXFP8_TRTLLM
@@ -838,71 +848,9 @@ class Mxfp4MoEMethod(FusedMoEMethodBase):
848
f"Incompatible Mxfp4 backend ({self.mxfp4_backend}) for EP"
849
)
850
841
- def _route_and_experts(
842
- self,
843
- layer: torch.nn.Module,
844
- x: torch.Tensor,
845
- router_logits: torch.Tensor,
846
- top_k: int,
847
- renormalize: bool,
848
- use_grouped_topk: bool = False,
849
- topk_group: int | None = None,
850
- num_expert_group: int | None = None,
851
- global_num_experts: int = -1,
852
- expert_map: torch.Tensor | None = None,
853
- custom_routing_function: Callable | None = None,
854
- scoring_func: str = "softmax",
855
- e_score_correction_bias: torch.Tensor | None = None,
856
- apply_router_weight_on_input: bool = False,
857
- activation: str = "silu",
858
- enable_eplb: bool = False,
859
- expert_load_view: torch.Tensor | None = None,
860
- logical_to_physical_map: torch.Tensor | None = None,
861
- logical_replica_count: torch.Tensor | None = None,
862
- ) -> torch.Tensor:
863
- assert isinstance(self.fused_experts, mk.FusedMoEModularKernel)
864
-
865
- topk_weights, topk_ids, _ = FusedMoE.select_experts(
866
- hidden_states=x,
867
- router_logits=router_logits,
868
- use_grouped_topk=use_grouped_topk,
869
- top_k=top_k,
870
- renormalize=renormalize,
871
- topk_group=topk_group,
872
- num_expert_group=num_expert_group,
873
- custom_routing_function=custom_routing_function,
874
- scoring_func=scoring_func,
875
- e_score_correction_bias=e_score_correction_bias,
876
- indices_type=self.topk_indices_dtype,
877
- enable_eplb=enable_eplb,
878
- expert_map=expert_map,
879
- expert_load_view=expert_load_view,
880
- logical_to_physical_map=logical_to_physical_map,
881
- logical_replica_count=logical_replica_count,
882
- )
883
-
884
- w13_weight = (
885
- self.w13_weight_triton_tensor
886
- if layer.w13_weight is None
887
- else layer.w13_weight
888
- )
889
- w2_weight = (
890
- self.w2_weight_triton_tensor if layer.w2_weight is None else layer.w2_weight
891
- )
892
- assert all([w is not None for w in [w13_weight, w2_weight]])
893
-
894
- return self.fused_experts(
895
- hidden_states=x,
896
- w1=w13_weight,
897
- w2=w2_weight,
898
- topk_weights=topk_weights,
899
- topk_ids=topk_ids,
900
- inplace=True,
901
- activation=activation,
902
- global_num_experts=global_num_experts,
903
- expert_map=expert_map,
904
- apply_router_weight_on_input=apply_router_weight_on_input,
905
- )
851
+ @property
852
+ def allow_inplace(self) -> bool:
853
+ return True
854
855
def apply(
856
self,
@@ -930,29 +878,6 @@ class Mxfp4MoEMethod(FusedMoEMethodBase):
878
if enable_eplb:
879
raise NotImplementedError("EPLB is not supported for mxfp4")
880
933
- if self.fused_experts is not None:
934
- return self._route_and_experts(
935
- layer,
936
- x,
937
- router_logits,
938
- top_k,
939
- renormalize,
940
- use_grouped_topk,
941
- topk_group,
942
- num_expert_group,
943
- global_num_experts,
944
- expert_map,
945
- custom_routing_function,
946
- scoring_func,
947
- e_score_correction_bias,
948
- apply_router_weight_on_input,
949
- activation,
950
- enable_eplb,
951
- expert_load_view,
952
- logical_to_physical_map,
953
- logical_replica_count,
954
- )
955
-
881
if self.mxfp4_backend == Mxfp4Backend.MARLIN:
882
topk_weights, topk_ids, _ = FusedMoE.select_experts(
883
hidden_states=x,
vllm/model_executor/layers/quantization/quark/quark_moe.py
+25
-28
@@ -310,7 +310,6 @@ class QuarkW8A8Fp8MoEMethod(QuarkMoEMethod):
310
# Property to determine if AITER is used
311
if self.rocm_aiter_moe_enabled:
312
from vllm.model_executor.layers.fused_moe.rocm_aiter_fused_moe import ( # noqa E501
313
- rocm_aiter_fused_experts,
313
shuffle_weights,
314
)
315
@@ -322,17 +321,11 @@ class QuarkW8A8Fp8MoEMethod(QuarkMoEMethod):
321
layer.w13_weight = torch.nn.Parameter(shuffled_w13, requires_grad=False)
322
layer.w2_weight = torch.nn.Parameter(shuffled_w2, requires_grad=False)
323
325
- self.rocm_aiter_fused_experts_func = rocm_aiter_fused_experts
324
elif self.use_marlin:
325
prepare_moe_fp8_layer_for_marlin(layer, False)
326
# Activations not quantized for marlin.
327
del layer.w13_input_scale
328
del layer.w2_input_scale
331
- self.fused_experts_func = None
332
- else:
333
- from vllm.model_executor.layers.fused_moe import fused_experts
334
-
335
- self.fused_experts_func = fused_experts
329
330
def get_fused_moe_quant_config(
331
self, layer: torch.nn.Module
@@ -369,8 +362,6 @@ class QuarkW8A8Fp8MoEMethod(QuarkMoEMethod):
362
logical_to_physical_map: torch.Tensor | None = None,
363
logical_replica_count: torch.Tensor | None = None,
364
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
372
- assert self.fused_experts is None
373
-
365
if enable_eplb:
366
raise NotImplementedError(
367
"EPLB not supported for `QuarkW8A8Fp8MoEMethod` yet."
@@ -392,7 +383,11 @@ class QuarkW8A8Fp8MoEMethod(QuarkMoEMethod):
383
)
384
385
if self.rocm_aiter_moe_enabled:
395
- return self.rocm_aiter_fused_experts_func(
386
+ from vllm.model_executor.layers.fused_moe.rocm_aiter_fused_moe import (
387
+ rocm_aiter_fused_experts,
388
+ )
389
+
390
+ return rocm_aiter_fused_experts(
391
hidden_states=x,
392
w1=layer.w13_weight,
393
w2=layer.w2_weight,
@@ -403,7 +398,7 @@ class QuarkW8A8Fp8MoEMethod(QuarkMoEMethod):
398
quant_config=self.moe_quant_config,
399
expert_map=expert_map,
400
)
406
- if self.use_marlin:
401
+ elif self.use_marlin:
402
assert activation == "silu", f"{activation} not supported for Marlin MoE."
403
return fused_marlin_moe(
404
x,
@@ -421,22 +416,22 @@ class QuarkW8A8Fp8MoEMethod(QuarkMoEMethod):
416
global_num_experts=global_num_experts,
417
expert_map=expert_map,
418
)
419
+ else:
420
+ from vllm.model_executor.layers.fused_moe import fused_experts
421
425
- assert self.fused_experts_func is not None
426
-
427
- return self.fused_experts_func(
428
- hidden_states=x,
429
- w1=layer.w13_weight,
430
- w2=layer.w2_weight,
431
- topk_weights=topk_weights,
432
- topk_ids=topk_ids,
433
- inplace=True,
434
- activation=activation,
435
- apply_router_weight_on_input=apply_router_weight_on_input,
436
- global_num_experts=global_num_experts,
437
- expert_map=expert_map,
438
- quant_config=self.moe_quant_config,
439
- )
422
+ return fused_experts(
423
+ hidden_states=x,
424
+ w1=layer.w13_weight,
425
+ w2=layer.w2_weight,
426
+ topk_weights=topk_weights,
427
+ topk_ids=topk_ids,
428
+ inplace=True,
429
+ activation=activation,
430
+ apply_router_weight_on_input=apply_router_weight_on_input,
431
+ global_num_experts=global_num_experts,
432
+ expert_map=expert_map,
433
+ quant_config=self.moe_quant_config,
434
+ )
435
436
437
class QuarkOCP_MX_MoEMethod(QuarkMoEMethod):
@@ -601,6 +596,10 @@ class QuarkOCP_MX_MoEMethod(QuarkMoEMethod):
596
block_shape=None,
597
)
598
599
+ @property
600
+ def allow_inplace(self) -> bool:
601
+ return True
602
+
603
def apply(
604
self,
605
layer: torch.nn.Module,
@@ -624,8 +623,6 @@ class QuarkOCP_MX_MoEMethod(QuarkMoEMethod):
623
logical_to_physical_map: torch.Tensor | None = None,
624
logical_replica_count: torch.Tensor | None = None,
625
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
627
- assert self.fused_experts is None
628
-
626
if enable_eplb:
627
raise NotImplementedError(
628
"EPLB not supported for `QuarkOCP_MX_MoEMethod` yet."
vllm/model_executor/layers/quantization/rtn.py
-2
@@ -377,8 +377,6 @@ class RTNMoEMethod(FusedMoEMethodBase):
377
logical_to_physical_map: torch.Tensor | None = None,
378
logical_replica_count: torch.Tensor | None = None,
379
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
380
- assert self.fused_experts is None
381
-
380
if enable_eplb:
381
raise NotImplementedError("EPLB not supported for `RTNMoEMethod` yet.")
382
vllm/model_executor/warmup/deep_gemm_warmup.py
+3
-3
@@ -13,7 +13,7 @@ import vllm.envs as envs
13
from vllm.distributed.parallel_state import get_dp_group
14
from vllm.model_executor.layers.fused_moe.deep_gemm_moe import DeepGemmExperts
15
from vllm.model_executor.layers.fused_moe.deep_gemm_utils import compute_aligned_M
16
-from vllm.model_executor.layers.fused_moe.layer import FusedMoE
16
+from vllm.model_executor.layers.fused_moe.layer import FusedMoE, FusedMoEModularMethod
17
from vllm.model_executor.layers.fused_moe.modular_kernel import FusedMoEModularKernel
18
from vllm.model_executor.layers.fused_moe.triton_deep_gemm_moe import (
19
TritonOrDeepGemmExperts,
@@ -160,8 +160,8 @@ def _fused_moe_grouped_gemm_may_use_deep_gemm(module: torch.nn.Module) -> bool:
160
):
161
return False
162
163
- if not isinstance(module.quant_method.fused_experts, FusedMoEModularKernel):
164
- # fused_experts could invoke deep_gemm_moe_fp8
163
+ if not isinstance(module.quant_method, FusedMoEModularMethod):
164
+ # modular kernels could invoke deep_gemm_moe_fp8
165
return True
166
167
mk: FusedMoEModularKernel = module.quant_method.fused_experts