[Fix] Honor FlashMLA natural-log LSE in DCP reduction (#33065)

This commit is contained in:
EchO
2026-08-03 19:55:52 -07:00
committed by GitHub
parent 91fae8a72c
commit 1e64fc1563
4 changed files with 63 additions and 9 deletions
@@ -202,6 +202,7 @@ def _correct_attn_cp_out_kernel(
lse_idx,
HEAD_DIM: tl.constexpr,
N_ROUNDED: tl.constexpr,
IS_LSE_BASE_ON_E: tl.constexpr,
):
"""
Apply the all-gathered lses to correct each local rank's attention
@@ -242,9 +243,9 @@ def _correct_attn_cp_out_kernel(
lse_max = tl.max(lse, axis=0)
lse_max = tl.where(lse_max == neg_inf, 0.0, lse_max)
lse = lse - lse_max
lse_exp = tl.exp2(lse)
lse_exp = tl.exp(lse) if IS_LSE_BASE_ON_E else tl.exp2(lse)
lse_acc = tl.sum(lse_exp, axis=0)
final_lse = tl.log2(lse_acc) + lse_max
final_lse = (tl.log(lse_acc) if IS_LSE_BASE_ON_E else tl.log2(lse_acc)) + lse_max
# Compute correction factor
lse_offset = lse_idx * lses_stride_N + b_i32 * lses_stride_B + h_i32 * lses_stride_H
@@ -255,7 +256,7 @@ def _correct_attn_cp_out_kernel(
neg_inf,
lse_diff,
)
factor = tl.exp2(lse_diff)
factor = tl.exp(lse_diff) if IS_LSE_BASE_ON_E else tl.exp2(lse_diff)
# Store final LSE
tl.store(vlse_ptr + b_i32 * lses_stride_B + h_i32 * lses_stride_H, final_lse)
@@ -298,6 +299,7 @@ def correct_attn_out(
cp_rank: int,
ctx: Optional[CPTritonContext],
new_output: torch.Tensor = None,
is_lse_base_on_e: bool = False,
) -> tuple[torch.Tensor, torch.Tensor]:
"""Correct the attention output using the all-gathered lses.
@@ -361,7 +363,11 @@ def correct_attn_out(
no_sD,
cp_rank,
)
const_args = {"HEAD_DIM": D, "N_ROUNDED": N}
const_args = {
"HEAD_DIM": D,
"N_ROUNDED": N,
"IS_LSE_BASE_ON_E": is_lse_base_on_e,
}
ctx.call_kernel(_correct_attn_cp_out_kernel, grid, *regular_args, **const_args)
return new_output, lse
+12 -2
View File
@@ -113,11 +113,16 @@ def cp_lse_ag_out_rs_mla(
cp_attn_lse: torch.Tensor,
cp_group: GroupCoordinator,
ctx: Optional[CPTritonContext] = None,
is_lse_base_on_e: bool = False,
):
"""Merge DCP partial attention outputs via Triton correction (PR #14194).
"""Merge DCP partial attention outputs with the LSE's actual log base.
cp_attn_out: [ B, H, D ]
cp_attn_lse: [ B, H ]
FlashInfer MLA returns base-2 LSE, while FlashMLA returns natural-log LSE.
The correction kernel must use the matching exp/log pair or it computes
incorrect cross-rank softmax weights.
"""
if cp_group.world_size == 1:
return cp_attn_out
@@ -133,7 +138,12 @@ def cp_lse_ag_out_rs_mla(
cp_attn_lse = cp_attn_lse.to(torch.float32)
lses = _ag_lse(cp_attn_lse, cp_group)
out, _ = correct_attn_out(
cp_attn_out, lses, cp_group.rank_in_group, ctx, new_output
cp_attn_out,
lses,
cp_group.rank_in_group,
ctx,
new_output,
is_lse_base_on_e=is_lse_base_on_e,
)
out = cp_group.reduce_scatter_along_dim(out, dim=0)
return out.to(cp_attn_out.dtype)
@@ -111,6 +111,12 @@ def _is_dcp_mla_decode_phase(forward_batch: ForwardBatch) -> bool:
)
def _is_mla_dcp_lse_base_on_e(attention_backend: Optional[str]) -> bool:
# FlashMLA exposes natural-log softmax LSE. FlashInfer MLA and the other
# currently supported MLA DCP decode backends expose base-2 LSE.
return attention_backend == "flashmla"
if _is_cuda:
from sglang.kernels.ops.gemm import bmm_fp8
@@ -1030,19 +1036,22 @@ class DeepseekMLAForwardMixin:
self.kv_lora_rank,
)
dcp_comm_backend = get_parallel().dcp_comm_backend
is_lse_base_on_e = _is_mla_dcp_lse_base_on_e(self.current_attention_backend)
if dcp_comm_backend in ("a2a", "fi_a2a"):
# A2A exchange of head partials + LSE, then local Triton combine.
# MLA decode LSE is base-2 (FlashInfer-MLA/FlashMLA) -> base_on_e=False.
attn_output = dcp_a2a_lse_reduce(
attn_output.contiguous(),
lse.contiguous(),
get_parallel().dcp_group,
is_lse_base_on_e=False,
is_lse_base_on_e=is_lse_base_on_e,
comm_backend=dcp_comm_backend,
)
else:
attn_output = cp_lse_ag_out_rs_mla(
attn_output, lse, get_parallel().dcp_group
attn_output,
lse,
get_parallel().dcp_group,
is_lse_base_on_e=is_lse_base_on_e,
)
attn_output = attn_output.transpose(0, 1)
attn_output = attn_output.view(-1, self.num_local_heads, self.kv_lora_rank)