[Kimi-K3] Accept fp32 routing weights in the fused MoE finalize (#38612)

Co-authored-by: Mohammad Angkad <mohammad.angkad@radixark.ai>
This commit is contained in:
Mohammad Miadh Angkad
2026-09-09 01:33:39 -07:00
committed by GitHub
co-authored by Mohammad Angkad
parent d10ebdd0cb
commit 72d5c5bb73
7 changed files with 55 additions and 29 deletions
@@ -248,10 +248,13 @@ def test_ar_fusion_push_norm(num_tokens: int, rows_per_token: int):
FIN_TOPK = 16
def _build_permuted_layout(num_tokens: int, seed: int):
def _build_permuted_layout(
num_tokens: int, seed: int, w_dtype: torch.dtype = torch.float32
):
"""trtllm-gen permuted gemm2 layout (rows grouped by expert, per-expert
tile padding). Deterministic on CPU: idx/weights are identical on every
rank (TP semantics — same routing), gemm2 values are per-rank."""
rank (TP semantics — same routing), gemm2 values are per-rank.
``w_dtype`` is the routing-weight dtype the deferred finalize hands back."""
num_experts, tile = 896, 8
gen = torch.Generator(device="cpu").manual_seed(seed)
topk_ids = torch.stack(
@@ -268,7 +271,7 @@ def _build_permuted_layout(num_tokens: int, seed: int):
for i, e in enumerate(topk_ids.flatten().tolist()):
idx[i] = bases[e] + fill[e]
fill[e] += 1
weights = torch.rand(num_tokens, FIN_TOPK, generator=gen).to(torch.bfloat16)
weights = torch.rand(num_tokens, FIN_TOPK, generator=gen).to(w_dtype)
num_rows = int(padded.sum())
g = torch.Generator(device="cpu").manual_seed(seed * 31 + dist.get_rank())
gemm2 = (torch.randn(num_rows, NORM_DIM, generator=g) * 2).to(torch.bfloat16)
@@ -296,13 +299,14 @@ def _finalize_norm_ref(gemm2, idx, weights, norm_w, eps: float) -> torch.Tensor:
return (total * factor * norm_w.float()).to(torch.bfloat16)
@pytest.mark.parametrize("w_dtype", [torch.float32, torch.bfloat16])
@pytest.mark.parametrize("bs", PUSH_BS)
@torch.inference_mode()
def test_ar_fusion_finalize_push_norm(bs: int):
def test_ar_fusion_finalize_push_norm(bs: int, w_dtype: torch.dtype):
comm = _init_comm()
world = comm.world_size
eps = 1e-6
gemm2, idx, weights = _build_permuted_layout(bs, seed=bs + 23)
gemm2, idx, weights = _build_permuted_layout(bs, seed=bs + 23, w_dtype=w_dtype)
g = torch.Generator(device="cpu").manual_seed(77)
norm_w = (torch.rand(NORM_DIM, generator=g) + 0.5).to(torch.bfloat16).to(_device())
ref = _finalize_norm_ref(gemm2, idx, weights, norm_w, eps)
@@ -325,7 +329,12 @@ def test_ar_fusion_finalize_push_norm_stress():
norm_w = (torch.rand(NORM_DIM, generator=g) + 0.5).to(torch.bfloat16).to(_device())
for it in range(12):
bs = (1, 8, 32)[it % 3]
gemm2, idx, weights = _build_permuted_layout(bs, seed=9000 + it)
# alternate the routing-weight precision: both kernel instantiations
# share the one push workspace
w_dtype = (torch.float32, torch.bfloat16)[it % 2]
gemm2, idx, weights = _build_permuted_layout(
bs, seed=9000 + it, w_dtype=w_dtype
)
ref = _finalize_norm_ref(gemm2, idx, weights, norm_w, eps)
out = torch.empty(bs, NORM_DIM, dtype=torch.bfloat16, device=_device())
all_reduce.finalize_all_reduce_push_norm(