🧠FFVAcademy

KV Cache: Memoria Eficiente

8 min de leitura·+60 XP
Pré-requisitos (0/1)0%

Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.

Por que um modelo de 30GB de parametros pode precisar de 60GB+ de VRAM? Por que gerar o primeiro token e lento mas os seguintes sao rapidos? A resposta e o KV Cache — uma das otimizacoes mais importantes (e menos explicadas) da inferencia de LLMs. Neste artigo, voce vai entender como ele funciona, quanto de memoria consome, e como tecnicas modernas (GQA, Flash Attention, PagedAttention) lidam com seus limites.

⚠️
Pre-requisito: voce precisa entender self-attention (Q, K, V) e como o Transformer gera tokens autorregressivamente. Se nao leu o artigo de Transformers, leia antes.

O problema: atencao autorregressiva e redundante

Na geracao autorregressiva, o modelo gera um token por vez. Para gerar o token na posicao t, ele precisa calcular a atencao entre Q(t) e os Keys de todos os tokens anteriores (1 ate t-1), e combinar com os Values correspondentes.

🗺️ Sem KV Cache: recalculo redundante (gerando "O gato sentou")
1️⃣Token "O"Calcula K(O), V(O) → atenção vs K(O)
2️⃣Token "gato"Recalcula K(O), V(O) ← REDUNDANTE! + K(gato)
3️⃣Token "sentou"Recalcula K(O), K(gato) ← REDUNDANTE! + K(sentou)

Para N tokens: recalcula N(N+1)/2 pares K/V — custo O(N²) em compute redundante.

A solucao: KV Cache

A ideia e simples: calcule K e V de cada token uma unica vez e guarde em memoria. Quando o proximo token chegar, so calcule K e V dele e concatene com o cache.

🗺️ Com KV Cache: calcula cada K/V exatamente UMA vez
1️⃣Token "O"Calcula K(O), V(O) → salva no cache
2️⃣Token "gato"Calcula K(gato), V(gato) APENAS → concatena ao cache
3️⃣Token "sentou"Calcula K(sentou), V(sentou) APENAS → concatena ao cache

Para N tokens: calcula exatamente N pares K/V — custo O(N) em vez de O(N²).

💡
O trade-off e classico: compute vs memoria. KV Cache troca recalculo (compute) por armazenamento (memoria VRAM). A geracao fica muito mais rapida, mas o cache ocupa espaco — e quanto maior o contexto, mais espaco.

Prefill vs Decode: as duas fases da inferencia

🗺️ Inferencia de um LLM
📥Prefill (prompt processing)compute-bound
Processa todo o prompt de uma vez (paralelo). Calcula K e V para todos os tokens do prompt e preenche o cache. Pode levar segundos para prompts longos.
CACHE PREENCHIDO
🔄Decode (geracao autorregressiva)memory-bound
Gera um token por vez. Cada passo: (1) calcula Q/K/V do novo token, (2) concatena K/V ao cache, (3) atencao do Q contra todo o cache, (4) prediz proximo token. Bottleneck: leitura do cache da VRAM.
REPETIR
📤Output completofim
Quando o modelo gera <|end|> ou atinge o limite de tokens, a geracao para. O cache e descartado (a menos que prompt caching esteja ativo).

Por isso o primeiro token demora mais (prefill inteiro) e os seguintes sao rapidos (so decode incremental). Voce ja percebeu isso ao usar ChatGPT ou Claude — aquela pausa inicial seguida de streaming rapido.

Quanto de memoria o cache consome?

KV Cache (bytes) = 2 × layers × seq_len × d_model × bytes_per_param

ModeloLayersDimCache 4k ctxCache 128k ctx
LLaMA 3 8B3240962 GB64 GB
LLaMA 3 70B80819210 GB320 GB
GPT-4 (est.)~120~12k~23 GB~750 GB

LLaMA 3 70B em FP16: modelo ~140 GB + cache 128k = 320 GB → ~460 GB de VRAM para UM request = 6× H100 80GB apenas para servir 1 usuário.

GQA e MQA: compartilhando K/V entre cabecas

