[KDA] Add target_verify support for speculative decoding (#26888)

Co-authored-by: yuyanqi <yuyanqi@meituan.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Xinyuan Tong <xinyuantong.cs@gmail.com>
This commit is contained in:
yyqjwyy
2026-07-25 19:52:44 +08:00
committed by GitHub
co-authored by yuyanqi Claude Opus 4.6 Xinyuan Tong
parent 7c4b22fae5
commit a678a42033
6 changed files with 701 additions and 4 deletions
@@ -403,6 +403,11 @@ class KDAAttnBackend(MambaAttnBackendBase):
ssm_states = mamba_cache_params.temporal
# Normal extend path
if forward_batch.extend_prefix_lens is None:
raise RuntimeError(
"extend_prefix_lens cannot be None in non-TARGET_VERIFY mode."
)
has_initial_state = forward_batch.extend_prefix_lens > 0
if self.forward_metadata.has_mamba_track_mask:
@@ -381,6 +381,34 @@ class MambaPool:
intermediate_ssm: Optional[torch.Tensor]
intermediate_conv_window: List[torch.Tensor]
def _detect_conv_window_axis(
self, conv_state_shape: List[Tuple[int, int]], win_len: int
) -> int:
"""Prefer GDN's trailing axis when both match; mixed layer layouts cannot
share one overlapping conv-window buffer.
"""
axis = None
for conv_shape in conv_state_shape:
if conv_shape[-1] == win_len:
shape_axis = len(conv_shape) - 1
elif conv_shape[0] == win_len:
shape_axis = 0
else:
raise ValueError(
f"conv_state shape {conv_shape} has no axis of length "
f"conv_kernel-1={win_len}; cannot build the deduplicated "
"sliding-window conv-intermediate view."
)
if axis is None:
axis = shape_axis
elif axis != shape_axis:
raise ValueError(
"inconsistent conv-window axis across conv shapes "
f"{conv_state_shape}; a single conv_window_axis cannot serve "
"mixed layouts."
)
return axis
def _allocate_deduplicated_conv_window(
self,
*,
@@ -676,6 +704,10 @@ class MambaPool:
)
self._intermediate_conv_window_phys = []
if dedup_conv_window:
win_len = cache_params.shape.conv_kernel - 1
self.conv_window_axis = self._detect_conv_window_axis(
conv_state_shape, win_len
)
intermediate_conv_window_cache = []
for conv_shape in conv_state_shape:
phys, view = self._allocate_deduplicated_conv_window(
+6 -4
View File
@@ -382,10 +382,12 @@ class KimiDeltaAttention(nn.Module):
hidden_states
)
# For prefill: raw gate is passed to chunk_kda_fwd, which fuses gate
# activation with chunk_local_cumsum (kda_gate_chunk_cumsum kernel).
# For decode: gate activation is handled inside fused_recurrent kernel.
if not forward_batch.forward_mode.is_decode():
# Prefill passes raw gates to chunk KDA; decode and target-verify kernels
# apply the activation internally.
if (
not forward_batch.forward_mode.is_decode()
and not forward_batch.forward_mode.is_target_verify()
):
forget_gate = forget_gate.unflatten(
-1, (-1, self.head_dim)
) # [T, H*K] -> [T, H, K]