Atenção e o mecanismo transformer

TL;DR

O mecanismo de atenção é o coração dos LLMs. Ele permite que cada token “olhe” para todos os outros tokens no contexto simultaneamente, calculando pesos de relevância via Query-Key-Value. Multi-head attention faz isso em paralelo com diferentes “lentes”. É isso que torna LLMs capazes de entender contexto, resolver referências e processar sequências inteiras de uma vez — e também é o motivo pelo qual contexto longo é caro.

O que é

O Transformer é a arquitetura de rede neural introduzida por Vaswani et al. em 2017 no paper “Attention Is All You Need”. Antes dele, modelos de linguagem usavam RNNs (Recurrent Neural Networks) que processavam texto sequencialmente — uma palavra por vez, da esquerda para a direita. Isso era lento e perdia informação em distâncias longas.

O Transformer substituiu a recorrência por atenção — um mecanismo que permite processar todos os tokens de uma sequência em paralelo, calculando a relação de cada token com todos os outros.

Por que importa

A atenção explica diretamente:

  • Por que LLMs são bons em contexto — cada token é enriquecido pelo contexto de todos os outros
  • Por que contexto longo custa caro — a atenção escala quadraticamente: O(n²) com o tamanho da sequência
  • Por que GPUs são necessárias — a paralelização massiva da atenção é perfeita para hardware paralelo
  • Por que “lost in the middle” acontece — os pesos de atenção podem se diluir em contextos muito longos

Como funciona

A intuição: “quem é relevante pra mim?”

Considere a frase: “O animal não atravessou a rua porque ele estava cansado.”

Quando o modelo processa “ele”, o mecanismo de atenção calcula:

  • Alta atenção para “animal” (é a referência provável)
  • Baixa atenção para “rua” (irrelevante para “ele”)
  • Atenção moderada para “cansado” (descreve “ele”)

O resultado: a representação de “ele” é enriquecida com informação de “animal”.

Os três vetores: Query, Key, Value

Para cada token, o modelo cria três vetores através de multiplicação por matrizes de pesos aprendidas:

VetorPapelAnalogia
Query (Q)“O que estou procurando?”A pergunta de busca
Key (K)“O que eu ofereço?”O índice de um documento
Value (V)“Qual é minha informação?”O conteúdo do documento

Q, K e V vêm todos do mesmo token?

Na self-attention (o que roda dentro de um LLM) sim: Q, K e V são três projeções do mesmo conjunto de tokens — a sequência atende a si mesma. Existe também a cross-attention, usada em arquiteturas encoder-decoder (tradução, alguns modelos multimodais): ali o Q vem de uma sequência (ex.: o texto sendo gerado) e K/V vêm de outra (ex.: a imagem ou o texto-fonte). LLMs decoder-only modernos usam só self-attention mascarada; a cross-attention reaparece quando há duas sequências distintas para casar.

O cálculo passo a passo

graph TD
    A["Token: 'ele'"] --> B["Gerar Q, K, V"]
    B --> C["Calcular scores:<br>Q · K^T de todos os tokens"]
    C --> D["Normalizar scores<br>(softmax)"]
    D --> E["Ponderar Values<br>pelos scores"]
    E --> F["Somar Values ponderados<br>= nova representação de 'ele'"]
  1. Score = Q(ele) · K(cada_token)ᵀ — produto escalar que mede similaridade
  2. Normalização = softmax(scores / √d_k) — transforma em probabilidades que somam 1
  3. Output = Σ (score_i × V_i) — média ponderada dos Values

A divisão por √d_k (dimensão das keys) evita que os scores fiquem muito grandes, o que tornaria o softmax muito “pontudo” (concentrado em um único token).

Fórmula canônica

A máscara causal — por que o modelo não pode “espiar o futuro”

Se a atenção deixa cada token olhar para todos os outros em paralelo, surge um problema no treino: prever o próximo token vira trapaça se o modelo já enxerga a resposta à frente. A solução é a máscara causal (causal mask).

