PASO 6b · INTUICIÓN VISUAL

FFN sin matemáticas

Vamos a entender los 4 puntos del FFN desde otro ángulo, con visualizaciones interactivas y analogías concretas.

🎯 FFN de un vistazo

Antes de zambullirte en los detalles, este es el panorama completo. Si solo leés esta sección, ya entendiste el 80%:

PROPÓSITO

¿Para qué sirve?

Para que cada token procese su información después de que la atención mezcló datos entre tokens. Es la fase de "pensar individualmente" sobre lo recibido.

APORTE

¿Qué le da al modelo?

Dos cosas que la atención no puede dar:
1) No-linealidad (vía ReLU) → aprender patrones complejos.
2) Capacidad de cómputo (vía la expansión) — de hecho, el FFN concentra la mayoría de los parámetros del modelo.

NECESIDAD

¿Por qué es indispensable?

Sin FFN, el Transformer:
a) Solo aprende patrones lineales (no podría modelar lenguaje).
b) Sus muchas capas se colapsarían a una sola (no podrías "apilar" para aprender más).

En la práctica: en GPT-3, los FFN concentran más del 60% de los parámetros aprendidos. Es decir, la mayor parte del "conocimiento" del modelo vive dentro de los FFN, no en las matrices de atención. NO es un complemento menor — es donde está el núcleo del cómputo.

↓ A continuación, las visualizaciones que sustentan cada uno de estos puntos ↓

1. ¿Por qué necesitamos no-linealidad?

El argumento abstracto "operaciones lineales son limitadas" se entiende mejor con un ejemplo visual concreto. Vamos al problema clásico que demuestra esto: XOR.

El problema XOR (en cristiano)

Imaginá que tenés 4 puntos en una hoja, distribuidos así:

  • Esquina inferior izquierda: ⭕ (clase A)
  • Esquina superior derecha: ⭕ (clase A)
  • Esquina superior izquierda: ❌ (clase B)
  • Esquina inferior derecha: ❌ (clase B)

Tu tarea: trazar UNA línea recta que deje todos los ⭕ de un lado y todos los ❌ del otro.

🎮 Intentalo vos: mové la línea para tratar de separar las clases

Por más que muevas la línea, NO PODÉS separar los ⭕ de los ❌ con una sola recta. Esto se llama "no linealmente separable". Cualquier modelo que solo pueda dibujar líneas rectas nunca aprenderá este patrón.

El gran descubrimiento: agregando UNA función no-lineal (ReLU) entre dos capas lineales, ahora podés "doblar" la línea y aprender este patrón. Sin no-linealidad, sos solo líneas rectas. Con no-linealidad, podés hacer cualquier forma.

Antes vs Después de agregar ReLU

❌ Sin no-linealidad (solo lineal)

Solo puede dibujar UNA línea recta. Imposible separar las 4 esquinas correctamente.

✓ Con ReLU (no-lineal)

Puede "doblar" y crear regiones complejas. ¡Funciona!

Aplicado al lenguaje: el lenguaje está LLENO de patrones tipo XOR. Por ejemplo: "el significado de 'banco' depende de si va con 'plaza' O con 'dinero', pero no ambos a la vez". Sin no-linealidad, el modelo no podría aprender estas reglas condicionales.

2. ¿Qué hace ReLU realmente? Una nueva forma de verlo

Ya viste que ReLU(x) = max(0, x) aplasta los negativos. Pero la pregunta es: ¿para qué sirve aplastarlos? Acá viene la intuición clave.

ReLU = un "interruptor de encendido / apagado"

Imaginá que el resultado de la multiplicación matricial es como una señal que llega a una neurona. Esa señal puede ser:

  • Positiva: "este patrón está presente en el input" → ReLU deja pasar la señal.
  • Negativa: "este patrón NO está presente" → ReLU apaga la neurona (la pone en 0).

Cada neurona en la capa expandida es como un detector de un patrón específico. Si el patrón está → la neurona se enciende y contribuye. Si no está → la neurona se apaga y queda en silencio.

🎮 Demo: ReLU como filtro de neuronas

Cada barra de abajo es una "neurona" con su valor crudo (antes de ReLU). Mové los sliders y mirá cómo ReLU enciende las positivas y apaga las negativas:

🔥 = neurona "encendida" (la señal pasa) · 💤 = neurona "apagada" (señal bloqueada)

