Multi-Head Latent Attention (MLA): Mathematical Foundations, Low-Rank KV Compression, Decoupled Rotary Positional Embeddings, and Inference Matrix Absorption

Autoregressive transformer inference in production is fundamentally bounded by memory bandwidth rather than compute capability during the decoding phase. As context lengths scale from 8,000 to 128,000 tokens and beyond, storing and loading the Key-Value (KV) cache across tens of attention layers consumes the vast majority of GPU High-Bandwidth Memory (HBM) and degrades serving throughput. While earlier architectures mitigated this bottleneck via Multi-Query Attention (MQA) or Grouped-Query Atte

13 min
Multi-Head Latent Attention (MLA): Mathematical Foundations, Low-Rank KV Compression, Decoupled Rotary Positional Embeddings, and Inference Matrix Absorption

Autoregressive transformer inference in production is fundamentally bounded by memory bandwidth rather than compute capability during the decoding phase. As context lengths scale from 8,000 to 128,000 tokens and beyond, storing and loading the Key-Value (KV) cache across tens of attention layers consumes the vast majority of GPU High-Bandwidth Memory (HBM) and degrades serving throughput.

While earlier architectures mitigated this bottleneck via Multi-Query Attention (MQA) or Grouped-Query Attention (GQA), these approaches trade away model expressivity by forcing multiple query heads to share a reduced set of key and value heads. Introduced by DeepSeek-AI in DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model (2024) and extended in DeepSeek-V3 Technical Report (2024), Multi-Head Latent Attention (MLA) resolves this compromise. MLA compresses keys and values into a low-rank latent subspace during generation, uses decoupled rotary positional embeddings to preserve relative positional geometry, and mathematically absorbs up-projection matrices directly into query and output projections during inference.

This technical analysis details the mathematical foundations of MLA, derives its decoupled rotary mechanics, examines its algebraic matrix absorption during decoding, and compares its memory footprint and serving economics against MHA, MQA, and GQA.

The KV Cache Memory Bandwidth Bottleneck

In standard multi-head self-attention (Vaswani et al., 2017), generating each new token during autoregressive decoding requires computing scaled dot-product attention against all preceding tokens in the sequence. To avoid recomputing keys and values for past tokens at every generation step, inference engines maintain a KV cache in GPU memory.

Cache Footprint Mechanics

For an autoregressive model with LL layers, nkvn_{kv} key-value heads, head dimension dhd_h, sequence length SS, batch size BB, and numerical precision storing PP bytes per element (such as 2 bytes for FP16/BF16 or 1 byte for FP8), the total memory required by the KV cache is:

MemoryKV=2×B×S×L×nkv×dh×P\text{Memory}_{\text{KV}} = 2 \times B \times S \times L \times n_{kv} \times d_h \times P

Consider a representative frontier architecture with 60 layers, 128 query heads, head dimension dh=128d_h = 128, running at a sequence length of S=128,000S = 128,000 tokens in 16-bit precision:

  • Multi-Head Attention (MHA) (nkv=128n_{kv} = 128): Storing 128 key heads and 128 value heads requires 2×60×128×128×2=3,932,1602 \times 60 \times 128 \times 128 \times 2 = 3,932,160 bytes (3.75 MB) per token. At S=128,000S = 128,000, a single sequence consumes 480 GB of GPU RAM for the KV cache alone, exceeding the capacity of an 80GB NVIDIA H100 or 141GB H200 GPU.
  • Grouped-Query Attention (GQA-8) (nkv=8n_{kv} = 8, as in Llama 3 70B): Compressing to 8 KV heads reduces cache consumption to 2×60×8×128×2=245,7602 \times 60 \times 8 \times 128 \times 2 = 245,760 bytes (240 KB) per token, or 30 GB per sequence at 128K context.
  • Multi-Query Attention (MQA) (nkv=1n_{kv} = 1): Compressing to a single KV head requires 2×60×1×128×2=30,7202 \times 60 \times 1 \times 128 \times 2 = 30,720 bytes (30 KB) per token, or 3.75 GB per sequence at 128K context.

