Optimize topk sigmoid in minimax_m2 (#14047)

Co-authored-by: xuebi <xuebi@minimaxi.com>
This commit is contained in:
Roger Young
2025-12-02 14:07:12 +08:00
committed by GitHub
co-authored by xuebi
parent 73df525382
commit 3dabd609fb
2 changed files with 38 additions and 13 deletions
+38 -10
View File
@@ -29,7 +29,6 @@ from typing import (
) )
import torch import torch
import torch.nn.functional as F
from sglang.srt.custom_op import CustomOp from sglang.srt.custom_op import CustomOp
from sglang.srt.distributed import get_tp_group from sglang.srt.distributed import get_tp_group
@@ -81,7 +80,7 @@ if _is_cuda:
pass pass
if _is_cuda or _is_hip: if _is_cuda or _is_hip:
from sgl_kernel import topk_softmax from sgl_kernel import topk_sigmoid, topk_softmax
if _use_aiter: if _use_aiter:
try: try:
from aiter import biased_grouped_topk as aiter_biased_grouped_topk from aiter import biased_grouped_topk as aiter_biased_grouped_topk
@@ -109,6 +108,7 @@ class TopKConfig:
apply_routed_scaling_factor_on_output: bool = False apply_routed_scaling_factor_on_output: bool = False
fused_shared_experts_scaling_factor: Optional[float] = None fused_shared_experts_scaling_factor: Optional[float] = None
output_format: Optional[TopKOutputFormat] = None output_format: Optional[TopKOutputFormat] = None
scoring_func: str = "softmax"
# -------------------------------- TopKOutput --------------------------------------- # -------------------------------- TopKOutput ---------------------------------------
@@ -244,6 +244,7 @@ class TopK(CustomOp):
apply_routed_scaling_factor_on_output=apply_routed_scaling_factor_on_output, apply_routed_scaling_factor_on_output=apply_routed_scaling_factor_on_output,
fused_shared_experts_scaling_factor=fused_shared_experts_scaling_factor, fused_shared_experts_scaling_factor=fused_shared_experts_scaling_factor,
output_format=output_format, output_format=output_format,
scoring_func=scoring_func,
) )
def forward_native( def forward_native(
@@ -430,10 +431,19 @@ def fused_topk_torch_native(
topk: int, topk: int,
renormalize: bool, renormalize: bool,
correction_bias: torch.Tensor = None, correction_bias: torch.Tensor = None,
scoring_func: str = "softmax",
): ):
def scoring_func_impl(gating_output: torch.Tensor) -> torch.Tensor:
if scoring_func == "softmax":
return gating_output.softmax(dim=-1)
elif scoring_func == "sigmoid":
return gating_output.sigmoid()
else:
raise ValueError(f"Invalid scoring function: {scoring_func}")
if correction_bias is not None: if correction_bias is not None:
n_routed_experts = gating_output.shape[-1] n_routed_experts = gating_output.shape[-1]
scores = gating_output.softmax(dim=-1) scores = scoring_func_impl(gating_output)
scores_for_choice = scores.view( scores_for_choice = scores.view(
-1, n_routed_experts -1, n_routed_experts
) + correction_bias.unsqueeze(0) ) + correction_bias.unsqueeze(0)
@@ -448,7 +458,7 @@ def fused_topk_torch_native(
M, topk, dtype=torch.float32, device=hidden_states.device M, topk, dtype=torch.float32, device=hidden_states.device
) )
topk_ids = torch.empty(M, topk, dtype=torch.int32, device=hidden_states.device) topk_ids = torch.empty(M, topk, dtype=torch.int32, device=hidden_states.device)
topk_weights = F.softmax(gating_output.float(), dim=-1) topk_weights = scoring_func_impl(gating_output.float())
topk_weights, topk_ids = torch.topk(topk_weights, topk, dim=-1) topk_weights, topk_ids = torch.topk(topk_weights, topk, dim=-1)
if renormalize: if renormalize:
@@ -464,6 +474,7 @@ def fused_topk_cpu(
num_token_non_padded: Optional[torch.Tensor] = None, num_token_non_padded: Optional[torch.Tensor] = None,
expert_location_dispatch_info: Optional[ExpertLocationDispatchInfo] = None, expert_location_dispatch_info: Optional[ExpertLocationDispatchInfo] = None,
correction_bias: torch.Tensor = None, correction_bias: torch.Tensor = None,
scoring_func: str = "softmax",
): ):
topk_weights, topk_ids = torch.ops.sgl_kernel.topk_softmax_cpu( topk_weights, topk_ids = torch.ops.sgl_kernel.topk_softmax_cpu(
hidden_states=hidden_states, hidden_states=hidden_states,
@@ -494,8 +505,10 @@ def fused_topk(
gating_output: torch.Tensor, gating_output: torch.Tensor,
topk: int, topk: int,
renormalize: bool, renormalize: bool,
correction_bias: Optional[torch.Tensor] = None,
num_token_non_padded: Optional[torch.Tensor] = None, num_token_non_padded: Optional[torch.Tensor] = None,
expert_location_dispatch_info: Optional[ExpertLocationDispatchInfo] = None, expert_location_dispatch_info: Optional[ExpertLocationDispatchInfo] = None,
scoring_func: str = "softmax",
): ):
assert hidden_states.shape[0] == gating_output.shape[0], "Number of tokens mismatch" assert hidden_states.shape[0] == gating_output.shape[0], "Number of tokens mismatch"
@@ -506,12 +519,23 @@ def fused_topk(
) )
topk_ids = torch.empty(M, topk, dtype=torch.int32, device=hidden_states.device) topk_ids = torch.empty(M, topk, dtype=torch.int32, device=hidden_states.device)
topk_softmax( if scoring_func == "softmax":
topk_weights, topk_softmax(
topk_ids, topk_weights,
gating_output, topk_ids,
renormalize, gating_output,
) renormalize,
)
elif scoring_func == "sigmoid":
topk_sigmoid(
topk_weights,
topk_ids,
gating_output,
renormalize,
correction_bias,
)
else:
raise ValueError(f"Invalid scoring function: {scoring_func}")
topk_ids = topk_ids_logical_to_physical(topk_ids, expert_location_dispatch_info) topk_ids = topk_ids_logical_to_physical(topk_ids, expert_location_dispatch_info)
_mask_topk_ids_padded_region(topk_ids, num_token_non_padded) _mask_topk_ids_padded_region(topk_ids, num_token_non_padded)
@@ -916,6 +940,7 @@ def select_experts(
fused_shared_experts_scaling_factor = ( fused_shared_experts_scaling_factor = (
topk_config.fused_shared_experts_scaling_factor topk_config.fused_shared_experts_scaling_factor
) )
scoring_func = topk_config.scoring_func
router_logits, correction_bias = ( router_logits, correction_bias = (
expert_location_dispatch.transform_select_experts_inputs( expert_location_dispatch.transform_select_experts_inputs(
@@ -972,6 +997,7 @@ def select_experts(
topk=num_routed_topk if _use_aiter else top_k, topk=num_routed_topk if _use_aiter else top_k,
renormalize=renormalize, renormalize=renormalize,
correction_bias=correction_bias, correction_bias=correction_bias,
scoring_func=scoring_func,
) )
elif custom_routing_function is None: elif custom_routing_function is None:
assert not apply_routed_scaling_factor_on_output, "Not implemented" assert not apply_routed_scaling_factor_on_output, "Not implemented"
@@ -981,8 +1007,10 @@ def select_experts(
gating_output=router_logits, gating_output=router_logits,
topk=num_routed_topk if _use_aiter else top_k, topk=num_routed_topk if _use_aiter else top_k,
renormalize=renormalize, renormalize=renormalize,
correction_bias=correction_bias,
num_token_non_padded=num_token_non_padded, num_token_non_padded=num_token_non_padded,
expert_location_dispatch_info=expert_location_dispatch_info, expert_location_dispatch_info=expert_location_dispatch_info,
scoring_func=scoring_func,
) )
else: else:
assert ( assert (
-3
View File
@@ -167,9 +167,6 @@ class MiniMaxM2MoE(nn.Module):
top_k=config.num_experts_per_tok, top_k=config.num_experts_per_tok,
renormalize=True, renormalize=True,
scoring_func=config.scoring_func, scoring_func=config.scoring_func,
use_grouped_topk=True, # TODO: Use "grouped top-k" flag only for hardcoded sigmoid scoring
num_expert_group=1,
topk_group=1,
correction_bias=self.e_score_correction_bias, correction_bias=self.e_score_correction_bias,
routed_scaling_factor=1.0, routed_scaling_factor=1.0,
) )