Multi-Head Attention (MHA) padrao gera K/V independentes para cada cabeca de atencao. Mas K/V consomem muito mais memoria que Q (cache!). Solucao: compartilhar K/V entre cabecas.

TecnicaQ headsK/V headsReducao de cacheUsado em
MHA (padrao)32320% (baseline)GPT-2, BERT, Transformer original
GQA (Grouped)32875%LLaMA 3, Gemma 2, Mistral
MQA (Multi-Query)32197%PaLM, Falcon, StarCoder
🗺️ MHA vs GQA vs MQA — compartilhamento de K/V entre cabeças
MHA (Multi-Head)
32 Q heads
32 K/V heads
Cada cabeça tem seu K/V
Cache baseline (100%)
GPT-2, BERT, Transformer original
CASOS DE USO
Máxima qualidade
Alto custo de memória
GQA (Grouped)
32 Q heads
8 K/V heads
4 Q heads compartilham 1 K/V
Cache 75% menor
LLaMA 3, Gemma 2, Mistral
CASOS DE USO
Compromisso ideal
Quase qualidade de MHA
MQA (Multi-Query)
32 Q heads
1 K/V head
TODAS as Q usam mesmo K/V
Cache 97% menor
PaLM, Falcon, StarCoder
CASOS DE USO
Máxima economia
Pode perder qualidade

Flash Attention: compute eficiente, nao menos compute

Flash Attention nao reduz a complexidade O(n2) — reduz os acessos a memoria. GPUs tem dois tipos de memoria:

MemoriaTamanho (H100)VelocidadePapel
SRAM (on-chip)~50 MB~19 TB/sRapida mas minuscula — usada como cache de trabalho
HBM (VRAM)80 GB~3.4 TB/sGrande mas ~6x mais lenta — onde modelo e KV Cache vivem

A atencao padrao materializa a matriz n x n inteira na HBM. Flash Attention calcula a atencao em blocos (tiles) que cabem na SRAM, sem nunca materializar a matriz completa. Resultado:

MetricaAtencao padraoFlash Attention v2
Memoria de picoO(n2) — materializa matriz n x nO(n) — so armazena tiles parciais
Acessos HBMMuitos — le e escreve matriz inteiraPoucos — tudo fica na SRAM o maximo possivel
Speedup tipicoBaseline2-4x mais rapido
ComplexidadeO(n2)O(n2) — mesma! So reordena os calculos

PagedAttention: servindo multiplos usuarios

Em producao, um servidor serve multiplos usuarios simultaneamente. Cada request tem um KV Cache de tamanho diferente. Alocar memoria contiguamente causa fragmentacao: espacos vazios entre caches de tamanhos diferentes.

🗺️ PagedAttention — antes e depois (inspirado em virtual memory do OS)
SEM PagedAttention (fragmentação)
Cache A: 2k tokens
[VAZIO — fragmentação]
Cache B: 8k tokens
[VAZIO]
Cache C: 1k tokens
→ ~40% da VRAM desperdiçada
COM PagedAttention (páginas fixas)
VRAM dividida em páginas de tamanho fixo
pág1:A · pág2:B · pág3:A · pág4:B
Páginas não precisam ser contíguas!
Fragmentação quase zero
→ Throughput 2–4× maior em batch

vLLM (UC Berkeley) implementa PagedAttention. Padrão na indústria para servir LLMs em produção.

Prompt Caching: reutilizando o prefill

Se 100 requests usam o mesmo system prompt de 2000 tokens, por que recalcular K/V desses 2000 tokens 100 vezes? Prompt Caching resolve: o KV Cache do prefixo comum e calculado uma vez e reutilizado.

🗺️ Prompt Caching — como o prefill é reutilizado
1️⃣Request 1Processa 2000 tokens (system) + 200 (user) → salva KV Cache do system
2️⃣Request 2Reutiliza cache dos 2000 tokens! Processa só 300 novos → 86% mais barato
🔄Requests NTodos reutilizam o cache → ~95% de economia em prefill

