Phase 10 - Lesson 16
Atenção Diferencial (V2)
This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.
A atenção softmax espalha uma pequena quantidade de probabilidade por cada token que não seja correspondente. Ao longo de 100k tokens, esse ruído se acumula e afoga o sinal. O Differential Transformer (Ye et al., ICLR 2025) corrige isso computando a atenção como a diferença entre duas softmaxes, subtraindo o piso de ruído compartilhado. O DIFF V2 (Microsoft, janeiro de 2026) é a reescrita para a stack de produção: igualando a latência de decodificação ao Transformer de linha de base (baseline), sem kernels customizados e compatível com FlashAttention. Esta lição aborda a transição do V1 para o V2 de ponta a ponta, com uma implementação simplificada (toy) funcional da operação de diferença que você pode rodar em Python stdlib.
Tipo: Build Linguagens: Python (stdlib) Pré-requisitos: Phase 7 · 02 (auto-atenção), Phase 7 · 15 (variantes de atenção), Phase 10 · 14 (passo a passo da arquitetura) Tempo: ~60 minutos
Objetivos de Aprendizado
- Explicar precisamente por que a atenção softmax possui um piso de ruído e por que ele cresce com o comprimento do contexto.
- Derivar a fórmula de atenção diferencial e explicar por que a subtração cancela o componente de ruído compartilhado enquanto preserva o sinal.
- Analisar a diferença do V1 para o V2: o que ficou mais rápido, o que ficou mais simples, o que ficou mais estável e por que cada mudança foi necessária para o pré-treinamento em produção.
- Implementar a atenção diferencial do zero em Python puro e verificar empiricamente a propriedade de cancelamento de ruído em uma consulta sintética de sinal mais ruído.
O Problema
A atenção softmax padrão possui uma propriedade matemática que se transforma em uma dor de cabeça operacional em larga escala. Para uma consulta q, os pesos de atenção são softmax(qK^T / sqrt(d)). A softmax nunca pode produzir zeros exatos — cada token não correspondente recebe alguma massa positiva. Essa massa residual é ruído e escala com o comprimento do contexto. Em 128k tokens, mesmo que cada token não correspondente receba apenas 0,001% da probabilidade, 127.999 deles combinados contribuem com cerca de 12% do total. O modelo precisa aprender a contornar um piso de ruído que cresce com o contexto.
Empiricamente, isso se manifesta como interferência nas cabeças de atenção: citações alucinadas em RAG de longo contexto, falhas de "perdido no meio" (lost-in-the-middle) em tarefas de recuperação de 100k tokens e degradação sutil de acurácia em benchmarks de agulha no palheiro (needle-in-a-haystack) além de 32k. O artigo do Differential Transformer (arXiv:2410.05258, ICLR 2025) mediu essa lacuna: os DIFF Transformers alcançaram menor perplexidade, maior acurácia em contextos longos e menos alucinações do que as linhas de base de mesmo tamanho.
O DIFF V1 tinha três problemas que o mantinham fora dos pipelines de pré-treinamento de ponta. Seu cache de valores (value cache) precisava ser carregado duas vezes por etapa de decodificação, exigia kernels CUDA personalizados que quebravam a compatibilidade com FlashAttention, e seu RMSNorm por cabeça desestabilizava o treinamento de longo prazo em escalas de mais de 70B. O DIFF V2 (blog unilm da Microsoft, 20 de janeiro de 2026) corrigiu todos os três. Esta lição aborda ambas as versões, constrói o operador de diferença e avalia o cancelamento de ruído em uma consulta simplificada (toy).
O Conceito
O piso de ruído da softmax
Para uma consulta q e chaves K = [k_1, ..., k_N], os pesos de atenção são:
w_i = exp(q . k_i / sqrt(d)) / sum_j exp(q . k_j / sqrt(d))
Nenhum w_i é jamais zero. Se k_i for completamente não relacionado a q, a pontuação q . k_i não é 0 — ela flutua em torno de zero com variância ||q||^2 / d. Após a normalização por softmax, cada token não relacionado ainda contribui com O(1/N) para a soma ponderada. A contribuição total dos tokens não relacionados é O((N-1)/N) = O(1) — não é uma quantidade pequena.
O que o modelo deseja é algo parecido com um top-k rígido (hard top-k): peso alto nos tokens correspondentes e peso próximo a zero em todos os outros lugares. A softmax é suave demais para fazer isso diretamente.
A ideia diferencial
Divida as projeções Q e K de cada cabeça em duas: Q = (Q_1, Q_2) e K = (K_1, K_2). Compute dois mapas de atenção:
A_1 = softmax(Q_1 K_1^T / sqrt(d))
A_2 = softmax(Q_2 K_2^T / sqrt(d))
Saída:
DiffAttn = (A_1 - lambda * A_2) V
A subtração cancela qualquer distribuição de ruído que os dois mapas compartilhem. Se ambos os mapas tiverem um peso aproximadamente uniforme nos 127k tokens não relacionados (o que acontecerá na inicialização aleatória), esses pesos se cancelam. O sinal — o pico de peso nos poucos tokens realmente relevantes — só é cancelado se aparecer em ambos os mapas com a mesma magnitude, o que não ocorrerá depois que o modelo for treinado.
lambda é um escalar aprendível por cabeça, parametrizado como lambda = exp(lambda_q1 dot lambda_k1) - exp(lambda_q2 dot lambda_k2) + lambda_init. Ele pode ser negativo. O lambda_init assume como padrão um pequeno número positivo como 0.8.
Por que isso se assemelha ao cancelamento de ruído direcionado
Pense em dois microfones barulhentos gravando a mesma voz. Ambos captam o interlocutor mais o ruído de fundo correlacionado. Subtraia um do outro e o ruído compartilhado desaparece. A voz sobrevive porque os dois sinais diferem em fase ou amplitude o suficiente para evitar o cancelamento total. O lambda por cabeça aprende exatamente esse equilíbrio.
V1 vs V2: a diferença
O V1 manteve a contagem de parâmetros igual à do Transformer de linha de base. Para obter duas consultas por cabeça, ele reduziu a dimensão da cabeça pela metade. Isso custou a expressividade da cabeça e — mais dolorosamente — reduziu pela metade o cache de valores (value cache) por cabeça. A decodificação tinha que carregar o cache de valores duas vezes por etapa (uma vez para cada ramificação da softmax). Resultado: decodificação mais lenta do que a linha de base, apesar de possuir a mesma contagem de parâmetros.
O V2 dobra o número de cabeças de consulta (query heads) e mantém as cabeças KV iguais (tomando parâmetros emprestados da projeção ascendente). A dimensão da cabeça permanece a mesma da linha de base. Após a subtração, a dimensão extra é projetada de volta para baixo para corresponder à projeção O_W do Transformer de linha de base. Três coisas acontecem ao mesmo tempo:
- A velocidade de decodificação corresponde à linha de base (o cache KV é carregado apenas uma vez).
- O FlashAttention roda inalterado (sem kernel personalizado).
- A intensidade aritmética na decodificação aumenta (mais computação por byte carregado da HBM).
O V2 também remove o RMSNorm por cabeça que o V1 usava para estabilizar a subtração. Em escalas de pré-treinamento da classe de 70B, esse RMSNorm desestabilizava o final do treinamento. O V2 o substitui por um esquema de inicialização mais simples que mantém o treinamento estável sem o módulo extra.
Quando recorrer a isso
| Carga de Trabalho | Benefício |
|---|---|
| RAG de contexto longo (64k+) | Mapas de atenção mais limpos, menos citações alucinadas |
| Benchmarks de agulha no palheiro | Ganho substancial de acurácia após 32k |
| QA de múltiplos documentos | Menos interferência entre documentos |
| Conclusão de código em 8k | Marginal, não vale a mudança de arquitetura |
| Chat curto (< 4k) | Essencialmente indistinguível da linha de base |
O valor cresce com o comprimento do contexto. Em 4k tokens, o piso de ruído é pequeno o suficiente para que a atenção padrão seja adequada. Em 128k, ele está prejudicando você.
Como se compara com outros recursos de 2026
| Recurso | Compatível com DIFF V2? |
|---|---|
| GQA | Sim (o V2 aumenta as cabeças Q, não as cabeças KV) |
| MLA (DeepSeek) | Sim em princípio, nenhum artigo publicado combinando-os |
| MoE | Sim (a atenção é independente do bloco MLP) |
| RoPE | Sim (inalterado) |
| YaRN / escalonamento de contexto longo | Sim (exatamente onde o DIFF mais ajuda) |
| FlashAttention | Sim no V2 (era não no V1) |
| Decodificação especulativa | Sim (a mudança na atenção é invisível para o loop de decodificação especulativa) |
Implemente
O arquivo code/main.py implementa a atenção diferencial em Python puro. Uma consulta simplificada (toy) com estrutura conhecida de sinal mais ruído permite que você meça a taxa de cancelamento de ruído diretamente.
Passo 1: atenção softmax padrão
Operações de matrizes da stdlib: listas de listas, matmul manual, softmax com subtração do valor máximo para estabilidade numérica.
def softmax(row):
m = max(row)
exps = [math.exp(x - m) for x in row]
s = sum(exps)
return [e / s for e in exps]
Passo 2: dividir Q, K em duas metades
Estilo V1: reduz a dimensão da cabeça pela metade. Estilo V2: mantém a dimensão da cabeça e dobra o número de cabeças. A implementação simplificada usa o estilo V1 para clareza pedagógica — a matemática é idêntica, apenas a organização dos dados é diferente.
Passo 3: dois ramos de softmax + subtração
A1 = [softmax([dot(q1, k) / scale for k in K1]) for q1 in Q1]
A2 = [softmax([dot(q2, k) / scale for k in K2]) for q2 in Q2]
diff_weights = [[a1 - lam * a2 for a1, a2 in zip(r1, r2)] for r1, r2 in zip(A1, A2)]
out = [[sum(w * v[j] for w, v in zip(row, V)) for j in range(d_v)] for row in diff_weights]
Nota: os pesos de saída podem ser negativos. Isso é normal — o cache de valores ainda lida com contribuições com sinal. A projeção V subsequente absorve o sinal.
Passo 4: medição do cancelamento de ruído
Construa uma sequência sintética de comprimento 1024. Coloque o token de sinal em uma posição conhecida, preencha o restante com ruído. Compute (a) o peso da atenção softmax padrão na posição do sinal e (b) o peso da atenção diferencial. Meça a proporção de sinal-ruído em cada um. A atenção DIFF produz de forma confiável uma relação sinal-ruído maior por um fator de 3x a 10x, dependendo de quanto as duas ramificações foram treinadas para diferir.
Passo 5: contabilidade de parâmetros do V1 vs V2
Dada uma configuração (hidden=4096, heads=32, d_head=128), imprima:
- Transformer de linha de base (baseline): Q, K, V cada um com tamanho
hidden * hidden, MLP em 4 * hidden. - DIFF V1: Q, K cada um de tamanho
hidden * hidden, V de tamanhohidden * hidden(inalterado), dimensão da cabeça dividida pela metade internamente. Adiciona parâmetroslambdapor cabeça (O(heads * d_head)). - DIFF V2: Q de tamanho
2 * hidden * hidden, K de tamanhohidden * hidden, V de tamanhohidden * hidden. Dimensão extra projetada de volta para baixo antes de O_W. Adiciona os mesmos parâmetroslambda.
O modelo simplificado mede o custo extra de parâmetros para o V2 (aproximadamente hidden * hidden extras por bloco de atenção) e o imprime.
Use
O DIFF V2 ainda não está disponível em todos os servidores de inferência de produção até abril de 2026, mas a integração está em andamento no vLLM e no SGLang. Enquanto isso, o padrão aparece em:
- Modelos de produção de contexto longo internos da Microsoft.
- Replicações de pesquisa em várias rodadas de treinamento de modelos abertos com alvo de contexto de mais de 256k.
- Arquiteturas híbridas que combinam atenção DIFF com atenção de janela deslizante (sliding-window) em camadas alternadas.
Quando recorrer a isso em 2026:
- Ao treinar um novo modelo do zero visando um contexto efetivo de mais de 64k. Adicione a atenção diferencial desde o início; o retreinamento posterior é caro.
- No ajuste fino (fine-tuning) de um modelo de contexto longo onde falhas de "perdido no meio" (lost-in-the-middle) dominam sua avaliação. Um LoRA nas projeções Q pode aproximar a estrutura do DIFF.
Quando não recorrer:
- Se você estiver servindo um modelo denso pré-treinado com desempenho estável em contextos longos. O custo do retreinamento raramente compensa com os pesos existentes.
- Se o seu contexto for sempre menor que 16k. O piso de ruído é insignificante.
Envie para Produção
Esta lição produz o arquivo outputs/skill-diff-attention-integrator.md. Dada uma arquitetura de modelo, comprimento do contexto alvo, perfil de alucinação e orçamento de treinamento, ele produz um plano de integração para adicionar atenção diferencial a uma nova rodada de pré-treinamento ou ajuste fino via LoRA.
Exercícios
Execute
code/main.py. Verifique se a relação sinal-ruído reportada para a atenção diferencial é maior do que a da atenção softmax padrão na consulta sintética. Varie a amplitude do ruído e mostre o ponto de transição onde a atenção padrão se torna inutilizável.Calcule a diferença na contagem de parâmetros da linha de base para o DIFF V1 e da linha de base para o DIFF V2 para um modelo da classe 7B (hidden=4096, heads=32, d_head=128, 32 camadas). Mostre quais componentes ganharam parâmetros e quais permaneceram iguais.
Leia a Seção 3 do artigo do DIFF V1 (arXiv:2410.05258) e a Seção 2 do blog do DIFF V2 no Hugging Face. Em duas frases, explique por que o RMSNorm por cabeça do V1 era necessário e por que o V2 pôde removê-lo sem causar divergência no treinamento.
Implemente uma ablação: compute a atenção diferencial com
lambda = 0(apenas a primeira softmax pura) elambda = 1(subtração completa). Na consulta sintética, meça como a relação sinal-ruído muda ao longo da variação. Identifique olambdaque maximiza a relação sinal-ruído.Estenda o modelo simplificado para GQA + DIFF V2. Escolha 8 cabeças KV e 32 cabeças Q. Mostre que o tamanho do cache KV corresponde a um modelo GQA de linha de base com a mesma configuração (8, 32).
Termos-Chave
| Termo | O que dizem | O que realmente significa |
|---|---|---|
| Atenção diferencial | "Duas softmaxes subtraídas uma da outra" | Divide Q, K em duas metades, computa dois mapas softmax, subtrai o segundo (escalonado por lambda) do primeiro e, em seguida, multiplica por V |
| Piso de ruído | "A cauda não-nula da softmax" | O peso O(1/N) que a softmax atribui a cada token não relacionado, o qual soma O(1) ao longo de contextos longos |
| lambda | "A escala de subtração" | Escalar aprendível por cabeça parametrizado como exp(lq1.lk1) - exp(lq2.lk2) + lambda_init; pode ser negativo |
| DIFF V1 | "A versão do ICLR 2025" | Differential Transformer original; divide a dimensão da cabeça pela metade para preservar a contagem de parâmetros, necessita de kernel personalizado, decodificação mais lenta |
| DIFF V2 | "A correção de janeiro de 2026" | Dobra as cabeças Q mantendo as cabeças KV; iguala a velocidade de decodificação da linha de base e funciona com FlashAttention |
| RMSNorm por cabeça | "O estabilizador do V1" | Normalização extra que o V1 aplicava após a diferença; o V2 a removeu para evitar instabilidade no final do treinamento |
| Relação sinal-ruído | "Quanta atenção é desperdiçada" | Razão do peso na posição do sinal real em relação ao peso médio nas posições não relacionadas |
| Perdido no meio | "Modo de falha de contexto longo" | Fenômeno empírico em que a acurácia de recuperação cai para documentos no meio de um contexto longo — a atenção DIFF reduz isso |
| Intensidade aritmética | "FLOPs por byte carregado" | Proporção que o V2 aumentou na decodificação ao dobrar as consultas por carga KV; importante para decodificação limitada por memória |
Leitura Adicional
- Ye et al. — Differential Transformer (arXiv:2410.05258, ICLR 2025) — o artigo original com a teoria de cancelamento de ruído e ablações de contexto longo
- Microsoft unilm — Differential Transformer V2 (Hugging Face blog, January 2026) — a reescrita para a stack de produção, igualando a decodificação da linha de base, compatível com FlashAttention
- Understanding Differential Transformer Unchains Pretrained Self-Attentions (arXiv:2505.16333) — análise teórica de por que a subtração recupera a estrutura de atenção pré-treinada
- Shared DIFF Transformer (arXiv:2501.17900) — variante com compartilhamento de parâmetros
- Vaswani et al. — Attention Is All You Need (arXiv:1706.03762) — o Transformer de linha de base do qual o DIFF realiza a subtração
- Liu et al. — Lost in the Middle (arXiv:2307.03172) — o benchmark de contexto longo que a atenção DIFF visa solucionar