#009

fused_moe

bf16 vllm · both · vllm.model_executor.layers.fused_moe.fused_moe · importance 11.4%

Reference Implementation

reference.py
import torch
import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):

    def __init__(self, num_experts: int, intermediate_size: int, top_k: int) -> None:
        super().__init__()
        self.num_experts = num_experts
        self.intermediate_size = intermediate_size
        self.top_k = top_k

    def forward(self, hidden_states: torch.Tensor, w1: torch.Tensor, w2: torch.Tensor, topk_weights: torch.Tensor, topk_ids: torch.Tensor) -> torch.Tensor:
        token_count = hidden_states.shape[0]
        hidden_size = hidden_states.shape[1]
        intermediate_size = self.intermediate_size
        output = torch.zeros(token_count, hidden_size, device=hidden_states.device, dtype=torch.float32)
        hidden_fp32 = hidden_states.float()
        for expert_index in range(self.num_experts):
            mask = topk_ids == expert_index
            if not mask.any():
                continue
            weight_for_expert = (topk_weights * mask.to(topk_weights.dtype)).sum(dim=1)
            token_idx = weight_for_expert.nonzero(as_tuple=True)[0]
            if token_idx.numel() == 0:
                continue
            x = hidden_fp32.index_select(0, token_idx)
            w1_e = w1[expert_index].float()
            w2_e = w2[expert_index].float()
            intermediate = F.linear(x, w1_e)
            gate = intermediate[:, :intermediate_size]
            up = intermediate[:, intermediate_size:]
            activated = F.silu(gate) * up
            expert_output = F.linear(activated, w2_e)
            output.index_add_(0, token_idx, expert_output * weight_for_expert.index_select(0, token_idx).unsqueeze(1))
        return output

Shapes

TSOL hardware:
# token_counthidden_sizeintermediate_sizenum_expertstop_k TSOL(XPU-A)TProdS
0 1352048204882 38.30 us 232.70 us 16.5%
1 2772048204882 56.71 us 249.80 us 22.7%
2 6682048204882 136.79 us 477.10 us 28.7%
3 10232048204882 208.22 us 539.00 us 38.6%
4 19792048204882 403.02 us 772.50 us 52.2%
5 41952048204882 851.82 us 1.60 ms 53.1%
6 76892048204882 1.56 ms 2.68 ms 58.1%
7 158092048204882 3.20 ms 5.37 ms 59.7%
8 120487681288 14.25 us 116.90 us 12.2%
9 240020487681288 757.05 us 2.16 ms 35.1%
10 419520487681288 1.32 ms 2.98 ms 44.4%
11 819220487681288 2.59 ms 4.99 ms 51.9%
12 1580920487681288 4.99 ms 9.09 ms 54.9%
13 2563220487681288 8.10 ms 14.48 ms 55.9%
14 4593620487681288 14.52 ms 25.71 ms 56.5%
15 52040963841288 230.33 us 595.80 us 38.7%
16 101940963841288 322.57 us 882.90 us 36.5%
17 204440963841288 646.04 us 1.61 ms 40.2%
18 393640963841288 1.24 ms 2.80 ms 44.5%
19 819240963841288 2.59 ms 5.69 ms 45.4%
20 40984096409682 3.33 ms 5.33 ms 62.5%
21 81794096409682 6.63 ms 10.10 ms 65.7%
22 153814096409682 12.48 ms 18.64 ms 67.0%

Input Generation

input.py
import torch


def _make_inputs(
    token_count: int, hidden_size: int, intermediate_size: int, num_experts: int, top_k: int
) -> dict[str, torch.Tensor]:
    hidden_states = torch.randn(token_count, hidden_size, dtype=torch.bfloat16, device="cuda") * 0.1
    w1 = torch.randn(
        num_experts, 2 * intermediate_size, hidden_size, dtype=torch.bfloat16, device="cuda"
    ) * hidden_size ** (-0.5)
    w2 = torch.randn(
        num_experts, hidden_size, intermediate_size, dtype=torch.bfloat16, device="cuda"
    ) * intermediate_size ** (-0.5)
    # Realistic top-k routing: select top_k experts per token from router logits so that
    # each token's selected experts are unique (real MoE never routes a token to the same
    # expert twice). Using torch.randint here instead would produce duplicate experts per
    # token, an unphysical case that sorted-scatter MoE kernels handle differently from the
    # gather reference, spuriously failing accuracy checks.
    router_logits = torch.randn(token_count, num_experts, dtype=torch.float32, device="cuda")
    topk_weights, topk_ids = torch.topk(router_logits.softmax(dim=-1), top_k, dim=-1)
    topk_weights = (topk_weights / topk_weights.sum(dim=-1, keepdim=True)).to(torch.float32)
    topk_ids = topk_ids.to(torch.int32)
    return {
        "hidden_states": hidden_states,
        "w1": w1,
        "w2": w2,
        "topk_weights": topk_weights,
        "topk_ids": topk_ids,
    }