Phase 10 - Lesson 16

Atención Diferencial (V2)

This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.

La atención softmax distribuye una pequeña cantidad de probabilidad sobre cada token que no coincide. En 100k tokens, ese ruido se acumula y ahoga la señal. El Differential Transformer (Ye et al., ICLR 2025) soluciona esto computando la atención como la diferencia entre dos softmaxes, restando el piso de ruido compartido. DIFF V2 (Microsoft, enero de 2026) es la reescritura para el stack de producción: iguala la latencia de decodificación al Transformer de línea de base (baseline), no requiere kernels personalizados y es compatible con FlashAttention. Esta lección aborda la transición de V1 a V2 de extremo a extremo, con una implementación simplificada (toy) funcional de la operación de diferencia que puedes ejecutar en Python stdlib.

Tipo: Build Lenguajes: Python (stdlib) Prerrequisitos: Phase 7 · 02 (autoatención), Phase 7 · 15 (variantes de atención), Phase 10 · 14 (recorrido de la arquitectura) Tiempo: ~60 minutos

Objetivos de Aprendizaje

  • Explicar con precisión por qué la atención softmax tiene un piso de ruido y por qué este crece con la longitud del contexto.
  • Derivar la fórmula de atención diferencial y explicar por qué la resta cancela el componente de ruido compartido al tiempo que preserva la señal.
  • Analizar la diferencia entre V1 y V2: qué se volvió más rápido, qué se simplificó, qué se volvió más estable y por qué cada cambio era necesario para el preentrenamiento en producción.
  • Implementar la atención diferencial desde cero en Python puro y verificar empíricamente la propiedad de cancelación de ruido en una consulta sintética de señal más ruido.

O Problema

La atención softmax estándar tiene una propiedad matemática que se convierte en un dolor de cabeza operativo a gran escala. Para una consulta q, los pesos de atención son softmax(qK^T / sqrt(d)). Softmax nunca puede producir ceros exactos; cada token que no coincide recibe cierta masa positiva. Esa masa residual es ruido y escala con la longitud del contexto. En 128k tokens, incluso si cada token que no coincide obtiene solo el 0.001% de la probabilidad, 127,999 de ellos combinados contribuyen con aproximadamente el 12% del total. El modelo debe aprender a evadir un piso de ruido que crece con el contexto.

Empiricamente, esto se manifiesta como interferencia en las cabezas de atención: citas alucinadas en RAG de contexto largo, fallos de "perdido en el medio" (lost-in-the-middle) en tareas de recuperación de 100k tokens y una degradación sutil de la precisión en benchmarks de aguja en el pajar (needle-in-a-haystack) más allá de 32k. El artículo de Differential Transformer (arXiv:2410.05258, ICLR 2025) mediu la brecha: los DIFF Transformers lograron una menor perplejidad, una mayor precisión en contextos largos y menos alucinaciones que las líneas de base del mismo tamaño. (Wait: "mediu" is Portuguese, let's fix it to "midió" in Spanish). Let's check: yes, it should be "midió").

DIFF V1 tenía tres problemas que lo mantuvieron fuera de los pipelines de preentrenamiento de frontera. Su caché de valores (value cache) tenía que cargarse dos veces por paso de decodificación, requería kernels CUDA personalizados que rompían la compatibilidad con FlashAttention y su RMSNorm por cabeza desestabilizaba el entrenamiento a largo plazo a escalas de más de 70B. DIFF V2 (blog unilm de Microsoft, 20 de enero de 2026) solucionó los tres. Esta lección recorre ambas versiones, construye el operador de diferencia y evalúa la cancelación de ruido en una consulta simplificada (toy).

El Concepto

El piso de ruido de softmax

Para una consulta q y claves K = [k_1, ..., k_N], los pesos de atención son:

w_i = exp(q . k_i / sqrt(d)) / sum_j exp(q . k_j / sqrt(d))

