7 La red feed-forward (FFN)
Dónde estamos. La atención (Cap. 4–5) hace que cada token recoja información de los demás. Pero recoger no es procesar: ahora cada token necesita pensar sobre lo que ha reunido. De eso se encarga la red feed-forward (FFN), la otra mitad de cada bloque del transformer. Es la pieza que más parámetros tiene del modelo —y, sin embargo, la que muchos tutoriales despachan en una línea—.
7.1 La idea en una frase
Tras la atención, cada token pasa por una pequeña red de dos capas que lo transforma —la misma para todos los tokens, aplicada a cada uno por separado—.
7.2 Conceptos clave y su papel en el transformer
Antes de entrar en detalle, definimos los términos de este capítulo y para qué sirve cada uno dentro de un transformer:
- FFN (red feed-forward). Definición: una red de dos capas (ensanchar → no linealidad → comprimir) aplicada a cada token por separado. En el transformer: es el paso de “cálculo” o “pensar”; mientras la atención mueve información entre tokens, la FFN la procesa dentro de cada uno.
- Procesamiento “position-wise”. Definición: aplicar los mismos pesos a cada token de forma independiente. En el transformer: garantiza que la FFN nunca pasa información de un token a otro —ese trabajo es exclusivo de la atención—.
- Expansión (ancho intermedio, \(d_{ff}\)). Definición: la capa de en medio es más ancha que el vector del modelo, típicamente 4×. En el transformer: da sitio para extraer muchas características en paralelo antes de comprimir lo útil de vuelta.
- Activación / no linealidad (\(\sigma\)). Definición: la función (ReLU, GELU, SwiGLU…) que se aplica entre las dos capas. En el transformer: es imprescindible; sin ella las dos tablas se fundirían en una y el bloque no podría calcular nada complejo.
- Gating (SwiGLU). Definición: una segunda proyección que decide, elemento a elemento, cuánto dejar pasar de la primera. En el transformer: actúa como un filtro aprendido sobre la activación; por la tabla extra, los modelos que lo usan reducen el ancho a ≈2,7× para no aumentar parámetros.
- Memoria clave-valor. Definición: lectura de la FFN según la cual las filas de \(W_1\) detectan patrones (claves) y \(W_2\) guarda lo que esos patrones escriben (valores). En el transformer: convierte la FFN en un almacén de asociaciones “si veo este patrón → escribo esto”.
- Conocimiento localizado (ROME). Definición: los hechos concretos viven sobre todo en las FFN intermedias y se pueden editar tocando esos pesos. En el transformer: hace de la FFN el almacén editable de conocimiento del modelo.
- Superposición / polisemia. Definición: el modelo empaqueta más características que neuronas disponibles, así que muchas neuronas se activan con cosas no relacionadas. En el transformer: es la razón de que “una neurona = un concepto” sea la excepción, no la regla.
Con esto en mente, veamos qué papel cumple la FFN frente a la atención.
7.3 Para qué sirve (su papel en el transformer)
Aquí está la clave que ordena todo el bloque: la atención y la FFN hacen trabajos opuestos y complementarios.
- La atención mueve información entre tokens (mezcla, enruta): es lo social.
- La FFN procesa la información dentro de cada token, por separado: es lo individual, el paso de “cálculo” o “pensar”.
Y se alternan, bloque tras bloque: mezclar (atención) → procesar (FFN) → mezclar → procesar… Sin la FFN, el modelo solo sabría promediar y enrutar, pero no calcular características ricas a partir de lo recogido.
🧩 Analogía. La atención es la reunión de equipo: todos comparten notas y cada uno se lleva lo relevante de los demás. La FFN es cada persona volviendo a su mesa, a solas, a pensarlo y actualizar su cuaderno. Reunión (atención) → reflexión a solas (FFN), una y otra vez en cada bloque.
7.4 La fórmula
Es una red de dos capas con una “activación” en medio:
\[ \text{FFN}(x) = W_2\,\sigma(W_1 x + b_1) + b_2 \tag{7.1}\]
Qué hace cada pieza:
- \(W_1\) = una tabla aprendida que ensancha el vector del token, proyectándolo a un espacio más grande (ahí caben más “características” calculadas a la vez).
- \(\sigma\) = la activación (la no linealidad). Es la pieza imprescindible: sin ella, \(W_1\) y \(W_2\) se fundirían en una sola tabla y todo el bloque sería una simple multiplicación —incapaz de calcular nada complejo—. La activación es lo que permite representar relaciones que no son meras proporciones.
- \(W_2\) = una segunda tabla que comprime de vuelta al tamaño original (\(d_{model}\)), para devolver el resultado al flujo residual.
- \(b_1, b_2\) = sesgos (un término constante que desplaza cada capa).
En una frase: ensanchar → aplicar la no linealidad → comprimir.
7.5 La expansión: ¿por qué más ancho en medio?
La capa intermedia es más ancha que el vector del modelo —típicamente 4×— (en el Transformer original, 512 → 2048; en GPT-2, 768 → 3072). ¿Por qué? El espacio ancho da sitio para extraer muchas características en paralelo antes de comprimir lo útil de vuelta. Piensa en abrir un abanico de posibilidades, quedarte con lo que importa, y volver a plegarlo.
Ojo: el “4×” es una convención, no una ley. Los modelos modernos tipo LLaMA usan ≈2,7× porque su activación (SwiGLU) añade una tabla extra, y reducen el ancho para mantener igual el número de parámetros.
7.6 Las activaciones: ReLU → GELU → SwiGLU
La activación \(\sigma\) ha ido evolucionando, pero su trabajo es siempre el mismo: meter la no linealidad que hace posible el cálculo complejo.
- ReLU (original): deja pasar lo positivo, corta en seco lo negativo a 0.
- GELU (GPT-2/3, BERT): una versión suave de ReLU, sin el corte brusco.
- SwiGLU (LLaMA, PaLM): añade un gating —una segunda proyección que decide, elemento a elemento, cuánto dejar pasar de la primera—. Es como un filtro aprendido encima de la activación.
7.7 Un detalle que se confunde mucho
La FFN se aplica a cada token por separado y con los mismos pesos (“position-wise” en el paper). Nunca pasa información de un token a otro —ese trabajo es exclusivo de la atención—. Es un error común creer que la FFN “combina palabras”: no, solo procesa cada una en su sitio.
7.8 La FFN se lleva la mayor parte de los parámetros
Aunque parezca el componente humilde, la FFN concentra ~2/3 de los parámetros de un transformer (por culpa de ese ancho 4×).
Por capa, la atención usa ≈ \(4\,d_{model}^2\) parámetros (las tablas Q, K, V y la de salida). La FFN usa \(2\,d_{model}\cdot d_{ff} = 2\,d_{model}\,(4\,d_{model}) = 8\,d_{model}^2\). Así, FFN/total \(= 8/(8+4) = 2/3\). (Aproximado: ignora embeddings y normalización, y cambia con el ancho y con GQA.)
7.9 Lo fascinante: la FFN es una “memoria”
¿Qué guarda realmente la FFN? Una respuesta preciosa: funciona como una memoria clave-valor (Geva et al. 2021). Las filas de \(W_1\) actúan como claves que detectan patrones en la entrada (en las capas bajas, patrones superficiales/ sintácticos; en las altas, semánticos), y \(W_2\) guarda los valores que esos patrones escriben hacia la salida. La FFN no es un revoltijo: es un almacén de asociaciones “si veo este patrón → escribo esto”.
Si esto es una memoria, ¿se puede editar? Sí. Los hechos del tipo “la capital de Francia es París” están localizados sobre todo en las FFN de las capas intermedias, y se puede cambiar un hecho concreto editando directamente esos pesos —es lo que hace el método ROME (Meng et al. 2022)—. La FFN es, en buena medida, el almacén editable de conocimiento del modelo.
7.10 ¿Y las “neuronas” se entienden?
Sería bonito que cada neurona de la capa ancha representara un concepto limpio. En la práctica, muchas son polisémicas (se activan con cosas no relacionadas), por un fenómeno llamado superposición: el modelo empaqueta más características que neuronas disponibles. Algunas neuronas sí son interpretables, pero conviene no exagerar: “una neurona = un concepto” es la excepción, no la regla. (Lo retomamos en la Parte VII, interpretabilidad.)
7.11 En código
import torch, torch.nn as nn
d_model, d_ff = 768, 3072 # GPT-2 small: expansión 4×
ffn = nn.Sequential(
nn.Linear(d_model, d_ff), # W1: ensancha 768 -> 3072
nn.GELU(), # la no linealidad
nn.Linear(d_ff, d_model), # W2: comprime 3072 -> 768
)
x = torch.randn(5, d_model) # 5 tokens
print(ffn(x).shape) # (5, 768): mismo tamaño, listo para el residualFíjate: entra y sale con el mismo tamaño (\(d_{model}\)), porque su salida se suma al flujo residual (Cap. 3). Y se aplica a los 5 tokens por igual, cada uno por su cuenta.
7.12 Resumen
- La FFN es una red de dos capas (ensanchar → no linealidad → comprimir) que procesa cada token por separado.
- Función: mientras la atención mueve info entre tokens, la FFN la procesa dentro de cada uno; el bloque alterna mezclar→procesar. Sin su no linealidad, no habría cálculo complejo.
- La capa intermedia es ~4× más ancha (convención; SwiGLU usa ≈2,7×).
- La FFN concentra ~2/3 de los parámetros.
- Funciona como memoria clave-valor (Geva et al. 2021) y es donde viven los hechos (editables, ROME (Meng et al. 2022)). Sus neuronas suelen ser polisémicas (superposición).
Siguiente (Capítulo 7): ya tenemos atención (mezclar) y FFN (procesar). Falta el andamiaje que mantiene todo en pie al apilar muchas capas: conexiones residuales y normalización.
7.13 Ejercicios
- La no linealidad. Explica por qué, si quitas \(\sigma\), las dos capas \(W_1\) y \(W_2\) equivalen a una sola. ¿Qué pierde el modelo?
- La cuenta. Con \(d_{model}=1024\) y expansión 4×, ¿cuántos parámetros tiene \(W_1\)? ¿Y \(W_2\)? (Ignora sesgos.)
- Reparto de trabajo. Para cada tarea, di si la hace la atención o la FFN:
- conectar “ella” con su referente; (b) decidir que un token activa el concepto “capital de país”; (c) promediar información de tokens lejanos.
- Editar un hecho. Si los hechos viven en las FFN intermedias, ¿por qué tendría sentido editar ahí y no en la capa de embeddings? (Piensa en qué guarda cada una.)