@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 49a1262267
Fork 0

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 9, 19:30 UTC

[AMD][ROCm] MoRI EP: a high-performance all2all backend (#28664)

Signed-off-by: Alex Sun <alex.s@amd.com>

Alex Sun committed Jan 22, 2026 at 16:33 UTC 49a12622678906727dd9d1cb157d5e14ab24d91b
16 files changed +397 -9
tests/kernels/moe/modular_kernel_tools/cli_args.py
+1 -1
@@ -141,7 +141,7 @@ def make_config(args: argparse.Namespace) -> Config:
141
142 quant_config = None
143 if args.quant_dtype is not None:
144 - quant_config = FusedMoEQuantConfig(
144 + quant_config = FusedMoEQuantConfig.make(
145 quant_dtype=args.quant_dtype,
146 per_act_token_quant=args.per_token_quantized_activations,
147 per_out_ch_quant=args.per_channel_quantized_weights,
tests/kernels/moe/modular_kernel_tools/common.py
+19 -1
@@ -28,7 +28,13 @@ from vllm.model_executor.layers.fused_moe.config import (
28 FusedMoEQuantConfig,
29 RoutingMethodType,
30 )
31 -from vllm.utils.import_utils import has_deep_ep, has_deep_gemm, has_pplx
31 +from vllm.utils.import_utils import (
32 + has_aiter,
33 + has_deep_ep,
34 + has_deep_gemm,
35 + has_mori,
36 + has_pplx,
37 +)
38
39 from .mk_objects import (
40 TestMoEQuantConfig,
@@ -211,6 +217,14 @@ class Config:
217 or info.backend == "deepep_low_latency"
218 )
219
220 + def needs_aiter(self):
221 + info = expert_info(self.fused_experts_type)
222 + return info.needs_aiter
223 +
224 + def needs_mori(self):
225 + info = prepare_finalize_info(self.prepare_finalize_type)
226 + return info.backend == "mori"
227 +
228 def all2all_backend(self):
229 info = prepare_finalize_info(self.prepare_finalize_type)
230 return info.backend
@@ -278,6 +292,10 @@ class Config:
292 return False, "Needs DeepGEMM, but DeepGEMM not available."
293 if self.needs_pplx() and not has_pplx(): # noqa: SIM103
294 return False, "Needs PPLX, but PPLX not available."
295 + if self.needs_aiter() and not has_aiter(): # noqa: SIM103
296 + return False, "Needs Aiter, but Aiter not available."
297 + if self.needs_mori() and not has_mori(): # noqa: SIM103
298 + return False, "Needs MoRI, but MoRI not available."
299
300 return True, None
301
tests/kernels/moe/modular_kernel_tools/mk_objects.py
+48 -1
@@ -37,7 +37,13 @@ from vllm.model_executor.layers.quantization.utils.w8a8_utils import (
37 from vllm.platforms import current_platform
38 from vllm.utils.deep_gemm import is_deep_gemm_supported
39 from vllm.utils.flashinfer import has_flashinfer_cutlass_fused_moe
40 -from vllm.utils.import_utils import has_deep_ep, has_deep_gemm, has_pplx
40 +from vllm.utils.import_utils import (
41 + has_aiter,
42 + has_deep_ep,
43 + has_deep_gemm,
44 + has_mori,
45 + has_pplx,
46 +)
47
48
49 @dataclass
@@ -66,6 +72,7 @@ class ExpertInfo:
72 supports_expert_map: bool
73 needs_matching_quant: bool = False
74 needs_deep_gemm: bool = False
75 + needs_aiter: bool = False
76
77
78 PREPARE_FINALIZE_INFO: dict[mk.FusedMoEPrepareAndFinalize, PrepareFinalizeInfo] = {}
@@ -126,6 +133,7 @@ def register_experts(
133 supports_expert_map: bool,
134 needs_matching_quant: bool = False,
135 needs_deep_gemm: bool = False,
136 + needs_aiter: bool = False,
137 ):
138 global EXPERT_INFO
139 global MK_FUSED_EXPERT_TYPES
@@ -139,6 +147,7 @@ def register_experts(
147 supports_expert_map,
148 needs_matching_quant,
149 needs_deep_gemm,
150 + needs_aiter,
151 )
152
153 MK_FUSED_EXPERT_TYPES.append(kind)
@@ -218,6 +227,20 @@ if has_deep_ep() and not current_platform.has_device_capability(100):
227 backend="deepep_low_latency",
228 )
229
230 +if has_mori():
231 + from vllm.model_executor.layers.fused_moe.mori_prepare_finalize import (
232 + MoriPrepareAndFinalize,
233 + )
234 +
235 + register_prepare_and_finalize(
236 + MoriPrepareAndFinalize,
237 + standard_format,
238 + fp8_types,
239 + blocked_quantization_support=True,
240 + backend="mori",
241 + supports_apply_weight_on_input=False,
242 + )
243 +
244 if has_pplx():
245 from vllm.model_executor.layers.fused_moe.pplx_prepare_finalize import (
246 PplxPrepareAndFinalize,
@@ -261,6 +284,25 @@ if has_flashinfer_cutlass_fused_moe() and current_platform.has_device_capability
284 )
285 else:
286 FlashInferCutlassMoEPrepareAndFinalize = None
287 + FlashInferExperts = None
288 +
289 +
290 +if has_aiter():
291 + from vllm.model_executor.layers.fused_moe.rocm_aiter_fused_moe import (
292 + AiterExperts,
293 + )
294 +
295 + register_experts(
296 + AiterExperts,
297 + standard_format,
298 + fp8_types,
299 + blocked_quantization_support=True,
300 + supports_chunking=True,
301 + supports_expert_map=True,
302 + needs_aiter=True,
303 + )
304 +else:
305 + AiterExperts = None
306
307 if has_deep_gemm() and is_deep_gemm_supported():
308 register_experts(
@@ -316,6 +358,9 @@ if cutlass_fp8_supported():
358 supports_chunking=False,
359 supports_expert_map=False,
360 )
361 +else:
362 + CutlassBatchedExpertsFp8 = None
363 + CutlassExpertsFp8 = None
364
365 if cutlass_fp4_supported():
366 from vllm.model_executor.layers.fused_moe.cutlass_moe import CutlassExpertsFp4
@@ -328,6 +373,8 @@ if cutlass_fp4_supported():
373 supports_chunking=True,
374 supports_expert_map=False,
375 )
376 +else:
377 + CutlassExpertsFp4 = None
378
379 MK_QUANT_CONFIGS: list[TestMoEQuantConfig | None] = [
380 None,
vllm/_aiter_ops.py
+12
@@ -79,6 +79,8 @@ def _rocm_aiter_fused_moe_impl(
79 w2_scale: torch.Tensor | None = None,
80 a1_scale: torch.Tensor | None = None,
81 a2_scale: torch.Tensor | None = None,
82 + num_local_tokens: torch.Tensor | None = None,
83 + output_dtype: torch.dtype | None = None,
84 ) -> torch.Tensor:
85 from aiter import ActivationType, QuantType
86 from aiter.fused_moe import fused_moe
@@ -100,6 +102,8 @@ def _rocm_aiter_fused_moe_impl(
102 w2_scale,
103 a1_scale,
104 a2_scale,
105 + num_local_tokens=num_local_tokens,
106 + dtype=output_dtype,
107 )
108
109
@@ -117,7 +121,11 @@ def _rocm_aiter_fused_moe_fake(
121 w2_scale: torch.Tensor | None = None,
122 a1_scale: torch.Tensor | None = None,
123 a2_scale: torch.Tensor | None = None,
124 + num_local_tokens: torch.Tensor | None = None,
125 + output_dtype: torch.dtype | None = None,
126 ) -> torch.Tensor:
127 + if output_dtype is not None:
128 + return torch.empty_like(hidden_states, dtype=output_dtype)
129 return torch.empty_like(hidden_states)
130
131
@@ -1236,6 +1244,8 @@ class rocm_aiter_ops:
1244 w2_scale: torch.Tensor | None = None,
1245 a1_scale: torch.Tensor | None = None,
1246 a2_scale: torch.Tensor | None = None,
1247 + num_local_tokens: torch.Tensor | None = None,
1248 + output_dtype: torch.dtype | None = None,
1249 ) -> torch.Tensor:
1250 return torch.ops.vllm.rocm_aiter_fused_moe(
1251 hidden_states,
@@ -1251,6 +1261,8 @@ class rocm_aiter_ops:
1261 w2_scale,
1262 a1_scale,
1263 a2_scale,
1264 + num_local_tokens,
1265 + output_dtype,
1266 )
1267
1268 @staticmethod
vllm/config/parallel.py
+3
@@ -43,6 +43,7 @@ All2AllBackend = Literal[
43 "pplx",
44 "deepep_high_throughput",
45 "deepep_low_latency",
46 + "mori",
47 "allgather_reducescatter",
48 "flashinfer_all2allv",
49 ]
@@ -158,6 +159,7 @@ class ParallelConfig:
159 - "pplx": Use pplx kernels\n
160 - "deepep_high_throughput": Use deepep high-throughput kernels\n
161 - "deepep_low_latency": Use deepep low-latency kernels\n
162 + - "mori": Use mori kernels\n
163 - "flashinfer_all2allv": Use flashinfer alltoallv kernels for mnnvl"""
164
165 max_parallel_loading_workers: int | None = None
@@ -443,6 +445,7 @@ class ParallelConfig:
445 "naive",
446 "deepep_high_throughput",
447 "deepep_low_latency",
448 + "mori",
449 )
450 and self.enable_expert_parallel
451 and self.tensor_parallel_size > 1
vllm/distributed/device_communicators/all2all.py
+94 -1
@@ -10,7 +10,7 @@ from vllm.distributed import get_dp_group, get_ep_group
10 from vllm.forward_context import get_forward_context
11 from vllm.logger import init_logger
12 from vllm.utils.flashinfer import has_flashinfer_all2all
13 -from vllm.utils.import_utils import has_deep_ep, has_pplx
13 +from vllm.utils.import_utils import has_deep_ep, has_mori, has_pplx
14
15 from .base_device_communicator import All2AllManagerBase, Cache
16
@@ -507,3 +507,96 @@ class FlashInferAllToAllManager(All2AllManagerBase):
507 self.prepare_workspace_tensor = None
508 self.mapping = None
509 self.initialized = False
510 +
511 +
512 +class MoriAll2AllManager(All2AllManagerBase):
513 + def __init__(self, cpu_group):
514 + assert has_mori(), (
515 + "MoRI kernels not found. Please follow https://github.com/ROCm/mori/blob/main/README.md"
516 + " to install MoRI kernels."
517 + ) # noqa
518 + import mori
519 +
520 + super().__init__(cpu_group)
521 + self.handle_cache = Cache()
522 +
523 + torch._C._distributed_c10d._register_process_group("mori", cpu_group)
524 + mori.shmem.shmem_torch_process_group_init("mori")
525 +
526 + def _make_all2all_kwargs(
527 + self,
528 + rank: int,
529 + num_ep_ranks: int,
530 + input_dtype: torch.dtype,
531 + quant_dtype: torch.dtype,
532 + token_hidden_size: int,
533 + scale_dim: int,
534 + scale_type_size: int,
535 + max_num_tokens_per_dp_rank: int,
536 + num_local_experts: int,
537 + num_experts_per_token: int,
538 + ):
539 + import mori # type: ignore[import-not-found]
540 +
541 + from vllm.platforms.rocm import on_gfx942, on_gfx950
542 +
543 + assert on_gfx942() or on_gfx950(), (
544 + "mori currently only support arch gfx942 and gfx950"
545 + )
546 +
547 + if not self.internode:
548 + # single node
549 + kernel_type = mori.ops.EpDispatchCombineKernelType.IntraNode
550 + rdma_block_num = 0
551 + warp_num_per_block = 16
552 + block_num = 80
553 + else:
554 + # multi node
555 + kernel_type = mori.ops.EpDispatchCombineKernelType.InterNodeV1
556 + if on_gfx942():
557 + warp_num_per_block = 16
558 + block_num = 32
559 + rdma_block_num = 16
560 + elif on_gfx950():
561 + warp_num_per_block = 8
562 + block_num = 64
563 + rdma_block_num = 32
564 + else:
565 + raise NotImplementedError(
566 + "mori currently only support arch gfx942 and gfx950"
567 + )
568 +
569 + return dict(
570 + rank=rank,
571 + world_size=num_ep_ranks,
572 + data_type=quant_dtype,
573 + hidden_dim=token_hidden_size,
574 + scale_dim=scale_dim,
575 + scale_type_size=scale_type_size,
576 + max_token_type_size=input_dtype.itemsize,
577 + max_num_inp_token_per_rank=max_num_tokens_per_dp_rank,
578 + num_experts_per_rank=num_local_experts,
579 + num_experts_per_token=num_experts_per_token,
580 + warp_num_per_block=warp_num_per_block,
581 + block_num=block_num,
582 + kernel_type=kernel_type,
583 + rdma_block_num=rdma_block_num,
584 + gpu_per_node=min(8, num_ep_ranks),
585 + )
586 +
587 + def _make_handle(self, **kwargs):
588 + import mori # type: ignore[import-not-found]
589 +
590 + mori_config = mori.ops.EpDispatchCombineConfig(**kwargs)
591 + handle = mori.ops.EpDispatchCombineOp(mori_config)
592 + return handle
593 +
594 + def get_handle(self, kwargs):
595 + import mori # type: ignore[import-not-found]
596 +
597 + mori_kwargs = self._make_all2all_kwargs(**kwargs)
598 + logger.debug("MoRI all2all args %s", mori_kwargs)
599 + handle: mori.ops.EpDispatchCombineOp = self.handle_cache.get_or_create(
600 + mori_kwargs, self._make_handle
601 + )
602 + return handle
vllm/distributed/device_communicators/cuda_communicator.py
+4
@@ -110,6 +110,10 @@ class CudaCommunicator(DeviceCommunicatorBase):
110 from .all2all import DeepEPLLAll2AllManager
111
112 self.all2all_manager = DeepEPLLAll2AllManager(self.cpu_group)
113 + elif self.all2all_backend == "mori":
114 + from .all2all import MoriAll2AllManager
115 +
116 + self.all2all_manager = MoriAll2AllManager(self.cpu_group)
117 elif self.all2all_backend == "flashinfer_all2allv":
118 from .all2all import FlashInferAllToAllManager
119
vllm/envs.py
+3
@@ -187,6 +187,7 @@ if TYPE_CHECKING:
187 "pplx",
188 "deepep_high_throughput",
189 "deepep_low_latency",
190 + "mori",
191 "allgather_reducescatter",
192 "flashinfer_all2allv",
193 ] = "allgather_reducescatter"
@@ -1298,6 +1299,7 @@ environment_variables: dict[str, Callable[[], Any]] = {
1299 # - "pplx": use pplx kernels
1300 # - "deepep_high_throughput", use deepep high-throughput kernels
1301 # - "deepep_low_latency", use deepep low-latency kernels
1302 + # - "mori", use MoRI kernels
1303 # - "flashinfer_all2allv", use flashinfer alltoallv kernels for mnnvl
1304 "VLLM_ALL2ALL_BACKEND": env_with_choices(
1305 "VLLM_ALL2ALL_BACKEND",
@@ -1307,6 +1309,7 @@ environment_variables: dict[str, Callable[[], Any]] = {
1309 "pplx",
1310 "deepep_high_throughput",
1311 "deepep_low_latency",
1312 + "mori",
1313 "allgather_reducescatter",
1314 "flashinfer_all2allv",
1315 ],
vllm/model_executor/layers/fused_moe/__init__.py
+4
@@ -88,6 +88,9 @@ if HAS_TRITON:
88 fused_experts,
89 get_config_file_name,
90 )
91 + from vllm.model_executor.layers.fused_moe.rocm_aiter_fused_moe import (
92 + AiterExperts,
93 + )
94 from vllm.model_executor.layers.fused_moe.router.fused_topk_router import (
95 fused_topk,
96 )
@@ -99,6 +102,7 @@ if HAS_TRITON:
102 )
103
104 __all__ += [
105 + "AiterExperts",
106 "fused_topk",
107 "fused_experts",
108 "get_config_file_name",
vllm/model_executor/layers/fused_moe/all2all_utils.py
+34 -1
@@ -16,7 +16,7 @@ from vllm.model_executor.layers.fused_moe.modular_kernel import (
16 FusedMoEPrepareAndFinalize,
17 )
18 from vllm.platforms import current_platform
19 -from vllm.utils.import_utils import has_deep_ep, has_pplx
19 +from vllm.utils.import_utils import has_deep_ep, has_mori, has_pplx
20
21 if current_platform.is_cuda_alike():
22 if has_pplx():
@@ -30,6 +30,8 @@ if current_platform.is_cuda_alike():
30 DEEPEP_QUANT_BLOCK_SHAPE,
31 DeepEPLLPrepareAndFinalize,
32 )
33 + if has_mori():
34 + from .mori_prepare_finalize import MoriPrepareAndFinalize
35
36
37 def maybe_roundup_layer_hidden_size(
@@ -169,5 +171,36 @@ def maybe_make_prepare_finalize(
171 physical_to_global=physical_to_global,
172 local_expert_global_ids=local_expert_global_ids,
173 )
174 + elif moe.use_mori_kernels:
175 + assert quant_config is not None
176 +
177 + # Note: We may want to use FP8 dispatch just to reduce
178 + # data movement.
179 + use_fp8_dispatch = (
180 + quant_config.is_per_act_token or quant_config.is_block_quantized
181 + )
182 + # For PTPC (per token per channel) quant, the scale dim for each token is 1
183 + # For 1x128 quant, the scale dim for each token is hidden_dim // 128
184 + scale_dim = 1 if quant_config.is_per_act_token else moe.hidden_dim // 128
185 + all_to_all_args = dict(
186 + rank=all2all_manager.rank,
187 + num_ep_ranks=all2all_manager.world_size,
188 + quant_dtype=quant_config.quant_dtype,
189 + token_hidden_size=moe.hidden_dim,
190 + scale_dim=scale_dim,
191 + scale_type_size=torch.float32.itemsize,
192 + max_num_tokens_per_dp_rank=moe.max_num_tokens,
193 + input_dtype=moe.in_dtype,
194 + num_local_experts=moe.num_experts // all2all_manager.world_size,
195 + num_experts_per_token=moe.experts_per_token,
196 + )
197 + handle = all2all_manager.get_handle(all_to_all_args)
198 +
199 + prepare_finalize = MoriPrepareAndFinalize(
200 + handle,
201 + max_tokens_per_rank=moe.max_num_tokens,
202 + num_dispatchers=all2all_manager.world_size,
203 + use_fp8_dispatch=use_fp8_dispatch,
204 + )
205
206 return prepare_finalize
vllm/model_executor/layers/fused_moe/config.py
+8
@@ -893,6 +893,10 @@ class FusedMoEParallelConfig:
893 self.all2all_backend in ["naive", "allgather_reducescatter"]
894 )
895
896 + @property
897 + def use_mori_kernels(self):
898 + return self.use_all2all_kernels and self.all2all_backend == "mori"
899 +
900 @staticmethod
901 def flatten_tp_across_dp_and_pcp(
902 tp_size: int, dp_size: int, dp_rank: int, pcp_size: int, pcp_rank: int
@@ -1136,6 +1140,10 @@ class FusedMoEConfig:
1140 def use_deepep_ll_kernels(self):
1141 return self.moe_parallel_config.use_deepep_ll_kernels
1142
1143 + @property
1144 + def use_mori_kernels(self):
1145 + return self.moe_parallel_config.use_mori_kernels
1146 +
1147 @property
1148 def use_flashinfer_cutlass_kernels(self):
1149 """
vllm/model_executor/layers/fused_moe/layer.py
+13
@@ -570,6 +570,14 @@ class FusedMoE(CustomOp):
570 self.moe_config_use_flashinfer_cutlass_kernels = (
571 self.moe_config.use_flashinfer_cutlass_kernels
572 )
573 + if self.use_mori_kernels:
574 + assert self.rocm_aiter_fmoe_enabled, (
575 + "Mori needs to be used with aiter fused_moe for now."
576 + )
577 + assert not self.aiter_fmoe_shared_expert_enabled, (
578 + "Mori does not support fusion shared expert now. "
579 + "Turn it off by setting VLLM_ROCM_USE_AITER_FUSION_SHARED_EXPERTS=0"
580 + )
581
582 self.quant_config = quant_config
583
@@ -712,6 +720,10 @@ class FusedMoE(CustomOp):
720 def use_deepep_ll_kernels(self):
721 return self.moe_parallel_config.use_deepep_ll_kernels
722
723 + @property
724 + def use_mori_kernels(self):
725 + return self.moe_parallel_config.use_mori_kernels
726 +
727 @property
728 def use_flashinfer_cutlass_kernels(self):
729 return (
@@ -729,6 +741,7 @@ class FusedMoE(CustomOp):
741 return (
742 self.moe_parallel_config.use_pplx_kernels
743 or self.moe_parallel_config.use_deepep_ll_kernels
744 + or self.moe_parallel_config.use_mori_kernels
745 or (self.dp_size > 1 and self.use_flashinfer_cutlass_kernels)
746 ) and envs.VLLM_ENABLE_MOE_DP_CHUNK
747
vllm/model_executor/layers/fused_moe/mori_prepare_finalize.py new
+121
@@ -0,0 +1,121 @@
1 +# SPDX-License-Identifier: Apache-2.0
2 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 +
4 +import mori
5 +import torch
6 +
7 +import vllm.model_executor.layers.fused_moe.modular_kernel as mk
8 +from vllm.logger import init_logger
9 +from vllm.model_executor.layers.fused_moe.config import FusedMoEQuantConfig
10 +from vllm.platforms import current_platform
11 +
12 +logger = init_logger(__name__)
13 +
14 +
15 +class MoriPrepareAndFinalize(mk.FusedMoEPrepareAndFinalize):
16 + """
17 + Prepare/Finalize using MoRI kernels.
18 + """
19 +
20 + def __init__(
21 + self,
22 + mori_op: mori.ops.EpDispatchCombineOp,
23 + max_tokens_per_rank: int,
24 + num_dispatchers: int,
25 + use_fp8_dispatch: bool = False,
26 + ):
27 + super().__init__()
28 + self.mori_op = mori_op
29 + self.num_dispatchers_ = num_dispatchers
30 + self.max_tokens_per_rank = max_tokens_per_rank
31 + self.use_fp8_dispatch = use_fp8_dispatch
32 +
33 + @property
34 + def activation_format(self) -> mk.FusedMoEActivationFormat:
35 + return mk.FusedMoEActivationFormat.Standard
36 +
37 + def output_is_reduced(self) -> bool:
38 + return True
39 +
40 + def num_dispatchers(self):
41 + return self.num_dispatchers_
42 +
43 + def max_num_tokens_per_rank(self) -> int | None:
44 + return self.max_tokens_per_rank
45 +
46 + def topk_indices_dtype(self) -> torch.dtype | None:
47 + return torch.int32
48 +
49 + def supports_async(self) -> bool:
50 + return False
51 +
52 + def prepare(
53 + self,
54 + a1: torch.Tensor,
55 + topk_weights: torch.Tensor,
56 + topk_ids: torch.Tensor,
57 + num_experts: int,
58 + expert_map: torch.Tensor | None,
59 + apply_router_weight_on_input: bool,
60 + quant_config: FusedMoEQuantConfig,
61 + ) -> mk.PrepareResultType:
62 + """
63 + Returns a tuple of:
64 + - quantized + dispatched a.
65 + - Optional quantized + dispatched a1_scales.
66 + - Optional ExpertTokensMetadata containing gpu/cpu tensors
67 + as big as the number of local experts with the information about the
68 + number of tokens assigned to each local expert.
69 + - Optional dispatched expert topk IDs
70 + - Optional dispatched expert topk weight
71 + """
72 + assert not apply_router_weight_on_input, (
73 + "mori does not support apply_router_weight_on_input=True now."
74 + )
75 + scale = None
76 + if self.use_fp8_dispatch:
77 + from aiter import QuantType, get_hip_quant
78 +
79 + if quant_config.is_block_quantized:
80 + quant_func = get_hip_quant(QuantType.per_1x128)
81 + a1, scale = quant_func(a1, quant_dtype=current_platform.fp8_dtype())
82 + elif quant_config.is_per_act_token:
83 + quant_func = get_hip_quant(QuantType.per_Token)
84 + a1, scale = quant_func(a1, quant_dtype=current_platform.fp8_dtype())
85 +
86 + (
87 + dispatch_a1,
88 + dispatch_weights,
89 + dispatch_scale,
90 + dispatch_ids,
91 + dispatch_recv_token_num,
92 + ) = self.mori_op.dispatch(a1, topk_weights, scale, topk_ids)
93 +
94 + expert_tokens_meta = mk.ExpertTokensMetadata(
95 + expert_num_tokens=dispatch_recv_token_num, expert_num_tokens_cpu=None
96 + )
97 +
98 + return (
99 + dispatch_a1,
100 + dispatch_scale,
101 + expert_tokens_meta,
102 + dispatch_ids,
103 + dispatch_weights,
104 + )
105 +
106 + def finalize(
107 + self,
108 + output: torch.Tensor,
109 + fused_expert_output: torch.Tensor,
110 + topk_weights: torch.Tensor,
111 + topk_ids: torch.Tensor,
112 + apply_router_weight_on_input: bool,
113 + weight_and_reduce_impl: mk.TopKWeightAndReduce,
114 + ) -> None:
115 + num_token = output.shape[0]
116 + result = self.mori_op.combine(
117 + fused_expert_output,
118 + None,
119 + topk_ids,
120 + )[0]
121 + output.copy_(result[:num_token])
vllm/model_executor/layers/fused_moe/rocm_aiter_fused_moe.py
+17 -4
@@ -188,6 +188,9 @@ def rocm_aiter_fused_experts(
188 apply_router_weight_on_input: bool = False,
189 expert_map: torch.Tensor | None = None,
190 quant_config: FusedMoEQuantConfig | None = None,
191 + a1q_scale: torch.Tensor | None = None,
192 + num_local_tokens: torch.Tensor | None = None,
193 + output_dtype: torch.dtype | None = None,
194 ) -> torch.Tensor:
195 if quant_config is None:
196 quant_config = FUSED_MOE_UNQUANTIZED_CONFIG
@@ -216,6 +219,9 @@ def rocm_aiter_fused_experts(
219 assert topk_weights.shape[-1] == 1, (
220 "Only support topk=1 when `apply_router_weight_on_input` is True"
221 )
222 + assert num_local_tokens is None, (
223 + "AITER tkw1 kernel does not support `num_local_tokens`"
224 + )
225
226 return rocm_aiter_ops.asm_moe_tkw1(
227 hidden_states,
@@ -272,9 +278,11 @@ def rocm_aiter_fused_experts(
278 activation_method=activation_method,
279 w1_scale=quant_config.w1_scale,
280 w2_scale=quant_config.w2_scale,
275 - a1_scale=quant_config.a1_scale,
281 + a1_scale=quant_config.a1_scale if a1q_scale is None else a1q_scale,
282 a2_scale=quant_config.a2_scale,
283 doweight_stage1=apply_router_weight_on_input,
284 + num_local_tokens=num_local_tokens,
285 + output_dtype=output_dtype,
286 )
287
288
@@ -370,9 +378,12 @@ class AiterExperts(mk.FusedMoEPermuteExpertsUnpermute):
378 # TODO(rob): rocm_aiter_fused_experts uses self.quant_config's
379 # a_scales for static quantization. Update this to fit better
380 # with the interface once all quant integrations are complete.
373 - assert a1q_scale is None
381 assert a2_scale == self.quant_config.a2_scale
375 - assert expert_tokens_meta is None
382 +
383 + if expert_tokens_meta is not None:
384 + num_local_tokens = expert_tokens_meta.expert_num_tokens
385 + else:
386 + num_local_tokens = None
387
388 result = rocm_aiter_fused_experts(
389 hidden_states=hidden_states,
@@ -384,6 +395,8 @@ class AiterExperts(mk.FusedMoEPermuteExpertsUnpermute):
395 apply_router_weight_on_input=apply_router_weight_on_input,
396 expert_map=expert_map,
397 quant_config=self.quant_config,
398 + a1q_scale=a1q_scale,
399 + num_local_tokens=num_local_tokens,
400 + output_dtype=output.dtype,
401 )
388 - assert result.shape == output.shape
402 output.copy_(result)
vllm/platforms/rocm.py
+6
@@ -106,6 +106,12 @@ def on_gfx9() -> bool:
106 return any(arch in GPU_ARCH for arch in ["gfx90a", "gfx942", "gfx950"])
107
108
109 +@cache
110 +def on_gfx942() -> bool:
111 + GPU_ARCH = torch.cuda.get_device_properties("cuda").gcnArchName
112 + return any(arch in GPU_ARCH for arch in ["gfx942"])
113 +
114 +
115 @cache
116 def on_gfx950() -> bool:
117 GPU_ARCH = torch.cuda.get_device_properties("cuda").gcnArchName
vllm/utils/import_utils.py
+10
@@ -451,3 +451,13 @@ def has_helion() -> bool:
451 # use helion...
452 """
453 return _has_module("helion")
454 +
455 +
456 +def has_aiter() -> bool:
457 + """Whether the optional `aiter` package is available."""
458 + return _has_module("aiter")
459 +
460 +
461 +def has_mori() -> bool:
462 + """Whether the optional `mori` package is available."""
463 + return _has_module("mori")