Antes do softmax, os scores Q·Kᵀ de todas as posições futuras são zerados — tecnicamente, setados para −∞. Como o softmax de −∞ é 0, cada token fica matematicamente proibido de atender a qualquer token à sua direita: só “vê” a si mesmo e ao passado.

É isso que define um modelo decoder-only

Um Transformer “decoder-only” (GPT, Llama, etc.) é, na prática, definido por essa máscara. Ela vale tanto na geração token-a-token quanto no prefill do prompt inteiro — por isso o modelo consegue treinar todas as posições de uma sequência em paralelo e mesmo assim manter a regra “só o passado conta”. O que é paralelo é o cálculo (todas as posições de uma vez), não o alcance (cada token enxerga apenas para trás). Encoders bidirecionais como o BERT não usam essa máscara — aí sim cada token vê todos os outros.

Multi-Head Attention

Em vez de calcular atenção uma vez, o modelo faz isso N vezes em paralelo (geralmente 32-128 “heads”). Cada head aprende a detectar um tipo diferente de relação:

HeadPode aprender a detectar
Head 1Referências pronominais (ele → animal)
Head 2Relações sintáticas (sujeito → verbo)
Head 3Padrões de código (variável → tipo)
Head NOutros padrões emergentes

Os outputs de todos os heads são concatenados e projetados para produzir a representação final:

graph LR
    X["Representação<br>do token"] --> H1["Head 1<br>Q1, K1, V1"]
    X --> H2["Head 2<br>Q2, K2, V2"]
    X --> HN["Head N<br>Qn, Kn, Vn"]
    H1 --> A1["Atenção 1"]
    H2 --> A2["Atenção 2"]
    HN --> AN["Atenção N"]
    A1 --> C["Concatenar"]
    A2 --> C
    AN --> C
    C --> O["Projeção final W_O"]

Attention sinks — o paradoxo do primeiro token

O softmax tem um efeito colateral estrutural: os pesos de atenção precisam somar 1. Quando a query de um token não encontra match forte em nenhum token anterior, o modelo ainda é obrigado a alocar essa atenção em algum lugar — e despeja nos primeiros tokens da sequência. Como eles são visíveis a quase todos os tokens subsequentes (natureza autoregressiva), o treinamento os converte em attention sinks: tokens que recebem atenção alta sem carregar semântica proporcional.

graph LR
    Q["Query do<br>token atual"] --> T0["Token 0 — sink<br>(peso alto 'estacionado')"]
    Q --> TM["Tokens do meio<br>(pesos baixos)"]
    Q --> TR["Tokens recentes<br>(pesos relevantes)"]

A consequência de produção é contraintuitiva: remover os primeiros tokens do KV cache (como faria uma sliding window ingênua) destrói a qualidade do modelo — não por perder contexto antigo, mas por remover uma fração enorme do denominador do softmax, desestabilizando a distribuição de atenção inteira. O StreamingLLM explora exatamente isso: mantém permanentemente os 4 primeiros tokens e desliza a janela para o resto, processando 4M+ tokens com estabilidade.

A complexidade quadrática

O cálculo Q·Kᵀ compara cada token com todos os outros:

Tokens no contextoComparaçõesCusto relativo
1.0001.000.0001x
10.000100.000.000100x
100.00010.000.000.00010.000x
1.000.0001.000.000.000.0001.000.000x

É por isso que contextos de 1M tokens exigem hardware especializado e otimizações como FlashAttention, paged attention, e KV cache.

As duas fases da atenção: prefill e decode

A mesma fórmula de atenção roda sob duas físicas completamente diferentes durante a inferência:

graph TD
    subgraph "Prefill — processa o prompt"
        A["Prompt inteiro<br>(milhares de tokens)"] --> B["Atenção em paralelo<br>(matmuls densos)"]
        B --> C["KV cache populado<br>+ primeiro token gerado"]
    end
    subgraph "Decode — gera a resposta"
        D["1 token novo por vez"] --> E["Atende a TODO o<br>KV cache acumulado"]
        E --> F["Lê GBs de memória<br>para gerar 1 token"]
        F --> D
    end
    C --> D
