40 layers › 2 groups of 6 layers › Source layer, pairs pooled › Compressed sparse attention
Compressed latent
×tensorlatent · 747
One 512-feature vector for every two tokens, before rotation; the indexer makes its keys from it.
- shape
- [B batch, T/2 compressed positions, 512 d_h]
Sources
Contextual evidence from Compressor, pairs pooled
The compressor makes the compressed key–value latents: at ratio 1 one projection and a norm per token; above 1 a per-feature softmax over each group of tokens, with an unfinished group kept for the next call.
compressor · deepseek-ai/DeepSeek-V4.1-Flash / inference/model.py
Pinned revision 2cba9e42aa02 ↗ · lines 429–485
Read code excerpt
class Compressor(nn.Module):
"""Pools `compress_ratio` consecutive tokens into one KV latent with a learned softmax gate.
Returns the latent before RoPE, or None while a group is still filling up -- so during decode it
only yields every `compress_ratio` steps, holding the partial group in `kv_state`/`score_state`.
Pre-RoPE is deliberate: the indexer needs the unrotated form, so Attention rotates afterwards.
"""
def __init__(self, args: ModelArgs, layer_id: int):
super().__init__()
compress_ratio = args.compress_ratios[layer_id]
head_dim = args.head_dim
self.compress_ratio = compress_ratio
self.head_dim = head_dim
self.norm = RMSNorm(head_dim, args.norm_eps)
# ratio 1 is a plain projection, so it stays in the checkpoint's bf16; the softmax pooling
# above ratio 1 runs in fp32, so those weights are promoted to fp32 to match
self.wkv = Linear(args.dim, head_dim, dtype=torch.float32 if compress_ratio > 1 else torch.bfloat16)
if compress_ratio > 1:
self.wgate = Linear(args.dim, head_dim, dtype=torch.float32)
# tail of an incomplete group, carried across decode steps
self.kv_state: torch.Tensor
self.score_state: torch.Tensor
state_shape = (args.max_batch_size, compress_ratio, head_dim)
self.register_buffer("kv_state", torch.zeros(state_shape, dtype=torch.float32), persistent=False)
self.register_buffer(
"score_state", torch.full(state_shape, -torch.inf, dtype=torch.float32), persistent=False
)
def forward(self, x: torch.Tensor, start_pos: int) -> torch.Tensor | None:
bsz, seqlen, _ = x.size()
ratio, dtype = self.compress_ratio, x.dtype
if ratio == 1: # one token per group: nothing to pool, so no gate and no fp32
return self.norm(self.wkv(x))
x = x.float()
kv, score = self.wkv(x), self.wgate(x)
if start_pos == 0:
should_compress = seqlen >= ratio
remainder = seqlen % ratio
cutoff = seqlen - remainder
if remainder: # trailing partial group waits in the state
kv, self.kv_state[:bsz, :remainder] = kv.split([cutoff, remainder], dim=1)
score, self.score_state[:bsz, :remainder] = score.split([cutoff, remainder], dim=1)
kv = kv.unflatten(1, (-1, ratio))
score = score.unflatten(1, (-1, ratio))
kv = (kv * score.softmax(dim=2)).sum(dim=2)
else: # one token per step: fill a slot, and pool only when the group just completed
should_compress = (start_pos + 1) % ratio == 0
slot = start_pos % ratio
self.kv_state[:bsz, slot] = kv.squeeze(1)
self.score_state[:bsz, slot] = score.squeeze(1)
if should_compress:
kv = (self.kv_state[:bsz] * self.score_state[:bsz].softmax(dim=1)).sum(dim=1, keepdim=True)
if not should_compress:
return None
return self.norm(kv.to(dtype))Contextual evidence from Compressor, pairs pooled
RMSNorm divides by the root mean square over the features, computed in float32, and multiplies by a learned gain.
rmsnorm · deepseek-ai/DeepSeek-V4.1-Flash / inference/model.py
Pinned revision 2cba9e42aa02 ↗ · lines 281–293
Read code excerpt
class RMSNorm(nn.Module):
def __init__(self, dim: int, eps: float = 1e-6):
super().__init__()
self.dim = dim
self.eps = eps
self.weight = nn.Parameter(torch.ones(dim))
def forward(self, x: torch.Tensor):
dtype = x.dtype
x = x.float()
var = x.square().mean(-1, keepdim=True)
x = x * torch.rsqrt(var + self.eps)
return (self.weight * x).to(dtype)Contextual evidence from Rotate, round to FP4
A key–value source compresses its own input and writes the shared cache; an index source runs its indexer before the latent is rotated; every other layer reads what the nearest earlier source published.
attention-compress · deepseek-ai/DeepSeek-V4.1-Flash / inference/model.py
Pinned revision 2cba9e42aa02 ↗ · lines 722–763
Read code excerpt
def _compress_topk_idxs(self, x, qr, latent, start_pos, offset, compress_len):
"""Which compressed positions each query attends to. Index sources run their own indexer;
the layers in between reuse the result their source published."""
if not self.is_index_source:
return shared_attn.topk_idxs
bsz, seqlen, _ = x.size()
if compress_len == 0:
idxs = torch.empty(bsz, seqlen, 0, dtype=torch.int32, device=x.device)
else:
assert self.indexer is not None
if self.indexer.freqs_cis is None:
self.indexer.freqs_cis = self.freqs_cis
idxs = self.indexer(x, qr, latent, start_pos, offset)
shared_attn.topk_idxs = idxs
return idxs
def _compress_kv(self, x, qr, start_pos, offset):
"""The shared compressed KV and the compressed positions every query may attend to. This
layer compresses its own KV only when it is a source; otherwise it just reads the cache."""
bsz, seqlen, _ = x.size()
ratio = self.compress_ratio
compress_len = (start_pos + seqlen) // ratio
latent = None
if self.is_kv_source:
latent = self.compressor(x, start_pos)
shared_attn.compress_kv = self.compress_kv_cache
# the indexer needs the latent before RoPE, so it runs before the cache is written
idxs = self._compress_topk_idxs(x, qr, latent, start_pos, offset, compress_len)
if 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)
)
apply_rotary_emb(latent[..., -self.rope_head_dim :], freqs)
# Compressed KV uses groups of 16 with E4M3 scales; the indexer uses 32 with E8M0.
fp4_act_quant(latent, 16, True, scale_dtype=torch.float8_e4m3fn)
self.compress_kv_cache[:bsz, start_pos // ratio : start_pos // ratio + latent.size(1)] = latent
# read after the write, so this does not depend on the slice aliasing the cache
return shared_attn.compress_kv[:bsz, :compress_len], idxsContextual evidence from Rotate, round to FP4
Rotary frequencies with the YaRN scaling above the original context, and the rotation of adjacent feature pairs, with an inverse.
rope · deepseek-ai/DeepSeek-V4.1-Flash / inference/model.py
Pinned revision 2cba9e42aa02 ↗ · lines 369–406
Read code excerpt
def precompute_freqs_cis(dim, seqlen, original_seq_len, base, factor, beta_fast, beta_slow) -> torch.Tensor:
"""Rotary frequencies as complex exponentials, one row per position.
With original_seq_len > 0 this applies YaRN: dimensions whose wavelength already fits inside the
training context keep their frequency, those far beyond it are divided by `factor`, and the
`beta_fast`..`beta_slow` band in between is faded across with a linear ramp.
"""
freqs = 1.0 / (base ** (torch.arange(0, dim, 2, dtype=torch.float32) / dim))
if original_seq_len > 0:
# the dim whose wavelength completes `rotations` turns over the training context
def corrected_dim(rotations):
return dim * math.log(original_seq_len / (rotations * 2 * math.pi)) / (2 * math.log(base))
low = max(math.floor(corrected_dim(beta_fast)), 0)
high = min(math.ceil(corrected_dim(beta_slow)), dim - 1)
ramp = ((torch.arange(dim // 2, dtype=torch.float32) - low) / max(high - low, 1e-3)).clamp(0, 1)
smooth = 1 - ramp
freqs = freqs / factor * (1 - smooth) + freqs * smooth
freqs = torch.outer(torch.arange(seqlen), freqs)
return torch.polar(torch.ones_like(freqs), freqs)
def apply_rotary_emb(x: torch.Tensor, freqs_cis: torch.Tensor, inverse: bool = False) -> torch.Tensor:
"""Rotate `x` in place, taking adjacent element pairs as complex numbers. Accepts [b, s, d] and
[b, s, h, d]; `inverse` conjugates the rotation, which is how the attention output gets the
query's rotation removed again so the cache can stay in one shared rotated form."""
y = x
x = torch.view_as_complex(x.float().unflatten(-1, (-1, 2)))
if inverse:
freqs_cis = freqs_cis.conj()
if x.ndim == 3:
freqs_cis = freqs_cis.view(1, x.size(1), x.size(-1))
else:
freqs_cis = freqs_cis.view(1, x.size(1), 1, x.size(-1))
x = torch.view_as_real(x * freqs_cis).flatten(-2)
y.copy_(x)
return yContextual evidence from Index keys
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()