40 layers › 6 layers › Source layer, pairs pooled › Compressed sparse attention › Compressor, pairs pooled
Compressed RMSNorm
×learnedself.norm(…) · 485
Divide each vector by its root mean square and multiply by a learned gain.
- in
- [B batch, T/2 compressed positions, 512 d_h]
- out
- [B batch, T/2 compressed positions, 512 d_h]
- parameters
- 512
ε = 1e-20.
Parameters
512 parameters owned by this component
| Component | Calculation | Parameters |
|---|---|---|
| RMSNorm gain | 512 | |
| Per-instance total | 512 | |
Derived from the pinned reference implementation and configuration; equal to the element counts of the checkpoint’s own tensors on the text path. The quantisation scales, the vision encoder and the DSpark blocks are not counted.
Codemodel.py 281–293, 429–485
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)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))Sources2
Direct evidence
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)Direct evidence
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))