FaseO que aconteceGargalo
PrefillO prompt inteiro é processado em paralelo — matmuls densos sobre milhares de tokensCompute-bound: 90-95% de utilização de GPU (H100)
DecodeCada token novo atende a todo o KV cache acumuladoMemory-bound: a intensidade aritmética cai ~2 ordens de magnitude; o limite vira o memory bandwidth bottleneck

Essa divisão explica fatos de produção que parecem desconexos:

  • TTFT e tokens/s são métricas independentes — uma mede o prefill, a outra o decode
  • Batching grande melhora o throughput do decode (amortiza as leituras de memória), mas não acelera o prefill de uma request individual
  • Provedores fazem prefill-decode disaggregation — GPUs separadas e otimizadas para cada fase

O KV cache — o monstro de memória que governa a inferência

Você acabou de ver que o decode é memory-bound. O KV cache é a razão exata disso — e entender essa única estrutura explica metade da engenharia de inferência moderna.

O problema. Na geração autoregressiva, cada token novo precisa atender a todos os anteriores — ou seja, precisa das Keys e Values de todo o passado. Sem cache, a cada passo o modelo recomputaria K e V da sequência inteira: gerar o token 1.000 recomputaria 999 pares K/V; o token 1.001, mais 1.000… um desperdício O(n²) só para reconstruir o que já se sabia.

A solução. Computa-se K e V de cada token uma única vez, quando ele entra, e guarda-se na memória da GPU. Cada token novo só calcula o seu Q, K, V; os K/V antigos vêm do cache. O custo de gerar um token cai de O(n²) para O(n) — ao preço de carregar o cache inteiro da memória a cada passo. É exatamente esse carregamento que torna o decode memory-bound.

O custo. O cache cresce linearmente com o contexto, e a conta é brutal:

(o 2 é um para K e outro para V; L = número de camadas; n_kv = número de KV heads; bytes = 2 em FP16/BF16).

ModeloConfigKV/tokenCache p/ 100k tokens
Llama 2 70B (MHA)80 cam · 64 heads · d=128~2,5 MB~250 GB
Llama 3 70B (GQA)80 cam · 8 KV heads · d=128~0,31 MB~31 GB

Uma H100 tem 80 GB. O KV cache de um único contexto de 100k tokens em MHA puro não cabe na placa — e é por isso que toda a engenharia de inferência gira em torno de encolher esse cache. As próximas otimizações (GQA, MLA, paged attention) são, no fundo, ataques diferentes a essa mesma linha.

MHA → MQA → GQA → MLA: a corrida para encolher o KV cache

Olhe de novo a fórmula do cache: 2 × L × n_kv × d_head × bytes. L e d_head são fixos pela arquitetura. A única alavanca real é n_kv — quantos conjuntos de Key/Value o modelo precisa guardar. Boa parte da evolução da atenção nos últimos anos é uma briga por esse número.

VarianteComo compartilha K/VKV cacheTrade-off
MHA (Multi-Head)Cada head tem seu próprio K/VMáximo (n_kv = n_heads)Qualidade máxima, cache máximo
MQA (Multi-Query)Todos os heads dividem um K/VMínimo (n_kv = 1)Cache despenca, qualidade cai em escala
GQA (Grouped-Query)Grupos de heads dividem K/VIntermediário (n_kv = grupos)O dial entre MHA e MQA
MLA (Multi-head Latent)Comprime K/V num vetor latente low-rankMenor que MQACache mínimo e qualidade acima do MHA
  • MHA é o original: 32 heads → 32 conjuntos de K/V no cache. Caro.
  • MQA foi a primeira pancada: e se todos os heads consultassem o mesmo K/V? O cache encolhe ~n_heads vezes. O problema: com um único K/V o modelo perde nuance e degrada conforme cresce.
  • GQA é o meio-termo que venceu: divide os heads em poucos grupos (ex.: 32 heads em 8 grupos), cada grupo com seu K/V. Pega quase toda a economia do MQA sem a queda de qualidade. É o padrão de Qwen, Llama 2/3 e Mistral.
  • MLA muda a estratégia: em vez de cortar heads, comprime Key e Value juntos num vetor latente de baixa dimensão antes de cachear, e os reconstrói na hora da atenção. Cache menor que o do MQA e, surpreendentemente, qualidade acima do MHA — a compressão funciona como um gargalo regularizador. É a aposta da família DeepSeek (V2/V3).