Requisitos: prefixo idêntico byte a byte · TTL ~5 min (Anthropic) · Preços: cache write = normal, cache read = ~10% do preço.

📋 Quando usar Prompt Caching?

Sempre que system prompt > 1000 tokens e requests sao frequentes

O custo de cache write e negligivel comparado com a economia em cache reads. Qualquer chatbot, RAG pipeline ou agent com system prompt longo se beneficia.

Alt: Sem cacheApenas para requests unicos com prompts sempre diferentes (raro em producao).

MLA: a próxima geração de eficiência de cache

GQA e MQA compartilham K/V entre cabeças — mas ainda armazenam K e V separadamente. Multi-head Latent Attention (MLA), introduzido pelo DeepSeek v2/v3 (2024), vai além: comprime K e V num espaço latente de dimensão muito menor antes de armazenar.

🗺️ MHA / GQA vs MLA — o que é armazenado no cache
MHA / GQA (padrão)
Armazena K e V explicitamente
Dimensão por token: 2 × d_head × n_kv_heads
LLaMA 3 70B com GQA 8: ~1.1 GB por 1k tokens
Cache cresce linearmente com seq_len
MLA (DeepSeek v3)
Comprime K, V em vetor latente c (dim muito menor)
Armazena c, não K e V separados
Na atenção: projeta c de volta para K/V on-the-fly
~5-10× menos cache que MHA equivalente
💡
Trade-off do MLA: menos VRAM de cache, mas mais compute na atenção (re-projeção latente → K/V a cada step). Na prática, GPUs modernas têm compute sobrando mas VRAM escassa — MLA é o trade-off certo. É a razão pela qual DeepSeek v3 pode rodar contextos de 128k tokens com muito menos VRAM que LLaMA 3 equivalente.
TécnicaRedução de cacheCustoAdoção
MQA (Multi-Query)1 K/V pair total → 8× menos (vs MHA 8h)Perda de qualidade pequena-médiaGPT-3.5, Falcon
GQA (Grouped Query)1 K/V por grupo → 2-8× menosPerda mínima (LLaMA 3 usa)LLaMA 3, Mistral, Gemma
MLA (Latent Attention)5-10× menos que MHACompute extra para re-projeçãoDeepSeek v2/v3 (emergente)
Cache Quantization (FP8)2× menos que FP16Ruído mínimo em V, moderado em KTensorRT-LLM, vLLM recente

Perguntas e respostas

KV Cache existe durante o treinamento?

Nao. Durante o treinamento, todo o contexto e processado de uma vez (teacher forcing) — nao ha geracao autorregressiva, entao nao ha necessidade de cache incremental. KV Cache e puramente uma otimizacao de inferencia.

Quantizar o KV Cache ajuda?

Sim. Armazenar K/V em FP8 ou INT8 em vez de FP16 reduz o cache pela metade com perda minima de qualidade. Pesquisas recentes (KV Cache quantization) mostram que INT4 e viavel para V mas nao para K (K e mais sensivel a precisao porque afeta os scores de atencao diretamente).

O que e sliding window attention?

Em vez de cachear K/V de TODOS os tokens anteriores, cada camada so atende aos ultimos W tokens (ex: W=4096). Memoria do cache fica fixa em O(W) independente do contexto. Mistral usa isso. A perda: tokens muito distantes nao se “veem” diretamente, mas informacao flui indiretamente pelas camadas empilhadas.
O que voce aprendeu: KV Cache elimina recalculo redundante na geracao autorregressiva (O(n2) → O(n) por token). O custo e memoria VRAM — que pode superar o tamanho do modelo. GQA compartilha K/V entre cabecas (4x menos cache). Flash Attention reordena calculos para minimizar acessos a HBM (2-4x mais rapido). PagedAttention resolve fragmentacao em batch serving. Prompt Caching reutiliza o prefill entre requests. Proximo: como modelos com 1T+ parametros rodam sem carregar tudo na memoria — Mixture of Experts.
🧩

Quiz rápido

4 perguntas · Acerte tudo e ganhe o badge 🎯 Gabarito

Continue lendo