Ningún w_i es jamás cero. Si k_i es completamente ajeno a q, la puntuación q . k_i no es 0; fluctúa alrededor de cero con una varianza de ||q||^2 / d. Después de la normalización por softmax, cada token ajeno sigue contribuyendo con O(1/N) a la suma ponderada. La contribución total de los tokens ajenos es O((N-1)/N) = O(1), lo cual no es una cantidad pequeña.

Lo que el modelo quiere es algo similar a un top-k estricto (hard top-k): peso alto en los tokens coincidentes y peso casi nulo en todos los demás lugares. Softmax es demasiado suave para hacer eso directamente.

La idea diferencial

Divida las proyecciones Q y K de cada cabeza en dos: Q = (Q_1, Q_2) and K = (K_1, K_2). Compute dos mapas de atención:

A_1 = softmax(Q_1 K_1^T / sqrt(d))
A_2 = softmax(Q_2 K_2^T / sqrt(d))

Salida:

DiffAttn = (A_1 - lambda * A_2) V

La resta cancela cualquier distribución de ruido que compartan los dos mapas. Si ambos mapas tienen un peso aproximadamente uniforme en los 127k tokens ajenos (lo cual sucederá en la inicialización aleatoria), estos se cancelan. La señal (el peso concentrado en los pocos tokens realmente relevantes) solo se cancela si aparece en ambos mapas con la misma magnitud, lo cual no sucederá una vez que el modelo se entrene.

lambda es un escalar aprendible por cabeza, parametrizado como lambda = exp(lambda_q1 dot lambda_k1) - exp(lambda_q2 dot lambda_k2) + lambda_init. Puede ser negativo. lambda_init se inicializa por defecto en un número positivo pequeño como 0.8.

Por qué esto se asemeja a la cancelación de ruido dirigida

Pense en dos micrófonos ruidosos que graban la misma voz. Ambos captan al hablante más el ruido de fondo correlacionado. Reste uno del otro y el ruido compartido desaparecerá. La voz sobrevive porque las dos señales difieren en fase o amplitud lo suficiente como para evitar la cancelación total. El lambda por cabeza aprende exactamente este equilibrio. (Wait: "Pense" is Portuguese/typo, should be "Piense" in Spanish).

V1 vs V2: la diferencia

V1 mantuvo la cantidad de parámetros igual a la del Transformer de línea de base. Para obtener dos consultas por cabeza, redujo a la mitad la dimensión de la cabeza. Eso costó expresividad de la cabeza y, lo que es peor, redujo a la mitad el caché de valores (value cache) por cabeza. La decodificación tenía que cargar el caché de valores dos veces por paso (una vez por cada rama de softmax). Resultado: decodificación más lenta que la línea de base a pesar de tener la misma cantidad de parámetros.

V2 duplica el número de cabezas de consulta (query heads) y mantiene las cabezas KV iguales (tomando parámetros prestados de la proyección ascendente). La dimensión de la cabeza sigue siendo la misma que la de la línea de base. Después de la resta, la dimensión extra se proyecta de nuevo hacia abajo para coincidir con la proyección O_W del Transformer de línea de base. Tres cosas ocurren a la vez:

  1. La velocidad de decodificación coincide con la línea de base (el caché KV se carga una sola vez).
  2. FlashAttention se ejecuta sin cambios (sin kernel personalizado).
  3. La intensidad aritmética en la decodificación aumenta (más cómputo por byte cargado desde HBM).

V2 también elimina la RMSNorm por cabeza que V1 usaba para estabilizar la resta. En escalas de preentrenamiento de la clase de 70B, esa RMSNorm desestabilizaba el entrenamiento tardío. V2 la reemplaza con un esquema de inicialización más simple que mantiene estable el entrenamiento sin el módulo adicional.

Cuándo recurrir a esto

Carga de trabajo Beneficio
RAG de contexto largo (64k+) Mapas de atención más limpios, menos citas alucinadas
Benchmarks de aguja en el pajar Incremento sustancial de precisión después de 32k
QA de múltiples documentos Menos interferencia entre documentos
Finalización de código en 8k Marginal, no vale la pena el cambio de arquitectura
Chat corto (< 4k) Esencialmente indistinguible de la línea de base