The Expressivity vs. Bandwidth Dilemma

While MQA and GQA reduce memory footprint by factors of 128x and 16x respectively, they introduce a fundamental representational constraint: multiple query heads attend to identical key-value subspaces. During complex multi-hop retrieval, code synthesis, and mathematical reasoning, distinct attention heads often require distinct projection subspaces.

During token generation, the arithmetic intensity (FLOPs per byte transferred) of the attention kernel drops to O(1)O(1), making the memory bus the primary latency bottleneck. MLA was engineered to deliver the serving efficiency of MQA while preserving the full representational power of 128 independent attention heads.

Multi-Head Latent Attention Architecture and Matrix Absorption

Core Architecture of Multi-Head Latent Attention

Multi-Head Latent Attention decomposes the traditional wide key and value projections into a low-rank bottleneck projection paired with a decoupled positional encoding mechanism.

Low-Rank Joint Key-Value Compression

Let htRd\mathbf{h}_t \in \mathbb{R}^d denote the hidden state vector of the tt-th token at a given transformer layer, where dd is the model hidden dimension. Instead of projecting ht\mathbf{h}_t directly into nhn_h independent key and value vectors of dimension dhd_h, MLA down-projects ht\mathbf{h}_t into a compressed latent vector ctKVRdc\mathbf{c}_t^{KV} \in \mathbb{R}^{d_c}:

ctKV=RMSNorm(WDKVht)\mathbf{c}_t^{KV} = \text{RMSNorm}\left(\mathbf{W}_{DKV} \mathbf{h}_t\right)

where:

  • WDKVRdc×d\mathbf{W}_{DKV} \in \mathbb{R}^{d_c \times d} is the down-projection weight matrix.
  • dcnh×dhd_c \ll n_h \times d_h is the latent key-value compression dimension (in DeepSeek-V2 and V3, dc=512d_c = 512, whereas nh×dh=128×128=16,384n_h \times d_h = 128 \times 128 = 16,384).
  • RMSNorm()\text{RMSNorm}(\cdot) stabilizes latent activations prior to subsequent transformations.

During training and prefill phases, the compressed vector ctKV\mathbf{c}_t^{KV} is up-projected into full content key and value matrices:

ktC=WUKctKV,kt,iCRdhC\mathbf{k}_t^C = \mathbf{W}_{UK} \mathbf{c}_t^{KV}, \quad \mathbf{k}_{t, i}^C \in \mathbb{R}^{d_h^C}

vtC=WUVctKV,vt,iCRdv\mathbf{v}_t^C = \mathbf{W}_{UV} \mathbf{c}_t^{KV}, \quad \mathbf{v}_{t, i}^C \in \mathbb{R}^{d_v}

where:

  • WUKR(nhdhC)×dc\mathbf{W}_{UK} \in \mathbb{R}^{(n_h d_h^C) \times d_c} is the key up-projection matrix.
  • WUVR(nhdv)×dc\mathbf{W}_{UV} \in \mathbb{R}^{(n_h d_v) \times d_c} is the value up-projection matrix.
  • i{1,2,,nh}i \in \{1, 2, \dots, n_h\} indexes the attention head.

Low-Rank Query Compression

To reduce activation memory during training and distributed tensor parallelism overhead, MLA also applies low-rank compression to the query vector:

ctQ=RMSNorm(WDQht)\mathbf{c}_t^Q = \text{RMSNorm}\left(\mathbf{W}_{DQ} \mathbf{h}_t\right)

qtC=WUQctQ,qt,iCRdhC\mathbf{q}_t^C = \mathbf{W}_{UQ} \mathbf{c}_t^Q, \quad \mathbf{q}_{t, i}^C \in \mathbb{R}^{d_h^C}

