40 layers › 4 layers › Source layer, every token › Compressed sparse attention › Indexer
Keep candidate blocks
×no parametersselect_candidate_blocks(index_score, compress_lens, …) · 569–572
For each query, keep the positions of the 2,048 best blocks of 8 positions, for the indexers of later layers.
- in
- [B batch, 1 positions, 1001 compressed positions]
- out
- [B batch, 1 positions, 1001 compressed positions]
This layer chooses its own positions from the whole range; the candidates only narrow the choice of layers 24, 28, 32, 36 (model.py 503, 573–575).
Codemodel.py 488–580, 583–610
def select_candidate_blocks(
logits: torch.Tensor,
compress_lens: torch.Tensor | int,
topk_blocks: int,
block_size: int,
) -> torch.Tensor:
"""Level one of the two-level top-k: keep the `topk_blocks` highest-scoring blocks per query.
`logits` is [..., n_positions] with positions the query cannot reach already at -inf, which is
what makes a block score of -inf mean "not reachable yet". `compress_lens` is a plain int during
decode, or broadcasts against logits' leading dims during prefill. Returns a bool mask shaped
like `logits`, so the layers consuming it just mask and never think about blocks again.
"""
width = logits.size(-1)
# score each block by its best position; -inf pads the last one out to block_size
scores = F.pad(logits, (0, -width % block_size), value=-torch.inf)
scores = scores.unflatten(-1, (-1, block_size)).amax(dim=-1)
num_blocks = scores.size(-1)
# the block with this query's newest position is only partly filled, so pin it in: it holds the
# most recent tokens but could otherwise be outscored by an older, full block
last = (compress_lens - 1) // block_size
scores = scores.masked_fill(torch.arange(num_blocks, device=logits.device) == last, torch.inf)
top = scores.topk(min(topk_blocks, num_blocks), dim=-1)
# fewer reachable blocks than topk_blocks means leftover picks came back -inf: drop them
keep = torch.zeros_like(scores, dtype=torch.bool).scatter_(-1, top.indices, top.values > -torch.inf)
return keep.repeat_interleave(block_size, dim=-1)[..., :width]class Indexer(torch.nn.Module):
"""Keeps the `index_topk` best compressed positions per query.
A small side attention: fp4 query heads against one shared key per compressed position, scores
rectified then combined by `weights_proj`. With a candidate source this is the second of two
levels; `select_candidate_blocks` is the first.
"""
def __init__(self, args: ModelArgs, layer_id: int):
super().__init__()
# the index keys are derived from the compressor's latent, so only a layer that compresses
# its own KV can produce them; every other indexer reads them from that layer's cache
self.owns_k = layer_id in args.kv_source_layers
self.compress_ratio = args.compress_ratios[layer_id]
self.is_candidate_source = layer_id == args.candidate_source_layer
self.uses_candidates = 0 <= args.candidate_source_layer < layer_id
self.candidate_topk_blocks = args.candidate_topk_blocks
self.candidate_block_size = args.candidate_block_size
self.dim = args.dim
self.n_heads = args.index_n_heads
self.n_local_heads = args.index_n_heads // world_size
self.index_head_dim = args.index_head_dim
self.rope_head_dim = args.rope_head_dim
self.index_topk = args.index_topk
self.q_lora_rank = args.q_lora_rank
self.softmax_scale = self.index_head_dim**-0.5
self.wq_b = ColumnParallelLinear(self.q_lora_rank, self.n_heads * self.index_head_dim)
self.weights_proj = ColumnParallelLinear(self.dim, self.n_heads, dtype=torch.bfloat16)
self.freqs_cis: torch.Tensor | None = None
if self.owns_k:
self.wk = Linear(args.head_dim, self.index_head_dim, dtype=torch.bfloat16)
self.k_norm = RMSNorm(self.index_head_dim, args.norm_eps)
self.k_cache: torch.Tensor
self.register_buffer(
"k_cache",
torch.zeros(args.max_batch_size, args.max_seq_len // self.compress_ratio, args.index_head_dim),
persistent=False,
)
def forward(self, x: torch.Tensor, qr: torch.Tensor, latent: torch.Tensor, start_pos: int, offset: int):
"""`latent` is this layer's RoPE-free compressed latent, None when this layer does not
compress or when its current group is still incomplete. An index-key owner turns it into
index keys here, which has to happen before Attention overwrites that same storage with
the RoPE'd, quantized values."""
assert self.freqs_cis is not None
bsz, seqlen, _ = x.size()
ratio, rd, end_pos = self.compress_ratio, self.rope_head_dim, start_pos + seqlen
# latent is None while a group is still filling up, so there is nothing to publish yet
if self.owns_k and latent is not None:
# a latent stands for the first token of its group, so group j takes position j * ratio
freqs = (
self.freqs_cis[: seqlen - seqlen % ratio : ratio]
if start_pos == 0
else self.freqs_cis[start_pos + 1 - ratio].unsqueeze(0)
)
k = self.k_norm(self.wk(latent))
apply_rotary_emb(k[..., -rd:], freqs)
fp4_act_quant(k, fp4_block_size, True)
self.k_cache[:bsz, start_pos // ratio : start_pos // ratio + k.size(1)] = k
shared_attn.index_k = self.k_cache
q = self.wq_b(qr).unflatten(-1, (self.n_local_heads, self.index_head_dim))
apply_rotary_emb(q[..., -rd:], self.freqs_cis[start_pos:end_pos])
fp4_act_quant(q, fp4_block_size, True)
index_k = shared_attn.index_k[:bsz, : end_pos // ratio]
weights = self.weights_proj(x) * (self.softmax_scale * self.n_heads**-0.5)
index_score = torch.einsum("bshd,btd->bsht", q, index_k)
index_score = (index_score.relu_() * weights.unsqueeze(-1)).sum(dim=2)
if world_size > 1:
dist.all_reduce(index_score)
# how many compressed positions each query can see: a block becomes visible once the query
# has passed its last token. One query per decode step, so there it is just a number.
if start_pos == 0:
compress_lens = (torch.arange(1, seqlen + 1, device=x.device) // ratio).unsqueeze(-1)
index_score.masked_fill_(torch.arange(seqlen // ratio, device=x.device) >= compress_lens, -torch.inf)
else:
compress_lens = end_pos // ratio
if self.is_candidate_source:
shared_attn.candidates = select_candidate_blocks(
index_score, compress_lens, self.candidate_topk_blocks, self.candidate_block_size
)
elif self.uses_candidates:
# level two: score with our own weights, but only inside the source's candidate blocks
index_score = index_score.masked_fill(~shared_attn.candidates, -torch.inf)
# top-k by score, re-sorted into position order; unreachable -> -1, rest shifted by offset
topk = min(self.index_topk, end_pos // ratio)
idxs = index_score.topk(topk, dim=-1, sorted=False).indices.sort(dim=-1).values
return torch.where(idxs < compress_lens, idxs + offset, -1).int()Sources2
Direct evidence
Candidate blocks: positions in blocks of 8, a block scored by its best position, the block of the newest visible position always kept, the best 2,048 blocks kept.
candidates · deepseek-ai/DeepSeek-V4.1-Flash / inference/model.py
Pinned revision 2cba9e42aa02 ↗ · lines 583–610
Read code excerpt
def select_candidate_blocks(
logits: torch.Tensor,
compress_lens: torch.Tensor | int,
topk_blocks: int,
block_size: int,
) -> torch.Tensor:
"""Level one of the two-level top-k: keep the `topk_blocks` highest-scoring blocks per query.
`logits` is [..., n_positions] with positions the query cannot reach already at -inf, which is
what makes a block score of -inf mean "not reachable yet". `compress_lens` is a plain int during
decode, or broadcasts against logits' leading dims during prefill. Returns a bool mask shaped
like `logits`, so the layers consuming it just mask and never think about blocks again.
"""
width = logits.size(-1)
# score each block by its best position; -inf pads the last one out to block_size
scores = F.pad(logits, (0, -width % block_size), value=-torch.inf)
scores = scores.unflatten(-1, (-1, block_size)).amax(dim=-1)
num_blocks = scores.size(-1)
# the block with this query's newest position is only partly filled, so pin it in: it holds the
# most recent tokens but could otherwise be outscored by an older, full block
last = (compress_lens - 1) // block_size
scores = scores.masked_fill(torch.arange(num_blocks, device=logits.device) == last, torch.inf)
top = scores.topk(min(topk_blocks, num_blocks), dim=-1)
# fewer reachable blocks than topk_blocks means leftover picks came back -inf: drop them
keep = torch.zeros_like(scores, dtype=torch.bool).scatter_(-1, top.indices, top.values > -torch.inf)
return keep.repeat_interleave(block_size, dim=-1)[..., :width]Direct evidence
The indexer scores every compressed position for every query with few small heads against one shared key, masks what the query may not see, and keeps the best 512; the candidate source also publishes its candidate blocks, and later indexers score inside them.
indexer · deepseek-ai/DeepSeek-V4.1-Flash / inference/model.py
Pinned revision 2cba9e42aa02 ↗ · lines 488–580
Read code excerpt
class Indexer(torch.nn.Module):
"""Keeps the `index_topk` best compressed positions per query.
A small side attention: fp4 query heads against one shared key per compressed position, scores
rectified then combined by `weights_proj`. With a candidate source this is the second of two
levels; `select_candidate_blocks` is the first.
"""
def __init__(self, args: ModelArgs, layer_id: int):
super().__init__()
# the index keys are derived from the compressor's latent, so only a layer that compresses
# its own KV can produce them; every other indexer reads them from that layer's cache
self.owns_k = layer_id in args.kv_source_layers
self.compress_ratio = args.compress_ratios[layer_id]
self.is_candidate_source = layer_id == args.candidate_source_layer
self.uses_candidates = 0 <= args.candidate_source_layer < layer_id
self.candidate_topk_blocks = args.candidate_topk_blocks
self.candidate_block_size = args.candidate_block_size
self.dim = args.dim
self.n_heads = args.index_n_heads
self.n_local_heads = args.index_n_heads // world_size
self.index_head_dim = args.index_head_dim
self.rope_head_dim = args.rope_head_dim
self.index_topk = args.index_topk
self.q_lora_rank = args.q_lora_rank
self.softmax_scale = self.index_head_dim**-0.5
self.wq_b = ColumnParallelLinear(self.q_lora_rank, self.n_heads * self.index_head_dim)
self.weights_proj = ColumnParallelLinear(self.dim, self.n_heads, dtype=torch.bfloat16)
self.freqs_cis: torch.Tensor | None = None
if self.owns_k:
self.wk = Linear(args.head_dim, self.index_head_dim, dtype=torch.bfloat16)
self.k_norm = RMSNorm(self.index_head_dim, args.norm_eps)
self.k_cache: torch.Tensor
self.register_buffer(
"k_cache",
torch.zeros(args.max_batch_size, args.max_seq_len // self.compress_ratio, args.index_head_dim),
persistent=False,
)
def forward(self, x: torch.Tensor, qr: torch.Tensor, latent: torch.Tensor, start_pos: int, offset: int):
"""`latent` is this layer's RoPE-free compressed latent, None when this layer does not
compress or when its current group is still incomplete. An index-key owner turns it into
index keys here, which has to happen before Attention overwrites that same storage with
the RoPE'd, quantized values."""
assert self.freqs_cis is not None
bsz, seqlen, _ = x.size()
ratio, rd, end_pos = self.compress_ratio, self.rope_head_dim, start_pos + seqlen
# latent is None while a group is still filling up, so there is nothing to publish yet
if self.owns_k and latent is not None:
# a latent stands for the first token of its group, so group j takes position j * ratio
freqs = (
self.freqs_cis[: seqlen - seqlen % ratio : ratio]
if start_pos == 0
else self.freqs_cis[start_pos + 1 - ratio].unsqueeze(0)
)
k = self.k_norm(self.wk(latent))
apply_rotary_emb(k[..., -rd:], freqs)
fp4_act_quant(k, fp4_block_size, True)
self.k_cache[:bsz, start_pos // ratio : start_pos // ratio + k.size(1)] = k
shared_attn.index_k = self.k_cache
q = self.wq_b(qr).unflatten(-1, (self.n_local_heads, self.index_head_dim))
apply_rotary_emb(q[..., -rd:], self.freqs_cis[start_pos:end_pos])
fp4_act_quant(q, fp4_block_size, True)
index_k = shared_attn.index_k[:bsz, : end_pos // ratio]
weights = self.weights_proj(x) * (self.softmax_scale * self.n_heads**-0.5)
index_score = torch.einsum("bshd,btd->bsht", q, index_k)
index_score = (index_score.relu_() * weights.unsqueeze(-1)).sum(dim=2)
if world_size > 1:
dist.all_reduce(index_score)
# how many compressed positions each query can see: a block becomes visible once the query
# has passed its last token. One query per decode step, so there it is just a number.
if start_pos == 0:
compress_lens = (torch.arange(1, seqlen + 1, device=x.device) // ratio).unsqueeze(-1)
index_score.masked_fill_(torch.arange(seqlen // ratio, device=x.device) >= compress_lens, -torch.inf)
else:
compress_lens = end_pos // ratio
if self.is_candidate_source:
shared_attn.candidates = select_candidate_blocks(
index_score, compress_lens, self.candidate_topk_blocks, self.candidate_block_size
)
elif self.uses_candidates:
# level two: score with our own weights, but only inside the source's candidate blocks
index_score = index_score.masked_fill(~shared_attn.candidates, -torch.inf)
# top-k by score, re-sorted into position order; unreachable -> -1, rest shifted by offset
topk = min(self.index_topk, end_pos // ratio)
idxs = index_score.topk(topk, dim=-1, sorted=False).indices.sort(dim=-1).values
return torch.where(idxs < compress_lens, idxs + offset, -1).int()