El valor crece con la longitud del contexto. En 4k tokens, el piso de ruido es lo suficientemente pequeño como para que la atención estándar sea adecuada. En 128k, te está perjudicando.

Cómo se compara con otras características de 2026

Característica ¿Compatible con DIFF V2?
GQA Sí (V2 aumenta las cabezas Q, no las cabezas KV)
MLA (DeepSeek) Sí en principio, no hay artículos publicados que los combinen
MoE Sí (la atención es independiente del bloque MLP)
RoPE Sí (sin cambios)
YaRN / escalado de contexto largo Sí (exactamente donde DIFF ayuda más)
FlashAttention Sí en V2 (era no en V1)
Decodificación especulativa Sí (el cambio de atención es invisible para el bucle de decodificación especulativa)

Implementación

code/main.py implementa la atención diferencial en Python puro. Una consulta simplificada (toy) con una estructura conocida de señal más ruido te permite medir la relación de cancelación de ruido directamente.

Paso 1: atención softmax estándar

Operaciones de matriz de stdlib: listas de listas, matmul manual, softmax con resta del máximo para estabilidad 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]

Paso 2: dividir Q, K en dos mitades

Estilo V1: reduce a la mitad la dimensión de la cabeza. Estilo V2: mantiene la dimensión de la cabeza y duplica el número de cabezas. La implementación simplificada utiliza V1 para mayor claridad pedagógica; la matemática es idéntica, solo difiere la contabilidad de los datos.

Paso 3: dos ramas de softmax + resta

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: los pesos de salida pueden ser negativos. Eso está bien; el caché de valores aún maneja contribuciones con signo. La proyección V posterior absorbe el signo.

Paso 4: medición de la cancelación de ruido

Construya una secuencia sintética de longitud 1024. Coloque el token de señal en una posición conocida, llene el resto con ruido. Compute (a) el peso de atención softmax estándar en la posición de la señal y (b) el peso de atención diferencial. Mida la relación señal-ruido en cada uno. La atención DIFF produce de manera confiable una relación señal-ruido de 3 a 10 veces mayor, dependiendo de cuánto se hayan entrenado las dos ramas para diferir.

Paso 5: contabilidad de parámetros de V1 vs V2

Dada una configuración (hidden=4096, heads=32, d_head=128), imprima:

  • Transformer de línea de base: Q, K, V cada uno de tamaño hidden * hidden, MLP en 4 * hidden.
  • DIFF V1: Q, K cada uno de tamaño hidden * hidden, V de tamaño hidden * hidden (sin cambios), la dimensión de la cabeza se reduce a la mitad internamente. Agrega parámetros lambda por cabeza (O(heads * d_head)).
  • DIFF V2: Q de tamaño 2 * hidden * hidden, K de tamaño hidden * hidden, V de tamaño hidden * hidden. La dimensión extra se proyecta de nuevo hacia abajo antes de O_W. Agrega los mismos parámetros lambda.

El modelo simplificado mide el costo de parámetros adicionales para V2 (aproximadamente hidden * hidden extra por bloque de atención) y lo imprime.

Úselo

DIFF V2 aún no se distribuye en todos los servidores de inferencia de producción a partir de abril de 2026, pero la integración está en marcha en vLLM y SGLang. Mientras tanto, el patrón aparece en:

  • Modelos de producción internos de Microsoft para contexto largo.
  • Replicaciones de investigación en varias ejecuciones de entrenamiento de modelos abiertos que apuntan a un contexto de más de 256k.
  • Arquitecturas híbridas que combinan atención DIFF con atención de ventana deslizante (sliding-window) en capas alternas.

Cuándo recurrir a esto en 2026:

  • Al entrenar un nuevo modelo desde cero que apunte a un contexto efectivo de más de 64k. Agregue la atención diferencial desde el principio; reentrenar más tarde es costoso.
  • Al realizar el ajuste fino (fine-tuning) de un modelo de contexto largo donde los fallos de "perdido en el medio" (lost-in-the-middle) dominan su evaluación. Un LoRA en las proyecciones Q puede aproximar la estructura de DIFF.