La magia: cuando tenés MUCHAS neuronas con ReLU, distintas combinaciones se "encienden" para distintos inputs. La red aprende a configurar las neuronas como "detectores" de patrones útiles (por ejemplo, "soy una palabra antes de un verbo", "soy un sustantivo masculino", etc.). El conjunto de neuronas encendidas para un input es como una "huella digital" del input.

3. ¿Qué significa "expandir" y "contraer" exactamente?

Antes de hablar de POR QUÉ lo hacemos, aclaremos QUÉ significa literalmente. Porque las palabras "expandir" y "contraer" suenan físicas, pero acá significan algo muy concreto.

Definición sin metáforas:
  • "Expandir" = pasar de un vector con POCOS números a uno con MÁS números.
  • "Contraer" = pasar de un vector con MUCHOS números a uno con MENOS números.
Eso es todo. No hay nada físico que se "estire" o "encoja". Solo cambia la cantidad de números en la lista.

Ejemplo concreto con números mínimos

Imaginá este vector chiquito de dim 2 (2 números):

input = [3, 5]

Expandir 2 → 4

Quiero convertirlo en un vector de 4 números. Para eso multiplico por una matriz que tenga 4 columnas:

matriz expansora (2 filas × 4 columnas):

      col0   col1   col2   col3
fila0 [0.5,   0.2,   0.1,   0.3]
fila1 [0.1,   0.4,   0.5,   0.2]

Aplico la multiplicación (producto punto con cada columna):

out[0] = (3 × 0.5) + (5 × 0.1) = 1.5 + 0.5 = 2.0
out[1] = (3 × 0.2) + (5 × 0.4) = 0.6 + 2.0 = 2.6
out[2] = (3 × 0.1) + (5 × 0.5) = 0.3 + 2.5 = 2.8
out[3] = (3 × 0.3) + (5 × 0.2) = 0.9 + 1.0 = 1.9

vector expandido = [2.0, 2.6, 2.8, 1.9]   ← AHORA TIENE 4 NÚMEROS

Empecé con 2 números, terminé con 4. Eso es "expandir".

Contraer 4 → 2

Ahora quiero volver de 4 números a 2. Para eso multiplico por una matriz que tenga 2 columnas:

matriz contraedora (4 filas × 2 columnas):

      col0   col1
fila0 [0.2,  0.3]
fila1 [0.4,  0.1]
fila2 [0.1,  0.5]
fila3 [0.3,  0.2]

Aplico la multiplicación con el vector expandido [2.0, 2.6, 2.8, 1.9]:

out[0] = (2.0×0.2) + (2.6×0.4) + (2.8×0.1) + (1.9×0.3)
       =    0.40   +    1.04   +    0.28   +    0.57   = 2.29

out[1] = (2.0×0.3) + (2.6×0.1) + (2.8×0.5) + (1.9×0.2)
       =    0.60   +    0.26   +    1.40   +    0.38   = 2.64

vector contraído = [2.29, 2.64]   ← VOLVIÓ A TENER 2 NÚMEROS

Empecé con 4 números, terminé con 2. Eso es "contraer".

La regla clave: la FORMA de la matriz controla el tamaño del output

Matriz Input Output ¿Qué hizo?
2 × 4 dim 2 dim 4 expandió 2→4
4 × 2 dim 4 dim 2 contrajo 4→2
4 × 8 dim 4 dim 8 expandió 4→8 (caso FFN)
8 × 4 dim 8 dim 4 contrajo 8→4 (caso FFN)

Regla rápida: la cantidad de columnas de la matriz = la dimensión del output. Si la matriz tiene más columnas que filas → expandís. Si tiene menos columnas que filas → contraés.

En el FFN del Transformer (con d_model=4, d_ff=8)

Vector de "perro" (dim 4):  [+0.5, +1.1, +0.7, +0.8]
                                     │
                                     │  multiplicar por W₁
                                     │  (matriz 4×8 → produce 8 números)
                                     ↓
Vector "expandido" (dim 8): [+0.65, -0.12, +0.40, -0.30, +0.18, +0.20, -0.15, +0.50]
                                     │
                                     │  aplicar ReLU
                                     │  (NO cambia la cantidad de números,
                                     │   solo aplasta los negativos)
                                     ↓
