[Feature] support bf16 MoE router and mxfp4 MoE for MiMo V2 (#40448)

This commit is contained in:
ollybbmonster
2026-09-20 16:13:59 -07:00
committed by GitHub
parent 2e2d8a2fda
commit 983e643854
3 changed files with 26 additions and 6 deletions
@@ -1927,7 +1927,12 @@ class FlashAttentionBackend(AttentionBackend):
is_swa_layer = (
layer.sliding_window_size is not None and layer.sliding_window_size > -1
)
window_size = (layer.sliding_window_size, 0) if is_swa_layer else (-1, -1)
if is_swa_layer and layer.attn_type == AttentionType.ENCODER_ONLY:
window_size = (layer.sliding_window_size, layer.sliding_window_size)
elif is_swa_layer:
window_size = (layer.sliding_window_size, 0)
else:
window_size = (-1, -1)
causal = True
if layer.is_cross_attention or layer.attn_type == AttentionType.ENCODER_ONLY:
+2 -1
View File
@@ -250,7 +250,8 @@ class DFlashAttention(nn.Module):
# Per-head sink bias; each TP rank owns its slice of the
# all-heads checkpoint tensor.
self.attention_sink_bias = nn.Parameter(
torch.empty(self.num_heads, dtype=torch.float32), requires_grad=False
torch.empty(self.num_heads, dtype=torch.float32 if _is_npu else None),
requires_grad=False,
)
set_weight_attrs(
self.attention_sink_bias,
+18 -4
View File
@@ -349,7 +349,7 @@ class MoEGate(nn.Module):
):
super().__init__()
self.is_nextn = is_nextn
self.dtype = torch.float32
self.dtype = getattr(torch, getattr(config, "moe_router_dtype", "float32"))
self.weight = nn.Parameter(
torch.empty((config.n_routed_experts, config.hidden_size), dtype=self.dtype)
)
@@ -359,7 +359,7 @@ class MoEGate(nn.Module):
if quant_config is not None
and quant_config.get_name() == "modelopt_fp4"
and get_moe_runner_backend().is_flashinfer_trtllm()
else self.dtype
else torch.float32
)
self.e_score_correction_bias = nn.Parameter(
torch.empty((config.n_routed_experts), dtype=correction_bias_dtype)
@@ -368,9 +368,15 @@ class MoEGate(nn.Module):
self.e_score_correction_bias = None
def forward(self, hidden_states):
logits = F.linear(hidden_states.to(self.dtype), self.weight, None)
if self.dtype != torch.float32 and hidden_states.is_cuda:
return torch.mm(
hidden_states.to(self.dtype),
self.weight.t(),
out_dtype=torch.float32,
)
return logits
logits = F.linear(hidden_states.to(self.dtype), self.weight, None)
return logits.to(torch.float32)
class MiMoV2MoE(nn.Module):
@@ -427,6 +433,7 @@ class MiMoV2MoE(nn.Module):
num_expert_group=config.n_group,
topk_group=config.topk_group,
correction_bias=self.gate.e_score_correction_bias,
is_fp4_experts=getattr(quant_config, "is_fp4_experts", False),
scoring_func=config.scoring_func,
quant_config=quant_config,
routed_scaling_factor=1.0,
@@ -1591,6 +1598,13 @@ class MiMoV2ForCausalLM(nn.Module, AudioEncoderMixin):
skipped_mtp_weights = True
continue
if ".mlp.experts." in name and loaded_weight.dtype == torch.uint8:
if name.endswith(".weight_scale"):
name = name + "_inv"
loaded_weight = torch.exp2(loaded_weight.to(torch.float32) - 127.0)
elif name.endswith(".weight"):
loaded_weight = loaded_weight.view(torch.int8)
# Support fused qkv_proj checkpoint (Pro format)
if "qkv_proj" in name:
if name in params_dict: