Multi-Head Latent Attention: How DeepSeek Compressed the Cache Further

Understand the main idea behind Multi-Head Latent Attention: compact latent storage, projection absorption, and a separate positional key.

Nov 5, 202610 min readFollow

Topics You Will Master

What a learned latent vector stores instead of full keys and values
How projection absorption avoids expanding every cached token
Why DeepSeek MLA keeps a separate position-carrying key
How to count latent-cache memory and compare it with GQA

Day 26 reduced cache size by sharing key/value heads. Could we keep a different view for each query head without storing every expanded key and value?

Multi-Head Latent Attention, or MLA, answers that question with a smaller learned representation. A latent vector is a set of internal numbers that a model learns to use; its entries do not need names such as "noun" or "location." In MLA, one compact vector carries content used to form both keys and values.

The important idea is not simply "compress now, expand the whole cache later." Algebra lets an optimized implementation move some of that expansion into other projections. We will work through that movement with small numbers.

MLA: a Compact Content Cache Plus a Separate Position Key

The content cache stays narrow. A separate positional key preserves the position-dependent part of the score.

Bestseller

LLM Fine-Tuning with Hugging Face: LoRA, QLoRA, PEFT

Fine-tune BERT, T5, ViT, LLaMA-style models and Qwen3-TTS using Hugging Face Transformers, custom datasets, LoRA, QLoRA.

Enroll on Udemy →30 day refund, lifetime access

Start With What Ordinary Attention Saves

At each layer, the hidden state for a token is the vector entering that layer's attention projections. Ordinary multi-head attention makes a key and value for each head and saves them for later queries.

Suppose two heads each have a four-number key and a four-number value. The content cache stores numbers per token per layer. The query is not included because future tokens do not need old queries.

A later query must read the old keys to make weights, then read the old values to make an output. Wider saved representations therefore cost both space and repeated memory reads.

Ordinary Attention Caches a 4-Number K and V for Each of 2 Heads

Our teaching baseline stores sixteen content numbers per token. These are toy dimensions, not a DeepSeek model configuration.

GQA saves fewer KV heads. MLA instead changes the form of the saved content. Those are different restrictions on what the model learns, not interchangeable runtime switches for any existing checkpoint.

Advertisement

Learn a Smaller Shared Representation

A learned down-projection maps the hidden state at token position into a smaller vector:

is a matrix learned during training. The letter names the compressed content, not a probability. For our toy example, let , a column with two numbers.

Each head has transformations that can turn this shared content into its key and value. For one head, write:

and are up-projections: matrices mapping the smaller vector into a wider one. The superscript marks the content part of a key. We will add the position part later.

One Cached Latent, Different Learned Up-Projections for Each Head

The cached content is shared, while different learned matrices can produce different head views.

This is not lossless compression of an arbitrary pre-existing KV cache. Two numbers cannot encode every possible sixteen-number vector without restrictions. The model is trained with this lower-dimensional structure so its attention learns to use the available representation. Whether that preserves useful model quality is an empirical question.

The Direct Form Explains the Meaning

Before optimizing, consider the direct calculation. For one head, choose the teaching matrix:

Multiplying by gives the four-number content key . We have not created four independent stored facts. All four entries are combinations of the same two latent numbers.

A query scores this key with a dot product:

That direct form tells us what the attention score means. But expanding the keys for every past token before every decode step would add work and temporary storage.

Direct Expansion: UK Turns 2 Latent Numbers Into a 4-Number Key

The expanded key is useful for understanding the math. An optimized decoder does not need to build it for every cached token.

Advertisement

Move the Key Projection Into the Query

Matrix multiplication lets us regroup the score without changing its mathematical value:

Read the two sides in words. The left side expands every stored latent into a key, then compares the query with that key. The right side transforms the new query once, then compares that transformed query directly with the stored latents.

For our numbers, . The smaller dot product is , exactly the same score as before.

This regrouping is called projection absorption. A fixed learned matrix can be combined with another projection, so the repeated calculation uses the compact representation. The DeepSeek-V2 paper describes this absorption and the separate position path used by MLA.

Projection Absorption: Moving UK Into the Query Keeps Score 4

Both paths produce score 4. The absorbed path reads the two-number content cache directly.

Why is moving work to the query side useful? At one decode step there is one newest query per head but potentially thousands of past positions. A transformation done for the newest query is not the same cost pattern as expanding every past key.

We can check the identity with NumPy. It handles the small arrays; no model download is needed.

PYTHON
import numpy as np

We define the exact column-vector values above. One-dimensional arrays here represent those vectors, and @ performs matrix multiplication or a vector dot product as appropriate.