Vector "activado" (dim 8):  [+0.65,  0.00, +0.40,  0.00, +0.18, +0.20,  0.00, +0.50]
                                     │
                                     │  multiplicar por W₂
                                     │  (matriz 8×4 → produce 4 números)
                                     ↓
Vector "contraído" (dim 4): [+0.7, +0.0, +0.8, +0.7]

Empezás con 4 números, los expandís a 8 (más espacio de trabajo), ReLU filtra cuáles "se encienden", y finalmente contraés de vuelta a 4. Es un viaje de ida y vuelta en la cantidad de números.

¿Y POR QUÉ hacer este viaje?

Ya que entendiste qué pasa mecánicamente, ahora vamos al "para qué". La razón clave es que en el espacio expandido tenés más capacidad.

Más neuronas = más "pliegues" que el modelo puede aprender

Cada celda del vector expandido (cada "neurona") con ReLU agrega UN pliegue a la función que la red puede aprender. Con pocas neuronas, podés hacer pocas "esquinas". Con muchas neuronas, podés aproximar cualquier curva.

🎮 Mové el slider y mirá cuánto detalle podés capturar:

2

Línea azul: la función "objetivo" que queremos aprender. Línea naranja: lo que la red puede aproximar con N neuronas ReLU. Con pocas neuronas → aproximación cruda. Con muchas → casi perfecta.

Por eso "expandimos" en FFN: al pasar de dim 4 → 8 (o 768 → 3072 en GPT-2), creamos más neuronas en la capa intermedia, lo que le da al modelo más "detectores de patrones" disponibles. Después contraemos para volver al tamaño esperado por el siguiente bloque, pero la "magia" ya ocurrió en el espacio expandido.

Analogía concreta: la bolsa de viaje

Imaginá que tenés que viajar y solo entran 4 cosas en tu mochila. Pero antes de meterlas, necesitás clasificarlas y decidir qué empacar.

  • Expandir: sacás TODA tu ropa de los cajones y la ponés sobre la cama. Ahora tenés 8 prendas desparramadas.
  • ReLU (el filtro): mirás cada prenda. "¿Esta me sirve? Sí → la dejo. ¿Esta no? → al ropero". Apagás las que no sirven.
  • Contraer: de las prendas útiles, elegís las 4 mejores y las metés en la mochila.

Resultado: tenés 4 prendas en la mochila (mismo tamaño que el espacio disponible), pero son las 4 MEJORES porque tuviste un "espacio de trabajo" más grande en el medio para decidir.

Si hubieras saltado del cajón directo a la mochila sin sacar nada sobre la cama, no habrías podido evaluar bien qué prendas convenían.

Analogía alternativa: la sala de juicio

Imaginá un juicio. El input es "la evidencia del caso" (un vector pequeño). El veredicto final también es chico ("culpable" o "inocente"). Pero en el medio, hay 12 jurados que cada uno evalúa la evidencia desde su propia perspectiva. Después se reúnen y combinan sus votos en el veredicto.

  • Sin los 12 jurados (sin expandir): el juicio sería superficial, una sola perspectiva.
  • Con los 12 jurados (con expansión): cada uno detecta algo distinto en la evidencia. Combinados, dan un veredicto mucho más robusto.

El FFN es eso: el input se "abre" a muchos detectores en el medio (cada neurona = un jurado), y después se "combinan" en el output final.

El concepto en una frase: Expandimos para tener "más espacio de trabajo" donde aplicar ReLU y procesar más patrones. Después contraemos para volver al tamaño que necesita el siguiente paso del Transformer.

4. ¿Cómo encaja FFN en el Transformer?

Para entender FFN en contexto, necesitás ver el "bloque" completo del Transformer y los dos sub-bloques que lo componen:

Input (3 vectores de dim 4)
MULTI-HEAD ATTENTION
Mezcla información ENTRE tokens.
Cada token "habla" con los demás.
FEED-FORWARD NETWORK
Procesa cada token POR SEPARADO.
Aplica no-linealidad para extraer patrones.
Output (3 vectores de dim 4)

Los dos roles complementarios

🔀 Atención: comunicación entre tokens

El rol: "qué información tomar de los otros tokens". Es la fase donde "perro" averigua que "come" es relevante para entenderse en esta frase.

Limitación: las operaciones son lineales. La atención puede pesar y combinar, pero no puede "transformar" la información a algo cualitativamente distinto.