where:

  • WDQRdc×d\mathbf{W}_{DQ} \in \mathbb{R}^{d_c' \times d} down-projects the query into latent dimension dcd_c' (where dc=1536d_c' = 1536).
  • WUQR(nhdhC)×dc\mathbf{W}_{UQ} \in \mathbb{R}^{(n_h d_h^C) \times d_c'} up-projects the latent query to head dimension dhCd_h^C.

The RoPE Incompatibility Problem and Decoupled RoPE

Rotary Position Embeddings (Su et al., 2021) encode relative token positions by applying a coordinate rotation matrix RΘ,t\mathbf{R}_{\Theta, t} directly to the query and key vectors.

Why Standard RoPE Breaks Low-Rank Compression

If standard RoPE were applied directly to the up-projected keys:

kt,i=RΘ,t(WUK,ictKV)\mathbf{k}_{t, i} = \mathbf{R}_{\Theta, t} \left(\mathbf{W}_{UK, i} \mathbf{c}_t^{KV}\right)

the attention logit between query tt and key jj would be:

qt,iTkj,i=(RΘ,tqt,iC)T(RΘ,jWUK,icjKV)=(qt,iC)TRΘ,tTRΘ,jWUK,icjKV\mathbf{q}_{t, i}^T \mathbf{k}_{j, i} = \left(\mathbf{R}_{\Theta, t} \mathbf{q}_{t, i}^C\right)^T \left(\mathbf{R}_{\Theta, j} \mathbf{W}_{UK, i} \mathbf{c}_j^{KV}\right) = (\mathbf{q}_{t, i}^C)^T \mathbf{R}_{\Theta, t}^T \mathbf{R}_{\Theta, j} \mathbf{W}_{UK, i} \mathbf{c}_j^{KV}

Because the rotation matrix RΘ,j\mathbf{R}_{\Theta, j} depends on the absolute position jj, it does not commute with the projection matrix WUK,i\mathbf{W}_{UK, i}:

RΘ,jWUK,iWUK,iRΘ,j\mathbf{R}_{\Theta, j} \mathbf{W}_{UK, i} \neq \mathbf{W}_{UK, i} \mathbf{R}'_{\Theta, j}

If RoPE were entangled with WUK,i\mathbf{W}_{UK, i}, the serving engine would be forced to decompress cjKV\mathbf{c}_j^{KV} into the full (nh×dhC)(n_h \times d_h^C)-dimensional key kj\mathbf{k}_j for every token jj before applying rotation RΘ,j\mathbf{R}_{\Theta, j}. The inference engine would have to cache the expanded keys in HBM, completely negating the memory benefits of low-rank compression.

The Decoupled RoPE Solution

MLA resolves this structural incompatibility by decoupling content representations from positional representations. Query and key vectors are partitioned into two concatenated segments:

qt,i=[qt,iCqt,iR]RdhC+dr\mathbf{q}_{t, i} = \begin{bmatrix} \mathbf{q}_{t, i}^C \\ \mathbf{q}_{t, i}^R \end{bmatrix} \in \mathbb{R}^{d_h^C + d_r}

kt,i=[kt,iCktR]RdhC+dr\mathbf{k}_{t, i} = \begin{bmatrix} \mathbf{k}_{t, i}^C \\ \mathbf{k}_t^R \end{bmatrix} \in \mathbb{R}^{d_h^C + d_r}

where:

  • qt,iCRdhC\mathbf{q}_{t, i}^C \in \mathbb{R}^{d_h^C} is the content query vector derived from ctQ\mathbf{c}_t^Q.
  • qt,iRRdr\mathbf{q}_{t, i}^R \in \mathbb{R}^{d_r} is the rotary query vector generated via qt,iR=RoPE(WQR,ictQ)\mathbf{q}_{t, i}^R = \text{RoPE}\left(\mathbf{W}_{QR, i} \mathbf{c}_t^Q\right), where WQR,iRdr×dc\mathbf{W}_{QR, i} \in \mathbb{R}^{d_r \times d_c'}.
  • kt,iCRdhC\mathbf{k}_{t, i}^C \in \mathbb{R}^{d_h^C} is the content key vector derived from ctKV\mathbf{c}_t^{KV}.
  • ktRRdr\mathbf{k}_t^R \in \mathbb{R}^{d_r} is the shared rotary key vector generated via ktR=RoPE(WKRht)\mathbf{k}_t^R = \text{RoPE}\left(\mathbf{W}_{KR} \mathbf{h}_t\right), where WKRRdr×d\mathbf{W}_{KR} \in \mathbb{R}^{d_r \times d}.

Crucially, ktR\mathbf{k}_t^R is a single, decoupled rotary vector shared across all nhn_h attention heads (with dr=64d_r = 64).

What the Inference Engine Caches

Because the content key kt,iC\mathbf{k}_{t, i}^C and content value vt,iC\mathbf{v}_{t, i}^C are strictly linear projections of ctKV\mathbf{c}_t^{KV}, the inference engine does not store kt,iC\mathbf{k}_{t, i}^C or vt,iC\mathbf{v}_{t, i}^C in the KV cache.

Instead, for each token tt, the KV cache stores strictly two vectors:

  1. The compressed latent vector ctKVRdc\mathbf{c}_t^{KV} \in \mathbb{R}^{d_c} (512 scalar elements).
  2. The decoupled positional key vector ktRRdr\mathbf{k}_t^R \in \mathbb{R}^{d_r} (64 scalar elements).

Cache Per Token Per Layer=dc+dr=512+64=576 scalars\text{Cache Per Token Per Layer} = d_c + d_r = 512 + 64 = 576 \text{ scalars}

In 16-bit precision, this amounts to 576×2=1,152576 \times 2 = 1,152 bytes per token per layer, representing a 56.9x reduction in cache size compared to standard MHA.

Inference Acceleration: Mathematical Absorption of Projection Matrices

The defining algebraic breakthrough of MLA during autoregressive decoding is the mathematical absorption of the up-projection matrices WUK\mathbf{W}_{UK} and WUV\mathbf{W}_{UV}. During generation, the model never materializes high-dimensional keys or values for historical tokens.

Attention Logit Matrix Absorption

The attention logit between query token tt and cached token jj for head ii decomposes into content and positional inner products:

Scoret,j,i=qt,iTkj,i=(qt,iC)Tkj,iC+(qt,iR)TkjR\text{Score}_{t, j, i} = \mathbf{q}_{t, i}^T \mathbf{k}_{j, i} = (\mathbf{q}_{t, i}^C)^T \mathbf{k}_{j, i}^C + (\mathbf{q}_{t, i}^R)^T \mathbf{k}_j^R

Substituting the content key definition kj,iC=WUK,icjKV\mathbf{k}_{j, i}^C = \mathbf{W}_{UK, i} \mathbf{c}_j^{KV} into the first term:

(qt,iC)Tkj,iC=(qt,iC)T(WUK,icjKV)=(WUK,iTqt,iC)TcjKV(\mathbf{q}_{t, i}^C)^T \mathbf{k}_{j, i}^C = (\mathbf{q}_{t, i}^C)^T \left(\mathbf{W}_{UK, i} \mathbf{c}_j^{KV}\right) = \left(\mathbf{W}_{UK, i}^T \mathbf{q}_{t, i}^C\right)^T \mathbf{c}_j^{KV}

Let us define the absorbed query vector q~t,iCRdc\tilde{\mathbf{q}}_{t, i}^C \in \mathbb{R}^{d_c}:

q~t,iC=WUK,iTqt,iC\tilde{\mathbf{q}}_{t, i}^C = \mathbf{W}_{UK, i}^T \mathbf{q}_{t, i}^C

Because q~t,iC\tilde{\mathbf{q}}_{t, i}^C depends only on the single active query token at step tt, it is computed once prior to attending over the sequence. The attention score is then computed directly as:

Scoret,j,i=(q~t,iC)TcjKV+(qt,iR)TkjR\text{Score}_{t, j, i} = (\tilde{\mathbf{q}}_{t, i}^C)^T \mathbf{c}_j^{KV} + (\mathbf{q}_{t, i}^R)^T \mathbf{k}_j^R

The inner product (q~t,iC)TcjKV(\tilde{\mathbf{q}}_{t, i}^C)^T \mathbf{c}_j^{KV} operates directly between a 512-dimensional vector and the cached 512-dimensional latent vectors cjKV\mathbf{c}_j^{KV} for all j{1,,t}j \in \{1, \dots, t\}. Key decompression is entirely bypassed.

Value Output Matrix Absorption

Following softmax normalization, the attention weights $A_{t, j, i} = \text{softmax}_j\left(\frac{\text{Score}_{t, j, i}}{\sqrt{d_h^C + d_r}}\right)$ are applied to the values:

ut,i=j=1tAt,j,ivj,iC=j=1tAt,j,i(WUV,icjKV)\mathbf{u}_{t, i} = \sum_{j=1}^t A_{t, j, i} \mathbf{v}_{j, i}^C = \sum_{j=1}^t A_{t, j, i} \left(\mathbf{W}_{UV, i} \mathbf{c}_j^{KV}\right)

By linearity, the matrix WUV,i\mathbf{W}_{UV, i} can be factored outside the summation over the sequence:

ut,i=WUV,i(j=1tAt,j,icjKV)\mathbf{u}_{t, i} = \mathbf{W}_{UV, i} \left( \sum_{j=1}^t A_{t, j, i} \mathbf{c}_j^{KV} \right)

Let u~t,iRdc\tilde{\mathbf{u}}_{t, i} \in \mathbb{R}^{d_c} denote the attention-weighted reduction in the latent space:

u~t,i=j=1tAt,j,icjKV\tilde{\mathbf{u}}_{t, i} = \sum_{j=1}^t A_{t, j, i} \mathbf{c}_j^{KV}

The multi-head attention block aggregates all heads and projects to the model hidden dimension via output projection weights $\mathbf{W}_O = [\mathbf{W}_O^1, \mathbf{W}_O^2, \dots, \mathbf{W}_O^{n_h}] \in \mathbb{R}^{d \times (n_h d_v)}$:

ot=i=1nhWOiut,i=i=1nhWOi(WUV,iu~t,i)=i=1nh(WOiWUV,i)u~t,i\mathbf{o}_t = \sum_{i=1}^{n_h} \mathbf{W}_O^i \mathbf{u}_{t, i} = \sum_{i=1}^{n_h} \mathbf{W}_O^i \left(\mathbf{W}_{UV, i} \tilde{\mathbf{u}}_{t, i}\right) = \sum_{i=1}^{n_h} \left(\mathbf{W}_O^i \mathbf{W}_{UV, i}\right) \tilde{\mathbf{u}}_{t, i}

The product $\mathbf{W}_{\text{absorbed}}^i = \mathbf{W}_O^i \mathbf{W}_{UV, i} \in \mathbb{R}^{d \times d_c}$ is a static weight matrix. During model initialization or engine compilation, Wabsorbed\mathbf{W}_{\text{absorbed}} can be pre-computed offline:

WabsorbedRd×(nhdc)\mathbf{W}_{\text{absorbed}} \in \mathbb{R}^{d \times (n_h d_c)}

During token generation:

  1. Attention weights At,j,iA_{t, j, i} are multiplied directly against cached latent vectors cjKVRdc\mathbf{c}_j^{KV} \in \mathbb{R}^{d_c} to produce u~t,i\tilde{\mathbf{u}}_{t, i}.
  2. The final head output is computed via a single linear transformation against Wabsorbed\mathbf{W}_{\text{absorbed}}.

Intermediate dvd_v-dimensional value tensors are never materialized or stored in memory during inference.

Architectural Comparison and Serving Economics

To quantify the efficiency gains of MLA, consider the structural and operational parameters of standard attention mechanisms evaluated against DeepSeek-V2 and DeepSeek-V3 configurations:

  • Standard Multi-Head Attention (MHA): 128 Query Heads, 128 KV Heads, Head Dim 128. Caches 32,768 elements (65,536 bytes) per token per layer in FP16. Baseline reference (1.00x).
  • Grouped-Query Attention (GQA-8): 64 Query Heads, 8 KV Heads, Head Dim 128. Caches 2,048 elements (4,096 bytes) per token per layer in FP16. 16.0x smaller cache than MHA.
  • Multi-Query Attention (MQA): 128 Query Heads, 1 KV Head, Head Dim 128. Caches 256 elements (512 bytes) per token per layer in FP16. 128.0x smaller cache than MHA, but severe loss in head representational diversity.
  • Multi-Head Latent Attention (MLA): 128 Query Heads, 128 effective KV Heads, Head Dim 128, Latent Dim 512 (+64 RoPE). Caches 576 elements (1,152 bytes) per token per layer in FP16. 56.9x smaller cache than MHA, and 71.9% smaller than GQA-8 while preserving 128 independent representational projections.

High-Throughput Serving Kernels: FlashMLA and SGLang

Standard attention kernels like FlashAttention-2 and FlashAttention-3 are optimized for GEMM layouts where KK and VV share identical dimensions with QQ. In MLA, the asymmetry between 512-dimensional latent vectors and 64-dimensional decoupled RoPE components requires specialized fused kernels.

To maximize compute utilization on NVIDIA Hopper architectures, DeepSeek open-sourced FlashMLA, a specialized decoding kernel designed for variable-length MLA sequences:

  • Paged Latent Allocation: The KV cache stores contiguous blocks of (dc+dr)(d_c + d_r) elements, integrated directly into memory managers like PagedAttention in SGLang and vLLM.
  • Tile-Based GEMM Fusion: On H100/H800 SXM5 GPUs, FlashMLA utilizes Tensor Core MMA (Matrix Multiply-Accumulate) instructions to perform the absorbed query-latent dot product and softmax accumulation within Tensor Memory Accelerator (TMA) shared memory buffers.
  • FP8 Quantized Latent Cache: In DeepSeek-V3, ctKV\mathbf{c}_t^{KV} is quantized to FP8 (E4M3 format) alongside per-block scaling factors, reducing cache consumption to 576 bytes per token per layer.

PyTorch Reference Implementation

The following reference module illustrates the execution flow of Multi-Head Latent Attention during autoregressive decoding with matrix absorption.

import math
import torch
import torch.nn as nn
import torch.nn.functional as F

class MultiHeadLatentAttention(nn.Module):
    def __init__(
        self,
        d_model: int = 5120,
        n_heads: int = 128,
        d_head: int = 128,
        d_c_kv: int = 512,
        d_c_q: int = 1536,
        d_rope: int = 64,
    ):
        super().__init__()
        self.d_model = d_model
        self.n_heads = n_heads
        self.d_head = d_head
        self.d_c_kv = d_c_kv
        self.d_c_q = d_c_q
        self.d_rope = d_rope
        self.scale = 1.0 / math.sqrt(d_head + d_rope)

        # Query compression and projection
        self.w_dq = nn.Linear(d_model, d_c_q, bias=False)
        self.q_norm = nn.RMSNorm(d_c_q)
        self.w_uq = nn.Linear(d_c_q, n_heads * d_head, bias=False)
        self.w_qr = nn.Linear(d_c_q, n_heads * d_rope, bias=False)

        # Key-Value compression and projection
        self.w_dkv = nn.Linear(d_model, d_c_kv, bias=False)
        self.kv_norm = nn.RMSNorm(d_c_kv)
        self.w_uk = nn.Linear(d_c_kv, n_heads * d_head, bias=False)
        self.w_uv = nn.Linear(d_c_kv, n_heads * d_head, bias=False)
        self.w_kr = nn.Linear(d_model, d_rope, bias=False)

        # Output projection
        self.w_out = nn.Linear(n_heads * d_head, d_model, bias=False)

    def apply_rope(self, x: torch.Tensor, freqs_cis: torch.Tensor) -> torch.Tensor:
        # 2D rotary embedding application on last dimension
        x_complex = torch.view_as_complex(x.float().reshape(*x.shape[:-1], -1, 2))
        x_rotated = torch.view_as_real(x_complex * freqs_cis).flatten(-2)
        return x_rotated.type_as(x)

    def forward_decode_absorbed(
        self,
        h_t: torch.Tensor,                # [batch, 1, d_model]
        cached_c_kv: torch.Tensor,        # [batch, seq_len, d_c_kv]
        cached_k_rope: torch.Tensor,      # [batch, seq_len, d_rope]
        freqs_cis_t: torch.Tensor,        # [1, 1, d_rope // 2]
    ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
        batch_size = h_t.size(0)

        # 1. Compress and project query
        c_q = self.q_norm(self.w_dq(h_t))
        q_c = self.w_uq(c_q).view(batch_size, 1, self.n_heads, self.d_head)
        q_rope = self.w_qr(c_q).view(batch_size, 1, self.n_heads, self.d_rope)
        q_rope = self.apply_rope(q_rope, freqs_cis_t)

        # 2. Compress current token KV for cache append
        c_kv_t = self.kv_norm(self.w_dkv(h_t))
        k_rope_t = self.apply_rope(self.w_kr(h_t), freqs_cis_t)

        new_cached_c_kv = torch.cat([cached_c_kv, c_kv_t], dim=1)
        new_cached_k_rope = torch.cat([cached_k_rope, k_rope_t], dim=1)

        # 3. Absorb Key Up-Projection Matrix W_UK into Query
        w_uk = self.w_uk.weight.view(self.n_heads, self.d_head, self.d_c_kv)
        q_absorbed = torch.einsum('bthd,hdc->bhtc', q_c, w_uk)

        # 4. Compute Attention Scores directly in latent space
        scores_c = torch.einsum('bhtc,bsc->bhts', q_absorbed, new_cached_c_kv)
        scores_r = torch.einsum('bthd,bsd->bhts', q_rope, new_cached_k_rope)
        
        scores = (scores_c + scores_r) * self.scale
        attn_weights = F.softmax(scores, dim=-1)

        # 5. Compute Latent Value Aggregation
        u_tilde = torch.einsum('bhts,bsc->bhtc', attn_weights, new_cached_c_kv)

        # 6. Absorb Value Up-Projection W_UV into Output Projection W_out
        w_uv = self.w_uv.weight.view(self.n_heads, self.d_head, self.d_c_kv)
        w_out = self.w_out.weight.view(self.d_model, self.n_heads, self.d_head)
        w_combined = torch.einsum('mhd,hdc->mhc', w_out, w_uv)

        # Final projection directly from latent space to hidden dimension
        output = torch.einsum('bhtc,mhc->btm', u_tilde, w_combined)

        return output, new_cached_c_kv, new_cached_k_rope

Practical Deployment Implications

  • Context Window Scaling: By reducing per-token memory consumption to 576 bytes (in FP8), a single 8-GPU NVIDIA H100 node (640 GB total HBM) can maintain concurrent active KV caches for over 1,000,000 tokens without requiring multi-node model parallel tensor distribution.
  • Throughput Density: Under high-concurrency batching regimes, the reduction in memory-bus traffic increases decode tokens-per-second per GPU by 3.5x to 5.2x compared to standard GQA baselines.
  • Training vs. Inference Duality: While MLA adds projection FLOPs during prefill and training, the matrix absorption property ensures that decoding remains strictly memory-bandwidth optimized.

Sources

Written by

More to read