PYTHON
latent = np.array([1.0, 2.0])
up_key = np.array([[1., 0.], [0., 1.], [1., 1.], [1., -1.]])
query = np.array([1.0, 0.0, 1.0, 0.0])
direct_score = query @ (up_key @ latent)
absorbed_score = (up_key.T @ query) @ latent
assert np.isclose(direct_score, absorbed_score)

Both scores are 4. We intentionally check the unscaled content dot product, not complete MLA attention. Complete attention also includes position scores, scaling, visibility rules, and softmax.

Move the Value Expansion After the Weighted Sum

The value side has a related identity. Let be the attention weight for past position . The ordinary weighted sum is:

We can first mix the narrow latents, then expand the one mixed result. We do not have to expand every past value separately.

Take two latent vectors, and , with illustrative weights 0.25 and 0.75. Their weighted latent is . If uses the same numeric matrix as our teaching , the resulting four-number value output is .

These weights are chosen to illustrate the value identity. They are not claimed to come from the single score in the preceding example.

Mixing Two Latents Before Expanding Gives the Same Value Output

Linearity lets expansion follow the weighted sum. Head-specific weights still produce head-specific results.

In a complete attention layer, the value up-projection can also combine with that head's contribution to the final output projection. This is why describing MLA only as "rebuild full K and V at every step" misses an important part of its inference design.

Advertisement

Position Rotations Complicate the Absorption

The position information from Day 17 tells attention where tokens occur. Rotary position embeddings, or RoPE, express part of that information by rotating query and key feature pairs. Day 29 will explain those rotations in detail.

The difficulty is algebraic, not simply a risk that compression might forget position. If a position-dependent rotation sits between the key up-projection and the dot product, the transformation is no longer the same fixed matrix for every cached position. It cannot be moved into the newest query in the simple way we just used.

DeepSeek's design separates a content score from a position score. In a simplified one-head notation:

is the querying position and is a key position. names content features. names features carrying rotary position information. The combined score is then scaled and masked before softmax, as in earlier attention lessons.

Content and Position Scores Take Separate Paths, Then Add

The content path can use absorption. The positional path remains available as a separate cached key.

The cache therefore contains more than alone: it also needs the small position-carrying key. Ignoring that extra vector would undercount memory and describe an incomplete attention mechanism.

Count the Cache That Is Actually Stored

Let the shared content latent have width and the separate cached rotary key have width . With layers, saved positions, independent equal-length requests, and bytes per stored number, a simplified uniform-layer count is:

There is no extra factor of two around . One shared content latent supports both key and value calculations. The formula describes this MLA storage layout, not ordinary separate K/V arrays.

For our toy comparison, choose and . At two bytes per number, the stored entry needs bytes per layer-token. Our earlier ordinary-content baseline needed bytes. This illustrates counting, not a measured compression ratio for a named model.

Counting the Stored MLA Entry: Content Latent Plus Rotary Key

Count the arrays that remain in memory, not the wider arrays used in the direct mathematical description.

A fair real-model comparison must use its actual head counts, dimensions, cache dtype, layer types, and implementation. Temporary buffers and model weights are additional costs. A smaller cache alone does not prove a faster complete service.

Advertisement

Sharing Heads and Sharing a Latent Are Different

In MQA, all query heads share one explicit KV head. In GQA, each group of query heads shares an explicit KV head. In MLA, heads can use different transformations of shared compact content, along with the position path.

The difference can be seen with the same two-number latent. One head could project it with , while another uses a different learned matrix. They share the stored input but need not produce identical content keys or attention weights.

Two Heads Read the Same Latent Through Different Learned Matrices

Shared storage does not require identical head computations.

These choices change how a model represents information. We should not take a trained MHA model, replace its cache with two numbers, and expect unchanged output. The architecture and its learned weights must support the compressed form.

Check Your Understanding

Why is the stored latent not a zipped copy of full K and V? The model learns a restricted representation during training rather than losslessly encoding arbitrary full vectors.

Why does query-side absorption help decoding? One new query can be transformed before it reads many saved latents.

Why must our memory formula include the rotary key? The content latent alone does not provide the complete position-dependent score in this design.

Tracing One Cached MLA Entry Through a Decode Step

Compact storage works because the later computation is designed to use it, not because earlier context stops mattering.

Recap

MLA saves shared latent content and a separate position-carrying key. The direct equations can expand content into keys and values, but projection absorption lets an optimized path avoid materializing all those expanded cached vectors.

Day 28 keeps the question of storage but changes its scale. Once thousands of requests own growing caches, where should those entries live in GPU memory?

Found this useful? Keep building with me.

New tutorials every week on YouTube: or go deeper with a full structured course.

Find this tutorial useful?

Subscribe to our YouTube channels for more practical production walk-throughs.

Discussion & Comments