@@ -234,6 +234,18 @@ def _resolve_enable_fused_hc(config: PretrainedConfig) -> bool:
234234 return bool (getattr (config , "enable_fused_hc" , True ))
235235
236236
237+ def _resolve_skip_premoe_allreduce () -> bool :
238+ """Resolve whether to skip the redundant PRE_MOE_FUSION allreduce.
239+
240+ When enabled (default), the RMSNorm is folded into hc_ffn.fused_hc's
241+ epilogue and the allreduce in forward_MoE is skipped — the data is
242+ already full after attention's internal o_b_proj allreduce.
243+ Set TRTLLM_DSV4_SKIP_PREMOE_ALLREDUCE=0 for ablation (baseline behavior).
244+ """
245+ env = os .environ .get ("TRTLLM_DSV4_SKIP_PREMOE_ALLREDUCE" , "1" )
246+ return env not in ("0" , "false" , "False" )
247+
248+
237249def _copy_deepseek_v4_fused_a_weight_scale (
238250 module : Linear , fused_a : torch .Tensor , fused_a_scale : torch .Tensor
239251) -> None :
@@ -1860,6 +1872,13 @@ def __init__(
18601872 # layers already take). Env var TRTLLM_MHC_ENABLE_FUSED_HC overrides the
18611873 # config attr (set to "0" to force-disable for validation/rollback).
18621874 self .enable_fused_hc = _resolve_enable_fused_hc (config )
1875+ # Skip-premoe-allreduce: when fused_hc is active AND PRE_MOE_FUSION is
1876+ # on, fold post_attention_layernorm into hc_ffn.fused_hc and skip the
1877+ # redundant allreduce in forward_MoE (the data is already full after
1878+ # attention's internal o_b_proj allreduce).
1879+ self .skip_premoe_allreduce = (
1880+ _resolve_skip_premoe_allreduce () and self .enable_fused_hc
1881+ )
18631882 self .next_layer_layernorm : RMSNorm = None
18641883 # Finalized in DeepseekV4ForCausalLM.post_load_weights once the full layer
18651884 # list is visible: a layer may defer its hc_ffn.post_mapping only if
@@ -2000,11 +2019,26 @@ def forward(
20002019 if spec_metadata is not None and spec_metadata .is_layer_capture (self .layer_idx ):
20012020 self .fusion_config .POST_MOE_FUSION = False
20022021 if self .enable_fused_hc :
2022+ # When skip_premoe_allreduce is active, fold post_attention_layernorm
2023+ # into fused_hc so layer_input emerges already RMSNorm-normalized.
2024+ # This lets us skip the redundant allreduce+norm in forward_MoE.
2025+ _norm_w = (
2026+ self .post_attention_layernorm .weight
2027+ if self .skip_premoe_allreduce and self .fusion_config .PRE_MOE_FUSION
2028+ else None
2029+ )
2030+ _norm_eps = (
2031+ self .post_attention_layernorm .variance_epsilon
2032+ if _norm_w is not None
2033+ else 0.0
2034+ )
20032035 residual , post_mix , comb_mix , layer_input = self .hc_ffn .fused_hc (
20042036 x_prev = x_attn ,
20052037 residual_prev = residual ,
20062038 post_mix_prev = post_mix ,
20072039 comb_mix_prev = comb_mix ,
2040+ norm_weight = _norm_w ,
2041+ norm_eps = _norm_eps ,
20082042 )
20092043 else :
20102044 # Break fused_hc into post_mapping and pre_mapping as separate ops.
@@ -2104,18 +2138,24 @@ def _run_MoE(hidden_states, hidden_states_fp4, do_finalize, input_ids):
21042138 )
21052139
21062140 if self .fusion_config .PRE_MOE_FUSION :
2107- # In DeepSeek-V4 the external residual connection is handled by mHC
2108- # (hc_ffn.post_mapping), so there is no residual to add here.
2109- # Use fused allreduce + RMSNorm (no residual addition).
2110- hidden_states = self .allreduce (
2111- hidden_states ,
2112- all_reduce_params = AllReduceParams (
2113- fusion_op = AllReduceFusionOp .RMS_NORM ,
2114- norm_weight = self .post_attention_layernorm .weight ,
2115- eps = self .post_attention_layernorm .variance_epsilon ,
2116- trigger_completion_at_end = False ,
2117- ),
2118- )
2141+ if self .skip_premoe_allreduce :
2142+ # Optimization: RMSNorm was already folded into hc_ffn.fused_hc's
2143+ # epilogue, and the data is already full (attention's o_b_proj
2144+ # allreduced it). Skip the redundant allreduce+norm entirely.
2145+ pass
2146+ else :
2147+ # Baseline: fused allreduce + RMSNorm (no residual addition).
2148+ # In DeepSeek-V4 the external residual connection is handled by
2149+ # mHC (hc_ffn.post_mapping), so there is no residual to add here.
2150+ hidden_states = self .allreduce (
2151+ hidden_states ,
2152+ all_reduce_params = AllReduceParams (
2153+ fusion_op = AllReduceFusionOp .RMS_NORM ,
2154+ norm_weight = self .post_attention_layernorm .weight ,
2155+ eps = self .post_attention_layernorm .variance_epsilon ,
2156+ trigger_completion_at_end = False ,
2157+ ),
2158+ )
21192159 else :
21202160 # No fusion: just normalize.
21212161 hidden_states = self .post_attention_layernorm (hidden_states )
0 commit comments