34 · Atención enmascarada + cruzada (cross)
El bloque decoder añade dos cosas al bloque encoder: auto-atención ENMASCARADA (sin mirar el futuro) y atención CRUZADA (consultas del decoder, claves/valores del encoder).
El bloque decoder = auto-atención ENMASCARADA (una posición no puede ver el futuro) → Add & Norm → atención CRUZADA (Q del decoder, K/V del encoder) → Add & Norm → FFN → Add & Norm.
Sin esto:
Sin el enmascaramiento el decoder haría trampa leyendo tokens futuros durante el entrenamiento; sin atención cruzada nunca podría mirar la entrada que está traduciendo.
El bloque encoder (lección 33) procesa toda su entrada de una vez: cada posición puede atender libremente a cualquier otra posición. El bloque decoder mantiene el mismo esqueleto — atención, Add & Norm, FFN, Add & Norm — pero añade dos piezas nuevas encima del diseño del encoder.
1. Auto-atención enmascarada. El decoder genera tokens uno a uno, de izquierda a derecha. En el momento de la generación, la posición t simplemente no tiene acceso a las posiciones t+1, t+2, … — todavía no se han producido. Sin embargo, durante el entrenamiento alimentamos toda la secuencia objetivo a la vez por paralelismo, así que debemos prohibir artificialmente que cada posición atienda a posiciones FUTURAS. Lo hacemos con una máscara causal: antes del softmax, sumamos -∞ a cada puntuación que mira hacia adelante. Tras el softmax esas entradas se vuelven exactamente 0. Esto es lo que hace al decoder autoregresivo — cada predicción depende solo de lo que vino antes.
2. Atención cruzada (cross-attention). Este es el puente entre las dos pilas. En la subcapa de atención cruzada, las consultas Q vienen del decoder (su estado actual), mientras que las claves K y los valores V vienen de la salida del encoder. Así, el decoder, en cada paso, consulta toda la entrada codificada y extrae exactamente la información que necesita. Este es precisamente el mismo flujo de información que el vector de contexto de la atención seq2seq del Capítulo 7, c_t = Σ_i α_{t,i} · h_i — solo que ahora expresado como una atención Q/K/V limpia sobre los estados ocultos del encoder.
Así que el bloque decoder completo son tres subcapas, cada una envuelta en Add & Norm:
x → Auto-Atención Enmascarada → Add & Norm → Atención Cruzada(Q=x, K=V=enc_out) → Add & Norm → FFN → Add & Norm
El encoder tiene dos subcapas por bloque; el decoder tiene tres. Esa subcapa extra de atención cruzada es lo que permite a la pila de salida condicionarse sobre la pila de entrada.
Python (in browser)
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Las flechas verdes punteadas son las conexiones residuales que rodean cada subcapa.
Read-along de PyTorch: nn.TransformerDecoderLayer/Decoder, más nn.Transformer.generate_square_subsequent_mask para la máscara causal
¿Por qué el decoder usa una máscara causal (look-ahead) durante el entrenamiento?
- El bloque decoder = auto-atención enmascarada → Add & Norm → atención cruzada → Add & Norm → FFN → Add & Norm: tres subcapas frente a las dos del encoder.
- La máscara causal suma -inf a las puntuaciones que miran al futuro antes del softmax (usa np.triu, k=1), haciendo al decoder autoregresivo — una posición no puede ver tokens que aún no ha generado.
- La atención cruzada toma Q del decoder y K/V de la salida del encoder, que es exactamente el vector de contexto del Capítulo 7 c_t = Σ_i α_{t,i}·h_i en forma Q/K/V.
La auto-atención enmascarada es el corazón de todo LLM solo-decoder estilo GPT; la atención cruzada impulsa modelos encoder-decoder como T5 y el Transformer de traducción original, y el lado decoder de Whisper.
Si lo quitas: Verías 'máscara causal', 'atención cruzada' y 'solo-decoder vs encoder-decoder' en cada paper de LLM sin captar las dos pequeñas adiciones que convierten un bloque encoder en un decoder generativo.