Otimizações modernas (2026)

OtimizaçãoO que fazGanho
FlashAttention 4Reorganiza computação para minimizar I/O de memória; novo online softmax pula ~90% do rescaling (Hot Chips 2025)Até 22% mais rápido que o kernel cuDNN em GPUs Blackwell
KV CacheCacheia Key/Value de tokens já processados para evitar recomputaçãoEssencial para geração autoregressiva
Grouped Query Attention (GQA)Compartilha Keys/Values entre múltiplos headsReduz memória 2-8x
MLA (Multi-head Latent Attention)Comprime K/V num vetor latente low-rank antes de cachear; reconstrói na hora da atenção (DeepSeek-V2/V3)KV cache ~1 ordem de grandeza menor que multi-head puro
Paged AttentionGerencia KV cache como “páginas” de memória virtualPermite batching eficiente (vLLM)
Sparse AttentionCada token atende apenas a um subconjunto relevanteReduz O(n²) para O(n·√n) ou O(n·log(n))
DSA (DeepSeek Sparse Attention)Heads leves selecionam quais tokens recebem atenção plenaSparse attention treinável, em produção (V3.2-Exp)

FlashAttention desempacotado — atenção que evita a memória lenta

A tabela trata o FlashAttention como “reorganiza a computação”. Vale abrir, porque o insight é contraintuitivo e cai em entrevista.

A GPU tem duas memórias: a HBM (dezenas de GB, lenta) e a SRAM (poucos MB, ~10x mais rápida, on-chip). A atenção ingênua materializa a matriz N×N inteira na HBM. O FlashAttention nunca faz isso:

  1. Tiling — corta Q, K e V em blocos pequenos que cabem na SRAM e computa a atenção bloco a bloco, on-chip. A matriz N×N completa nunca toca a HBM.
  2. Online softmax — como cada bloco vê só um pedaço da linha, o softmax é calculado incrementalmente, carregando estatísticas correntes (o máximo e a soma) que são reajustadas a cada bloco novo. O resultado é matematicamente idêntico ao softmax sobre a linha inteira.
  3. Recomputação no backward — em vez de guardar a matriz de atenção para o gradiente, o treino a recomputa a partir de Q/K/V na SRAM. Troca um pouco mais de FLOPs por uma redução enorme de tráfego de memória.

O resultado: mesmo cálculo, resultado exato (não é aproximação), porém com memória linear em n e parede de relógio menor. É por isso que a armadilha lá embaixo está certa — FlashAttention não muda a qualidade, só a física da execução.

A fronteira 2025-2026 é a sparse attention treinável — não mais um truque aplicado só na inferência, mas esparsidade aprendida durante o treino. O NSA (Native Sparse Attention, fev/2025) treina o modelo já esparso com kernels hardware-aligned; o DSA (DeepSeek-V3.2-Exp, set/2025) usa um lightning indexer — heads leves que pontuam quais tokens merecem atenção plena — com kernels atingindo 640 TFlops no prefill. O GLM5 (2026) já adota DSA. A aposta: quebrar o O(n²) sem perder qualidade, tornando contexto de 1M tokens economicamente viável.

Uma rota paralela à esparsidade é a atenção híbrida (local + global). Em vez de toda camada pagar o O(n²), o modelo intercala camadas de sliding window — onde cada token só atende a uma janela local fixa — com uma minoria de camadas de atenção global, que costuram o contexto inteiro. O Gemma 2 alterna 1:1 (janela de 4096 tokens); o GPT-OSS usa janelas bem menores (128 tokens) entre as camadas globais. A maior parte do trabalho fica local e barata; só algumas camadas pagam o custo quadrático. Cuidado com a dosagem: janelas pequenas demais ou camadas globais de menos degradam a qualidade — o modelo perde alcance de longo prazo. Note que isso é diferente do StreamingLLM lá de cima: aqui a esparsidade local é treinada na arquitetura, não um remendo aplicado só na inferência.

