[Perf] Fuse the glm5_next mHC attn->MLP boundary (#39200)

Co-authored-by: mmangkad <mohammad.angkad@radixark.ai>
This commit is contained in:
Mohammad Miadh Angkad
2026-09-20 16:20:37 -07:00
committed by GitHub
co-authored by mmangkad
parent 983e643854
commit 2fa6b94e34
3 changed files with 162 additions and 3 deletions
+21 -1
View File
@@ -72,6 +72,7 @@ class MHCState:
hc_attn_pre: Callable
hc_ffn_pre: Callable
hc_post: Callable
hc_ffn_post_pre: Optional[Callable] = None
h_res: Optional[torch.Tensor] = None
h_post: Optional[torch.Tensor] = None
@@ -94,9 +95,26 @@ class MHCState:
def attn_to_mlp(
self, hidden_states, residual, out_norm: Optional[torch.nn.Module] = None
):
out_norm_weight, out_norm_eps = self._resolve_out_norm(out_norm)
if self.hc_ffn_post_pre is not None and hidden_states.shape[0] != 0:
# Returns None when it declines -- no fused kernel for this platform
# or shape, or a shape the fusion is slower at -- and the chain runs.
fused = self.hc_ffn_post_pre(
hidden_states=hidden_states,
residual=residual,
h_res=self.h_res,
h_post=self.h_post,
out_norm_weight=out_norm_weight,
out_norm_eps=out_norm_eps,
)
if fused is not None:
hidden_states, residual, self.h_res, self.h_post, norm_fused = fused
if out_norm is not None and not norm_fused:
hidden_states = out_norm(hidden_states)
return hidden_states, residual
hidden_states = self.hc_post(hidden_states, residual, self.h_res, self.h_post)
residual = hidden_states
out_norm_weight, out_norm_eps = self._resolve_out_norm(out_norm)
hidden_states, self.h_res, self.h_post, norm_fused = self.hc_ffn_pre(
hidden_states, out_norm_weight, out_norm_eps
)
@@ -406,6 +424,7 @@ class MHCLayerCommunicator(LayerCommunicator):
hc_attn_pre: Callable,
hc_ffn_pre: Callable,
hc_post: Callable,
hc_ffn_post_pre: Optional[Callable] = None,
):
self.is_first_layer = is_first_layer
self.mhc = MHCState(
@@ -413,6 +432,7 @@ class MHCLayerCommunicator(LayerCommunicator):
hc_attn_pre=hc_attn_pre,
hc_ffn_pre=hc_ffn_pre,
hc_post=hc_post,
hc_ffn_post_pre=hc_ffn_post_pre,
)
super().__init__(
+61 -1
View File
@@ -76,6 +76,10 @@ from sglang.srt.model_loader.weight_utils import (
default_weight_loader,
sharded_weight_loader,
)
from sglang.srt.models.deepseek_common.amd.deepseek_v4_fused_mhc import (
apply_mhc_post_pre_boundary,
is_cross_layer_mhc_fusion_enabled,
)
from sglang.srt.models.deepseek_common.deepseek_weight_loader import (
DeepseekV2WeightLoaderMixin,
)
@@ -124,6 +128,15 @@ if _use_aiter_gfx95:
logger = logging.getLogger(__name__)
# Matches DeepSeek-V4's _MHC_POST_MULT_VALUE; the fused and unfused boundaries
# must agree on it.
_MHC_POST_MULT_VALUE = 2.0
# Conservative cap, not the crossover: at GLM-5.3-Flash's hc_mult=4 and
# hidden_size=4096 the fusion wins to 16 tokens and reaches parity at 24, with
# 17-23 unmeasured. Past it the pre-norm GEMM drops mhc_pre's split-K kernel.
_MHC_FUSED_BOUNDARY_MAX_TOKENS = 16
@torch.compile
def swiglu_clamped(y: torch.Tensor, limit: float):
@@ -788,6 +801,13 @@ class Glm5NextDecoderLayer(nn.Module):
hc_attn_pre=self.hc_attn_pre,
hc_ffn_pre=self.hc_ffn_pre,
hc_post=self.hc_post,
# Resolved once: env and platform are frozen after startup,
# and None keeps the dispatch off the per-boundary path.
hc_ffn_post_pre=(
self.hc_ffn_post_pre
if is_cross_layer_mhc_fusion_enabled()
else None
),
)
self.layer_communicator = MHCLayerCommunicator(
**shared_kwargs,
@@ -808,7 +828,7 @@ class Glm5NextDecoderLayer(nn.Module):
rms_eps=self.config.rms_norm_eps,
hc_eps=self.config.hc_eps,
sinkhorn_iters=self.config.hc_sinkhorn_iters,
post_mult_value=2.0,
post_mult_value=_MHC_POST_MULT_VALUE,
hc_norm_weight=None,
out_norm_weight=out_norm_weight,
out_norm_eps=out_norm_eps,
@@ -834,6 +854,46 @@ class Glm5NextDecoderLayer(nn.Module):
out_norm_eps,
)
def hc_ffn_post_pre(
self, hidden_states, residual, h_res, h_post, out_norm_weight, out_norm_eps
):
# Fuses hc_post into the pre-norm GEMM; the mhc_pre big-fuse stage
# still launches separately, so this is two launches instead of three.
assert self.config.mhc, "hc_ffn_post_pre is only valid when config.mhc=True"
num_tokens, hidden_size = hidden_states.shape
if num_tokens > _MHC_FUSED_BOUNDARY_MAX_TOKENS:
return None
hc_mult = self.config.hc_mult
fused = apply_mhc_post_pre_boundary(
layer_input=hidden_states,
residual=residual.view(num_tokens, hc_mult, hidden_size),
post=h_post.view(num_tokens, hc_mult),
comb=h_res.view(num_tokens, hc_mult, hc_mult),
hc_fn=self.hc_ffn_fn,
hc_scale=self.hc_ffn_scale,
hc_base=self.hc_ffn_base,
hc_mult=hc_mult,
rms_eps=self.config.rms_norm_eps,
hc_eps=self.config.hc_eps,
hc_post_mult=_MHC_POST_MULT_VALUE,
sinkhorn_iters=self.config.hc_sinkhorn_iters,
norm_weight=out_norm_weight,
norm_eps=out_norm_eps,
# Matches DeepSeek-V4's two hc_ffn_fn boundaries; the Triton tier's
# parameter is hc_fn_t and this fn has the same [mix_hc, hc_dim] layout.
fn_transpose=True,
)
if fused is None:
return None
next_residual, layer_input, post, comb, norm_fused = fused
return (
layer_input,
next_residual.reshape(num_tokens, -1),
comb.reshape(num_tokens, hc_mult * hc_mult),
post.reshape(num_tokens, hc_mult),
norm_fused,
)
def hc_post(self, hidden_states, residual, h_res, h_post):
assert self.config.mhc, "hc_post is only valid when config.mhc=True"
return _hc_post_fn(