Las dos piezas "humildes" que hacen posible apilar muchas capas. Sin ellas, los Transformers profundos no funcionarían — los gradientes desaparecerían y las señales se distorsionarían entre capas.
Este paso introduce dos operaciones (Residual y LayerNorm) que se aplican alrededor de cada sub-bloque del Transformer. Si solo leés esta sección, ya entendiste el 80%:
Hacer posible apilar muchas capas. Son dos "pegamentos":
Residual = sumar el input original al output del sub-bloque.
LayerNorm = normalizar el vector a media 0 y desviación estándar 1.
Residual aporta un "canal libre" por donde la información original y los gradientes fluyen sin distorsionarse a través de las capas.
LayerNorm aporta una escala estable y predecible: no importa qué pasó antes, cada vector sale "calibrado".
Sin estas dos piezas, apilar 96 capas sería imposible:
Sin residual → la info original se pierde y los gradientes se desvanecen (no se puede entrenar profundo).
Sin LayerNorm → los valores explotan o se desvanecen entre capas.
x' = LayerNorm( x + Attention(x) ) ← residual + norm alrededor de atención x'' = LayerNorm( x' + FFN(x') ) ← residual + norm alrededor de FFNEso es todo el bloque Transformer. Atención y FFN ya los entendés; Residual y LayerNorm los explicamos ahora.
↓ A continuación, el detalle de cada pieza con ejemplos y visualizaciones ↓
GPT-3 tiene 96 bloques apilados. Cada bloque transforma el vector que recibe. Sin las dos piezas de este paso, hay dos problemas serios que aparecen al apilar tantas capas:
Imaginá que tenés un sub-bloque (atención o FFN) que toma un vector x y produce un nuevo vector sublayer(x). Una conexión residual hace algo trivial:
Es decir: en lugar de quedarte con la salida del sub-bloque, le sumás el input original. Eso es todo. No hay matemática complicada.
Si sublayer(x) = 0 (sub-bloque no aporta nada), el output sigue siendo x. La información del input nunca se pierde, en el peor caso pasa intacta.
Pensalo así: si la salida es output = x + sublayer(x), entonces sublayer(x) aprende a producir la "diferencia" o "cambio" que se le aplica a x. La capa no tiene que reconstruir todo desde cero — solo tiene que aprender qué agregar.
Es mucho más fácil aprender "qué pequeña corrección hacer" que "cómo reconstruir todo el vector desde cero".
Durante el entrenamiento, los "gradientes" (las señales que dicen cómo ajustar los pesos) tienen que viajar desde la salida hacia los pesos de cada capa. En redes muy profundas sin residual, los gradientes se debilitan al pasar por muchas capas y desaparecen (esto se llama "vanishing gradients").
Las conexiones residuales son como una autopista que permite a los gradientes saltearse capas y llegar limpios hasta atrás. Hace posible entrenar redes de 100+ capas.
Imaginá que el input al sub-bloque es: x = [+0.50, +1.15, +0.78, +0.88] Y el sub-bloque (digamos, atención) produce: sublayer(x) = [+0.30, -0.20, +0.15, +0.45] Con conexión residual, el output es la SUMA: output = sublayer(x) + x = [+0.30+0.50, -0.20+1.15, +0.15+0.78, +0.45+0.88] = [+0.80, +0.95, +0.93, +1.33] Notá que el output conserva mucho del "perfil" del input original (x), solo modificado por la pequeña contribución del sub-bloque.
Antes de explicar LayerNorm necesitás dos conceptos básicos de estadística. Tranquilo, son simples.
La media es el promedio aritmético: sumás todos los números y dividís por la cantidad.
Ejemplo: vector = [2, 4, 6, 8] suma = 2 + 4 + 6 + 8 = 20 cantidad = 4 media = 20 / 4 = 5 Ejemplo 2: vector = [+0.80, +0.95, +0.93, +1.33] suma = 0.80 + 0.95 + 0.93 + 1.33 = 4.01 media = 4.01 / 4 = 1.0025
La desviación estándar mide qué tan dispersos están los valores alrededor de la media. Si todos están cerca de la media → std bajo. Si están muy dispersos → std alto.
Receta para calcularla:
(valor − media)² (la diferencia al cuadrado).Ejemplo: vector = [+0.80, +0.95, +0.93, +1.33]
media = 1.0025
Diferencias al cuadrado:
(0.80 - 1.0025)² = (-0.2025)² = 0.0410
(0.95 - 1.0025)² = (-0.0525)² = 0.0028
(0.93 - 1.0025)² = (-0.0725)² = 0.0053
(1.33 - 1.0025)² = (+0.3275)² = 0.1073
Varianza = (0.0410 + 0.0028 + 0.0053 + 0.1073) / 4 = 0.0391
Desviación estándar = √0.0391 = 0.198
Ingresá 4 números y mirá cómo cambian la media y la desviación estándar:
Después de pasar por muchas operaciones (atención, FFN, suma residual, otra capa, otra...), los valores de los vectores pueden quedar en escalas muy distintas. Algunos vectores pueden tener valores enormes (ej. todos entre +50 y +100), otros casi todos chiquititos (entre −0.001 y +0.001). Esto hace muy difícil entrenar el modelo.
LayerNorm fuerza que cada vector tenga media 0 y desviación estándar 1. Así, no importa qué pasó antes — la salida siempre tiene una escala predecible y manejable.
μ (mu) = la media de los valores de x (calculada como vimos arriba).σ (sigma) = la desviación estándar de x.γ (gamma) y β (beta) = vectores aprendibles (uno por dimensión). El modelo los entrena.⊙ = multiplicación elemento por elemento.A cada elemento del vector le restamos la media. El nuevo vector tiene media 0.
x = [0.80, 0.95, 0.93, 1.33]
media μ = 1.0025
x - μ = [0.80-1.0025, 0.95-1.0025, 0.93-1.0025, 1.33-1.0025]
= [-0.2025, -0.0525, -0.0725, +0.3275]
Verificación: la media de estos nuevos valores es ≈ 0 ✓
Dividimos cada elemento por la desviación estándar. El nuevo vector tiene std 1.
std σ = 0.198
(x - μ) / σ = [-0.2025/0.198, -0.0525/0.198, -0.0725/0.198, +0.3275/0.198]
= [-1.023, -0.265, -0.366, +1.654]
Verificación: la media sigue siendo 0, y la desviación estándar ahora es 1 ✓
Si el modelo decide que NO quiere media 0 y std 1 para cierta dimensión, los parámetros γ y β le permiten escalar y desplazar el resultado:
γ = [1.2, 0.8, 1.0, 1.1] (vector aprendido) β = [0.1, 0.0, -0.2, 0.3] (vector aprendido) resultado = γ ⊙ (x normalizado) + β = [1.2*(-1.023)+0.1, 0.8*(-0.265)+0.0, 1.0*(-0.366)+(-0.2), 1.1*(+1.654)+0.3] = [-1.128, -0.212, -0.566, +2.119]
γ escala cada dimensión (multiplica). β la desplaza (suma). Si γ = 1 y β = 0, el resultado es exactamente el normalizado. Pero al ser aprendidos, el modelo puede ajustarlos si conviene.
Pregunta natural. La respuesta: queremos que el modelo tenga la opción de no normalizar si encuentra que cierta escala es útil. Sin γ y β, le estaríamos imponiendo media 0 / std 1 a todas las capas — y eso podría ser una restricción demasiado fuerte.
Con γ y β aprendibles: el modelo arranca normalizando (lo cual estabiliza el entrenamiento al principio), y después aprende si le conviene mantener esa normalización o ajustarla en cada dimensión.
Movés los sliders y mirás cómo se normaliza el vector en tiempo real:
Ahora que entendés residual y LayerNorm, podés ver el bloque completo del Transformer. Cada bloque tiene dos sub-bloques (atención y FFN), y alrededor de cada uno hay residual + LayerNorm.
El paper original ("Attention is All You Need", 2017) usaba Post-LN: normalizar DESPUÉS de sumar el residual. Esa es la versión que mostré arriba.
Post-LN (original): x' = LayerNorm( x + sublayer(x) ) Pre-LN (moderno, usado en GPT-2, GPT-3, LLaMA, etc.): x' = x + sublayer( LayerNorm(x) )
La diferencia: en Pre-LN, primero normalizamos, después aplicamos el sub-bloque, y la suma residual usa el x sin normalizar. Empíricamente, Pre-LN es más fácil de entrenar para modelos muy profundos (resulta menos sensible a hiperparámetros). Pero la idea conceptual es la misma.
Click "Siguiente paso" para ver cómo se aplica residual + LayerNorm al vector de "perro" después de la atención.
Con los pasos 4 a 7 ya tenés todas las piezas de UN bloque del Transformer:
En el Paso 8: Stacking de bloques vamos a ver cómo se apilan muchos de estos bloques (12, 24, 96...) para formar el Transformer completo. Vas a entender por qué más capas = más capacidad de razonamiento abstracto, y cómo emergen patrones jerárquicos a medida que subís de capa.