DEV Community

Abhishek Banerjee
Abhishek Banerjee

Posted on Originally published at Medium on

Under the Hood of Transformer Mechanics, Attention Math, and Memory Bottlenecks

Artificial intelligence at scale is often treated as a set of REST endpoints. We call /v1/chat/completions, stream tokens to a frontend, and benchmark system latency in raw milliseconds. But treating Large Language Models (LLMs) purely as black-box services masks the engineering friction occurring at the hardware and algorithmic level.

When output generation slows to a crawl or GPU VRAM OOMs (Out Of Memory) unexpectedly, the root cause is rarely the API layer. It lies within tensor projections, matrix multiplications, memory bandwidth limitations, and sequence allocations.

To write performant systems, design efficient runtimes, or evaluate model architectures, we must peer beneath the abstraction layer. Here is an in-depth operational breakdown of how Transformer architectures execute self-attention, manage memory, and handle generation mechanics under the hood.

The Core Engine: Scaled Dot-Product Attention

The foundational building block of modern generative AI is the Scaled Dot-Product Attention mechanism. At its core, self-attention maps a sequence of input vectors to a sequence of context-aware output vectors by evaluating the relative importance of every token to every other token.

The Mathematical Formulation

Input Tokens (X) │ ├───> [W_Q] ───> Queries (Q) ──┐ ├───> [W_K] ───> Keys (K) ───┼──> (Q × Kᵀ) / √d_k ──> [Softmax] ──> Attention Weights (A) └───> [W_V] ───> Values (V) ───────────────────────────────────────────> (A × V) ──> Context Matrix (Z)

The Step-by-Step Tensor Execution

  1. Linear Projection: Input embeddings $X$ are multiplied by learned parameter matrices $W_Q, W_K, W_V$ to generate tensor representations $Q, K, V$.
  2. Similarity Scoring ($QK^T$): The dot product between Query matrix $Q$ and transposed Key matrix $K^T$ computes raw similarity scores for all sequence pairs. For a sequence length of $N$, this yields an $N \times N$ matrix.
  3. Scaling ($\sqrt{d_k}$): The raw dot products are scaled by dividing by $\sqrt{d_k}$. Without this scaling factor, as vector dimensionality increases, dot products grow large in magnitude, pushing the subsequent softmax function into regions with extremely small gradients (vanishing gradient problem).
  4. Softmax Normalization: Applying softmax row-wise converts score magnitudes into a probability distribution where row values sum to 1.
  5. Value Aggregation: Multiplying the softmax probability matrix by the Value matrix $V$ yields a weighted sum of token representations.

Multi-Head Attention (MHA) vs. Grouped-Query Attention (GQA)

Single attention distributions struggle to capture distinct semantic relationships simultaneously. Multi-Head Attention (MHA) solves this by splitting hidden representations across multiple subspaces.

In standard MHA, each head maintains its own dedicated projection for Queries, Keys, and Values. However, during autoregressive generation, holding distinct Key and Value tensors for every query head introduces significant memory bottlenecks.

The Architectural Shift to GQA

To strike a balance between representational capacity and inference speed, modern architectures (such as Meta’s Llama 3 and Mistral AI’s models) utilize Grouped-Query Attention (GQA):

By assigning multiple Query heads to share a single Key-Value pair group, GQA slashes KV cache memory footprint by 4x to 8x without noticeable degradation in context retrieval metrics.

The Memory Bottleneck: KV Caching Deep Dive

During autoregressive generation, an LLM generates text token by token. Generating token $N$ requires computing attention across all preceding tokens $1 \dots N-1$.

Without optimization, calculating the $Key$ and $Value$ matrices for past tokens at every new step results in $O(N²)$ redundant computations.

The KV Cache Solution

KV Caching stores previously computed Key and Value state tensors in GPU memory. At step $N$, the model only computes $Q_N, K_N, V_N$ for the newest incoming token. $K_N$ and $V_N$ are appended to the stored cache, and $Q_N$ computes attention over the combined tensor.