Cuándo no hacerlo:

  • Si está sirviendo un modelo denso preentrenado con un rendimiento de contexto largo estable. El costo del reentrenamiento rara vez se amortiza con los pesos existentes.
  • Su contexto siempre está por debajo de 16k. El piso de ruido es insignificante.

Envíe para Producción

Esta lección produce el archivo outputs/skill-diff-attention-integrator.md. Dada la arquitectura de un modelo, la longitud del contexto objetivo, el perfil de alucinación y el presupuesto de entrenamiento, genera un plan de integración para agregar atención diferencial a una nueva ejecución de preentrenamiento o ajuste fino con LoRA.

Ejercicios

  1. Ejecute code/main.py. Verifique que la relación señal-ruido informada para la atención diferencial sea mayor que la de la atención softmax estándar en la consulta sintética. Varíe la amplitud del ruido y muestre el punto de cruce donde la atención estándar se vuelve inutilizable.

  2. Calcule la diferencia en la cantidad de parámetros desde la línea de base hasta DIFF V1 y desde la línea de base hasta DIFF V2 para un modelo de clase 7B (hidden=4096, heads=32, d_head=128, 32 capas). Muestre qué componentes ganaron parámetros y cuáles permanecieron iguales.

  3. Lea la Sección 3 del artículo de DIFF V1 (arXiv:2410.05258) y la Sección 2 del blog de DIFF V2 en Hugging Face. En dos oraciones, explique por qué la RMSNorm por cabeza de V1 era necesaria y por qué V2 pudo eliminarla sin causar divergencia en el entrenamiento.

  4. Implemente una ablación: compute la atención diferencial con lambda = 0 (primera softmax pura) y lambda = 1 (resta completa). En la consulta sintética, mida cómo cambia la relación señal-ruido a lo largo del barrido. Identifique el lambda que maximiza la relación señal-ruido.

  5. Extienda el modelo simplificado a GQA + DIFF V2. Elija 8 cabezas KV y 32 cabezas Q. Muestre que el tamaño del caché KV coincide con un modelo GQA de línea de base con la misma configuración (8, 32).

Términos Clave

Término Lo que la gente dice Lo que realmente significa
Atención diferencial "Dos softmaxes restadas entre sí" Divide Q, K en dos mitades, computa dos mapas softmax, resta el segundo (escalado por lambda) del primero y luego multiplica por V
Piso de ruido "La cola no nula de softmax" El peso O(1/N) que softmax asigna a cada token no relacionado, el cual suma O(1) a lo largo de contextos largos
lambda "La escala de resta" Escalar aprendible por cabeza parametrizado como exp(lq1.lk1) - exp(lq2.lk2) + lambda_init; puede ser negativo
DIFF V1 "La versión de ICLR 2025" Differential Transformer original; reduce a la mitad la dimensión de la cabeza para preservar la cantidad de parámetros, requiere un kernel personalizado, decodificación más lenta
DIFF V2 "La solución de enero de 2026" Duplica las cabezas Q manteniendo las cabezas KV; iguala la velocidad de decodificación de la línea de base y funciona con FlashAttention
RMSNorm por cabeza "El estabilizador de V1" Normalización adicional que V1 aplicaba después de la diferencia; V2 la eliminó para evitar la inestabilidad en el entrenamiento tardío
Relación señal-ruido "Cuánta atención se desperdicia" Relación entre el peso en la posición de la señal real y el peso promedio en las posiciones no relacionadas
Perdido en el medio "Modo de fallo de contexto largo" Fenómeno empírico en el que la precisión de recuperación cae para documentos en medio de un contexto largo; la atención DIFF reduce esto
Intensidad aritmética "FLOPs por byte cargado" Relación que V2 aumentó en la decodificación al duplicar las consultas por carga de KV; importante para la decodificación limitada por memoria

Lectura Adicional

0 lifetime access. Curriculum based on AI Engineering from Scratch by Rohit Ghumare (MIT, used under attribution).