HardKimi K3

Gated MLA

Kimi K3

Hard

Problem

Gated Multi-head Latent Attention compresses each hidden token once and reconstructs keys and values when attention runs. Let hidden states X have shape (B,S,D), let H be the number of heads, let D_h=D/H, and let L be the latent width. The projections produce

Q=XW_q^{\mathsf T}\in\mathbb{R}^{B\times S\times D}.

C=XW_c^{\mathsf T}\in\mathbb{R}^{B\times S\times L}.

K=CW_k^{\mathsf T},\qquad V=CW_v^{\mathsf T},

where both K and V have shape (B,S,D). Split Q, K, and V into H heads of width D_h. For each head, compute

A=\operatorname{softmax}\left(\frac{QK^{\mathsf T}}{\sqrt{D_h}}+M\right),

where M masks later sequence positions when causal mode is enabled and is zero otherwise. These layers use no positional encoding. Concatenate the head contexts into \widetilde{O}\in\mathbb{R}^{B\times S\times D}, then apply the channel gate and output projection:

Y=\left[\operatorname{sigmoid}(XW_g^{\mathsf T})\odot\widetilde{O}\right]W_o^{\mathsf T}.

Return a dictionary with output and latent_cache. The output has shape (B,S,D), and the cache has shape (B,S,L); both preserve the input floating-point dtype and device.

Theory

Gated Multi-head Latent Attention is ordinary global attention with a compact storage path and a learned output gate. Each token is compressed into one latent vector. Keys and values are reconstructed from that latent representation when attention runs, so the model does not need separate full-width cached content for every head.

Start from familiar attention

Attention still follows the usual story. A query describes what a token wants, keys describe what can be matched, and values contain the information returned. For each head, scaled dot-product attention computes

A = \operatorname{softmax}\left(\frac{QK^{\mathsf T}}{\sqrt{D_h}} + M\right)

and the head context is AV. The mask M blocks later positions in causal mode. Softmax is taken over key positions so every query gets a distribution over the tokens it may read.

What changes is how keys and values are produced. Queries come directly from the hidden states, while each token first creates a latent representation

C = XW_c^{\mathsf T}

The latent vector is then expanded in two different ways:

K=CW_k^{\mathsf T}, \qquad V=CW_v^{\mathsf T}

One compressed vector therefore carries the source information needed to reconstruct both keys and values. The function returns this latent sequence as the cache.

Why the latent representation helps

Without compression, storing keys and values means retaining a larger set of features for every earlier token. MLA stores the smaller latent vector instead. The key and value up-projections can recover the representations needed by attention.

For this problem, do not confuse compression with averaging. Every token keeps its own latent vector, and the sequence length remains unchanged. Only the feature width is reduced.

Kimi K3 periodically uses Gated MLA for unrestricted global content interaction. These layers use no explicit positional encoding. The exercise therefore does not add rotary embeddings, learned position vectors, or any other position transformation. Causal order is enforced only by the mask when causal mode is enabled.

Split attention into heads

The projected query, key, and value tensors each have model width. Divide that width evenly across the requested number of heads. Each head performs its own attention calculation using feature width D_h.

The heads must remain independent until their context vectors have been computed. Afterward, place their features back beside each token to recover model width. This is a reshape and transpose operation, not a sum across heads.

The channel-wise output gate

The ungated attention context is multiplied by a gate derived from the original hidden state:

Y = \left[\operatorname{sigmoid}(XW_g^{\mathsf T})\odot\widetilde{O}\right]W_o^{\mathsf T}

Sigmoid gives one number between zero and one for each token channel. A channel with a gate near zero is suppressed, while a gate near one passes through almost unchanged. Because the gate has full model width, different channels of the same token can be controlled differently.

Apply this gate before the final output projection. The projection then mixes the gated channels into the final representation.

A small causal example

Consider three tokens. In causal mode, the first query may attend only to token 1. The second may attend to tokens 1 and 2. The third may attend to all three. Each head produces a lower-triangular attention pattern because later key positions are blocked before softmax.

Suppose one channel of the joined attention context for token 2 is 1.6, and its gate logit is zero. Sigmoid of zero is 0.5, so that channel becomes 0.8 before the output projection. The gate changes what is passed onward without changing the attention probabilities themselves.

In non-causal mode, all three queries may use all three keys. The latent cache is identical in both cases because the cache depends on the hidden states and latent down-projection, not on the mask.

Implementation order

Common mistakes to avoid

Examples

Example 1

Input
hidden_states = [[[2]]], query_projection = [[1]], latent_down_projection = [[1]], key_up_projection = [[1]], value_up_projection = [[1]], output_gate_projection = [[0]], output_projection = [[1]], num_heads = 1, causal = true
Output
{"output": tensor([[[1.0]]]), "latent_cache": tensor([[[2.0]]])}
Explanation
The token is cached as the scalar latent value 2. Single-token attention reads that value, and the output gate scales it by 0.5.

Example 2

Input
hidden states shape (1, 2, 2), latent width = 1, number of heads = 1, causal = True
Output
{"output": tensor of shape (1, 2, 2), "latent_cache": tensor of shape (1, 2, 1)}

Example 3

Input
hidden states shape (1, 3, 2), latent width = 1, number of heads = 2, causal = False
Output
{"output": tensor of shape (1, 3, 2), "latent_cache": tensor of shape (1, 3, 1)}

Hints

  1. Reshape projected tensors to batch, heads, sequence, head width before computing attention.
  2. A causal mask excludes positions above the main diagonal before softmax.
  3. Merge the head outputs back to model width before applying the channel gate and output projection.

Requirements

Constraints

Starter Code

import math
import torch

def gated_mla(hidden_states: torch.Tensor, query_projection: torch.Tensor, latent_down_projection: torch.Tensor, key_up_projection: torch.Tensor, value_up_projection: torch.Tensor, output_gate_projection: torch.Tensor, output_projection: torch.Tensor, num_heads: int, causal: bool = True) -> dict[str, torch.Tensor]:
    """
    Returns a dictionary containing gated attention output and the latent key-value cache.
    """
    pass

Test Cases

CaseMatches
Single token latent cachepublic
Causal two-token attentionpublic
Two heads without causal maskingpublic