Real-World Impact: For a 70B parameter model operating in FP16 ($L=80, d_{\text{model}}=8192, h=8$) running a single sequence of 32,000 tokens, the KV cache alone demands roughly 10.4 GB of VRAM . Under high-concurrency batching, KV cache size quickly exceeds the footprint of the actual model weights.

PagedAttention: Virtual Memory for LLM Runtimes

Traditional memory allocators require contiguous blocks of GPU memory. Because generation outputs are dynamic, systems must pre-allocate contiguous memory slices based on the maximum context limit (e.g., reserving space for 4096 tokens upfront). This leads to severe internal and external memory fragmentation , wasting up to 60–80% of unallocated GPU VRAM.

PagedAttention Architecture

Popularized by engine frameworks like vLLM, PagedAttention adapts virtual memory paging principles from operating systems to handle neural network attention matrices.

  1. Non-Contiguous Allocation: KV caches are broken into fixed-size physical blocks (e.g., 16 tokens per block).
  2. Page Tables: A lookup table maps physical memory pages to a logical context stream dynamically as new tokens drop in.
  3. Zero Waste: Memory is requested strictly on-demand. When a sequence completes, its pages are freed immediately into the execution pool.

Implementation: PyTorch KV-Cached Attention

Here is a dynamic KV-cached scaled dot-product attention written in PyTorch:

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

class KVCachedAttention(nn.Module):
    def __init__ (self, d_model: int, n_heads: int):
        super(). __init__ ()
        self.d_model = d_model
        self.n_heads = n_heads
        self.head_dim = d_model // n_heads

        self.q_proj = nn.Linear(d_model, d_model, bias=False)
        self.k_proj = nn.Linear(d_model, d_model, bias=False)
        self.v_proj = nn.Linear(d_model, d_model, bias=False)
        self.out_proj = nn.Linear(d_model, d_model, bias=False)

    def forward(self, x: torch.Tensor, kv_cache: tuple = None):
        """
        x: Input tensor of shape (batch_size, seq_len, d_model)
        kv_cache: Tuple of (cached_keys, cached_values) or None
        """
        b, s, _ = x.shape

        # Project inputs to Q, K, V representations
        q = self.q_proj(x).view(b, s, self.n_heads, self.head_dim).transpose(1, 2)
        k = self.k_proj(x).view(b, s, self.n_heads, self.head_dim).transpose(1, 2)
        v = self.v_proj(x).view(b, s, self.n_heads, self.head_dim).transpose(1, 2)

        # Append to existing KV Cache if available
        if kv_cache is not None:
            prev_k, prev_v = kv_cache
            k = torch.cat([prev_k, k], dim=-2)
            v = torch.cat([prev_v, v], dim=-2)

        new_kv_cache = (k, v)

        # Calculate Scaled Dot-Product Attention Scores
        scores = torch.matmul(q, k.transpose(-2, -1)) / math.sqrt(self.head_dim)

        # Apply causal masking during prefill phase (seq_len > 1)
        if s > 1:
            mask = torch.triu(torch.full((s, k.size(-2)), float('-inf')), diagonal=1).to(x.device)
            scores = scores + mask

        attn_weights = F.softmax(scores, dim=-1)
        output = torch.matmul(attn_weights, v)

        # Reshape and project back to original tensor dimensions
        output = output.transpose(1, 2).contiguous().view(b, s, self.d_model)
        return self.out_proj(output), new_kv_cache
Enter fullscreen mode Exit fullscreen mode

The Engineering Reality

Optimization in AI systems requires balancing mathematical precision against hardware constraints.

Understanding matrix projection mechanics, context scaling parameters, and runtime memory patterns allows us to debug slow inference passes, design resilient AI backends, and extract maximum throughput from infrastructure investments.

Need High-Impact Technical Content for Your Team?

I help engineering-focused companies, developer-tooling startups, and SaaS platforms explain complex infrastructure, backend architecture, and developer tooling through publication-grade articles.

Whether you need deep-dive technical essays, developer guides, or architecture counter-narratives, feel free to reach out:

Top comments (0)