-
-
Notifications
You must be signed in to change notification settings - Fork 19.6k
Naive dispatch combine POC #31933
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Naive dispatch combine POC #31933
Changes from 15 commits
f8851e0
085adf7
a6b039d
f8052ce
13b619f
04bb010
b1320de
4d47206
f86fad8
5601b95
8c1a530
7d7d5a6
63357f7
3886cfb
2284b59
5efe9ff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |
| import torch | ||
|
|
||
| import vllm.model_executor.layers.fused_moe.modular_kernel as mk | ||
| from vllm.distributed import get_ep_group | ||
| from vllm.model_executor.layers.fused_moe.config import FusedMoEQuantConfig | ||
| from vllm.model_executor.layers.fused_moe.topk_weight_and_reduce import ( | ||
| TopKWeightAndReduceContiguous, | ||
|
|
@@ -12,6 +13,115 @@ | |
| from vllm.model_executor.layers.fused_moe.utils import moe_kernel_quantize_input | ||
|
|
||
|
|
||
| class MoEPrepareAndFinalizeNaiveEP(mk.FusedMoEPrepareAndFinalize): | ||
| def __init__(self, defer_input_quant: bool = False) -> None: | ||
| super().__init__() | ||
| self.defer_input_quant = defer_input_quant | ||
|
|
||
| @property | ||
| def activation_format(self) -> mk.FusedMoEActivationFormat: | ||
| return mk.FusedMoEActivationFormat.Standard | ||
|
|
||
| def max_num_tokens_per_rank(self) -> int | None: | ||
| return None | ||
|
|
||
| def topk_indices_dtype(self) -> torch.dtype | None: | ||
| return None | ||
|
|
||
| def num_dispatchers(self) -> int: | ||
| return 1 | ||
|
|
||
| def output_is_reduced(self) -> bool: | ||
| return False | ||
|
|
||
| def prepare( | ||
| self, | ||
| a1: torch.Tensor, | ||
| topk_weights: torch.Tensor, | ||
| topk_ids: torch.Tensor, | ||
| num_experts: int, | ||
| expert_map: torch.Tensor | None, | ||
| apply_router_weight_on_input: bool, | ||
| quant_config: FusedMoEQuantConfig, | ||
| ) -> mk.PrepareResultType: | ||
| if apply_router_weight_on_input: | ||
| topk = topk_ids.size(1) | ||
| assert topk == 1, ( | ||
| "apply_router_weight_on_input is only implemented for topk=1" | ||
| ) | ||
| # Note: do not use inplace for shared experts overlap | ||
| a1 = a1 * topk_weights.to(a1.dtype) | ||
|
|
||
| # Defer input quantization to the MoE kernel. | ||
| if self.defer_input_quant: | ||
| a1q = a1 | ||
| a1q_scale = None | ||
| else: | ||
| a1q, a1q_scale = moe_kernel_quantize_input( | ||
| a1, | ||
| quant_config.a1_scale, | ||
| quant_config.quant_dtype, | ||
| quant_config.per_act_token_quant, | ||
| quant_config.block_shape, | ||
| ) | ||
| # TODO - this is just for deepgemm? | ||
| expert_tokens_meta = None | ||
|
|
||
| from vllm.platforms import current_platform | ||
|
|
||
| # The torch ops do not support fp8, so use an int8 view. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. which ops are missing? too late for this PR, but we can improve fp8 coverage in PyTorch to make things better in the future
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. float8_e4m3nz
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i.e. the usual one for nvidia gpus |
||
| # Since dispatch does not do a reduce, this is safe to do. | ||
| use_int8_view = a1q.dtype == current_platform.fp8_dtype() | ||
| if use_int8_view: | ||
| a1q = a1q.view(torch.int8) | ||
|
|
||
| # Skip gathering scales if we have static quantization | ||
| # (the scale is a scalar, replicated on all ranks) or | ||
| # if quantization is deferred. | ||
| skip_gather_scales = a1q_scale is None or a1q_scale.ndim == 0 | ||
| scales = None if skip_gather_scales else [a1q_scale] | ||
|
|
||
| res = get_ep_group().dispatch( | ||
| a1q, | ||
| topk_weights, | ||
| topk_ids, | ||
| is_sequence_parallel=False, # TODO: support SP | ||
| extra_tensors=scales, | ||
| ) | ||
| if skip_gather_scales: | ||
| a1q, topk_weights, topk_ids = res | ||
| else: | ||
| a1q, topk_weights, topk_ids, scales = res | ||
| a1q_scale = res[0] | ||
|
|
||
| if use_int8_view: | ||
| a1q = a1q.view(current_platform.fp8_dtype()) | ||
|
|
||
| return a1q, a1q_scale, expert_tokens_meta, topk_ids, topk_weights | ||
|
|
||
| def finalize( | ||
| self, | ||
| output: torch.Tensor, | ||
| fused_expert_output: torch.Tensor, | ||
| topk_weights: torch.Tensor, | ||
| topk_ids: torch.Tensor, | ||
| apply_router_weight_on_input: bool, | ||
| weight_and_reduce_impl: mk.TopKWeightAndReduce, | ||
| ) -> None: | ||
| if isinstance(weight_and_reduce_impl, TopKWeightAndReduceDelegate): | ||
| weight_and_reduce_impl = TopKWeightAndReduceContiguous() | ||
|
|
||
| out = weight_and_reduce_impl.apply( | ||
| output=None, | ||
| fused_expert_output=fused_expert_output, | ||
| topk_weights=topk_weights, | ||
| topk_ids=topk_ids, | ||
| apply_router_weight_on_input=apply_router_weight_on_input, | ||
| ) | ||
|
|
||
| output.copy_(get_ep_group().combine(out, is_sequence_parallel=False)) | ||
|
|
||
|
|
||
| class MoEPrepareAndFinalizeNoEP(mk.FusedMoEPrepareAndFinalize): | ||
| def __init__(self, defer_input_quant: bool = False) -> None: | ||
| super().__init__() | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what should this be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now, this can be the all2all_manager world size. If DP+TP is supported then it is divided by the tp world size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need to know num_dispatcher?