Positional encoding — atenção não sabe ordem

A atenção pura é permutation-invariant: os scores Q·Kᵀ não mudam se você embaralhar os tokens. Sem informação posicional, “cão morde homem” e “homem morde cão” produziriam as mesmas representações. É por isso que todo Transformer injeta posição nos embeddings — e a forma de fazer isso evoluiu:

  • Posicional absoluto (paper original) — soma um vetor de posição ao embedding. Simples, mas generaliza mal além do comprimento visto no treino.
  • RoPE (padrão moderno) — em vez de somar, rotaciona pares de dimensões de Q e K por um ângulo proporcional à posição. O produto escalar Q·K passa a codificar distância relativa naturalmente: o que importa é “quão longe”, não “em qual posição absoluta”.
  • YaRN (extensão de contexto) — reescala as frequências do RoPE (interpolação rampada + temperatura de atenção) para esticar a janela além do comprimento de pretraining, usando ~10x menos tokens de treino que métodos anteriores. É assim que modelos treinados em 4K chegam a 128K+.

A arquitetura completa do Transformer

graph TD
    A[Input Tokens] --> B[Token Embeddings + Positional Encoding]
    B --> C[Layer 1]
    subgraph "Transformer Layer (repete N vezes)"
        C --> D[Multi-Head Self-Attention]
        D --> E[Add & Normalize]
        E --> F[Feed-Forward Network]
        F --> G[Add & Normalize]
    end
    G --> H[..."Layer N"]
    H --> I[Linear + Softmax]
    I --> J[Probabilidade do próximo token]

Cada camada combina:

  1. Self-attention — captura relações entre tokens
  2. Feed-forward network — processa cada token independentemente (onde fica o “conhecimento” armazenado)
  3. Residual connections + layer norm — estabilizam o treinamento em redes profundas

A Feed-Forward Network — onde mora o conhecimento

A atenção recebe toda a atenção (trocadilho intencional), mas ~⅔ dos parâmetros de um Transformer estão na FFN — a rede feed-forward que vem depois da atenção em cada camada. Se a atenção é o mecanismo de roteamento (quem fala com quem), a FFN é a memória (o que se sabe).

Ela é deceptivamente simples — roda em cada token de forma independente:

  • Up-projection — expande a dimensão do token, tipicamente para d_ff ≈ 4 × d_model (ex.: 4096 → 16384).
  • Ativação não-linear — GELU no GPT, SwiGLU na família Llama.
  • Down-projection — comprime de volta para d_model.

Esse “incha → processa → comprime” é onde os fatos ficam guardados: estudos de interpretabilidade mostram que as camadas FFN funcionam como uma memória chave-valor, com neurônios específicos ativando para conceitos específicos (“a capital da França é…”). A atenção move informação entre posições; a FFN transforma a informação de cada posição com base no que aprendeu no pré-treino.

Armadilhas

  • “O modelo lê da esquerda pra direita” — na geração sim, mas durante o processamento do input, self-attention vê todos os tokens simultaneamente.
  • “Atenção = compreensão” — atenção é correlação estatística. O modelo pode dar peso alto a um token por razões estatísticas, não semânticas.
  • Ignorar o custo quadrático — duplicar o contexto quadruplica o custo de atenção. É por isso que context engineering importa tanto.
  • “Flash Attention muda a qualidade” — não. FlashAttention é matematicamente equivalente à atenção padrão. Só reorganiza a computação para ser mais eficiente em hardware.
  • Confundir parâmetros com atenção — os pesos das camadas feed-forward (não a atenção) são onde o “conhecimento factual” do modelo reside. Atenção é o mecanismo de busca/organização.

Veja também

Referências