🧠 FFN: procesamiento dentro de cada token

El rol: "qué hacer con la información que ya tiene cada token". Es la fase donde "perro" (ya con info de toda la frase) la procesa para extraer significado más profundo.

Aporta lo que atención no puede: no-linealidad + más capacidad de cómputo (vía la expansión).

Analogía completa: una reunión de equipo
  • Atención = el brainstorming grupal: todos se hablan entre sí, comparten ideas, escuchan las ideas relevantes de los demás.
  • FFN = la reflexión individual: después del brainstorming, cada persona se queda pensando individualmente sobre lo que escuchó, conecta puntos, saca sus propias conclusiones.
Ninguna de las dos fases por sí sola sería suficiente. La reunión grupal sin reflexión sería caos. La reflexión sin la reunión sería ignorancia. Juntas, producen entendimiento.

¿Y por qué se repite muchas veces?

Este bloque (attention + FFN) se llama una "capa" del Transformer y se apila muchas veces. GPT-2 small tiene 12 capas. GPT-3 tiene 96 capas. En cada nueva capa, el modelo puede extraer patrones más abstractos:

Sin FFN entre cada atención, esas capas serían matemáticamente equivalentes a una sola. FFN es lo que permite que apilar capas realmente agregue capacidad.

El dato contundente: ¿dónde vive realmente el modelo?

Una percepción común equivocada: "atención es el corazón del Transformer, el FFN es un agregado menor". Falso. Mirá la distribución real de parámetros en modelos famosos:

Modelo % en atención % en FFN
GPT-2 small ~33% ~67%
GPT-3 ~33% ~67%
LLaMA-2 7B ~28% ~72%

Dicho de otra forma: en GPT-3 (175 mil millones de parámetros), más de 100 mil millones viven en los FFN. La atención decide "qué mirar", pero el FFN es donde realmente se procesa y almacena la mayor parte del conocimiento aprendido.

Recientes interpretaciones de los FFN: los investigadores empezaron a ver los FFN como "memoria asociativa de patrones". Cada par de neuronas (una en W₁, otra en W₂) actúa como un par "clave-valor": cuando el input activa cierta neurona en W₁ (clave), W₂ "escribe" cierto patrón como respuesta (valor). El modelo aprende miles de estos pares, formando una gran memoria de hechos y reglas.

5. Resumen final: el FFN en 3 dimensiones

Ahora que recorriste todas las visualizaciones, podés releer el "at-a-glance" del principio con perspectiva completa. Acá lo refresco con un nivel más de detalle:

PROPÓSITO — ¿para qué sirve?

FFN procesa la información dentro de cada token, después de que la atención mezcló información ENTRE tokens. Si atención es "escuchar lo que dicen los demás", FFN es "pensar individualmente sobre lo que escuchaste". Cada token recibe el FFN de forma independiente, pero todos usan las mismas matrices W₁ y W₂.

APORTE — ¿qué le da al modelo?

Dos cosas críticas que la atención no puede aportar:

  • No-linealidad (vía ReLU): aplastar los negativos crea los "pliegues" que permiten aprender patrones complejos como XOR — y todas las reglas condicionales del lenguaje.
  • Capacidad de cómputo (vía expansión): al pasar a un espacio dim 8 (o 3072 en GPT-2), el modelo tiene "más espacio de trabajo" donde detectar muchos patrones simultáneamente. De hecho, el 60-70% de los parámetros del modelo viven en los FFN.
NECESIDAD — ¿por qué es indispensable?

Si removieras los FFN del Transformer, pasarían dos cosas muy graves:

  • (a) El modelo solo aprendería funciones lineales. El lenguaje no es lineal — depende de contextos condicionales, ambigüedades, jerarquías. Sería incapaz de modelar gramática o significado mínimamente complejo.
  • (b) Apilar capas no agregaría nada. Matemáticamente, 96 capas de pura atención lineal son equivalentes a 1 sola capa. FFN es lo que rompe esa equivalencia y permite que cada capa nueva aprenda algo cualitativamente distinto.

En otras palabras: sin FFN, no hay LLM posible. El Transformer sería un truco matemático bonito pero incapaz de aprender lenguaje.

Cuando esto te resulte claro, volvé al archivo principal del paso 6 para ver los cálculos matemáticos con esta nueva perspectiva.