LECCIÓN 7

Backpropagation

La joya de la corona. Cómo calcular el gradiente de CADA peso de la red de forma eficiente, usando la regla de la cadena hacia atrás. Lo haremos número por número, sin un solo gap, sobre nuestra red XOR.

1. El problema y la idea

En la lección 6 vimos que necesitamos dL/dw para cada peso. Pero la pérdida está al final de una cadena: el peso afecta a z, que afecta a a, que afecta a la siguiente capa, que afecta a la pérdida. ¿Cómo calculamos el efecto de un peso enterrado en la primera capa sobre la pérdida final?

Regla de la cadena: si L depende de a, y a depende de z, y z depende de w, entonces dL/dw = (dL/da)·(da/dz)·(dz/dw). Backpropagation aplica esta regla hacia atrás, capa por capa, reutilizando lo ya calculado. De ahí el nombre: propagar el error hacia atrás.
forward → x→ z₁ → a₁→ z₂ → ŷ L ← backward (gradientes)

2. Punto de partida (el forward de la lección 4)

Trabajamos con x = (1, 0), target = 1. Recordemos lo que ya calculamos:

a₁ = [0.524979, 0.475021]   (salida capa oculta)
ŷ = a₂ = 0.543014            (predicción)
L  = 0.104418               (MSE ½)

W₂ = [0.50, -0.40]   W₁ = [[0.20, -0.30], [0.40, 0.10]]

Dato útil de la sigmoid: su derivada es σ'(z) = a·(1 − a), donde a = σ(z). Súper cómoda: solo necesitamos la activación que ya tenemos.

3. Backward, paso a paso (de derecha a izquierda)

1 Gradiente en la salida: dL/da₂

Con MSE L = ½(a₂ − t)², la derivada es directa (por eso el ½):

dL/da₂ = (a₂ - t) = 0.543014 - 1 = -0.456986

2 Atravesar la sigmoid de salida: dL/dz₂

Multiplicamos por la derivada de la sigmoid a₂(1−a₂):

dL/dz₂ = dL/da₂ · a₂·(1-a₂)
       = -0.456986 · (0.543014 · 0.456986)
       = -0.456986 · 0.248151
       = -0.113401

3 Gradiente de los pesos de salida: dL/dW₂ y dL/db₂

Como z₂ = a₁·W₂ + b₂, la derivada respecto a cada peso es la activación que lo multiplicaba:

dL/dW₂ = a₁ · dL/dz₂
   peso de a₁:  0.524979 · -0.113401 = -0.059533
   peso de a₂:  0.475021 · -0.113401 = -0.053868

dL/db₂ = dL/dz₂ = -0.113401   (el bias multiplica por 1)
✅ ¡Ya tenemos los gradientes de la capa de salida! Ahora seguimos hacia atrás, a la capa oculta.

4 Propagar a la capa oculta: dL/da₁

El error de z₂ se reparte hacia atrás según los pesos W₂ que lo trajeron:

dL/da₁ = dL/dz₂ · W₂
   hacia a₁:  -0.113401 · 0.50  = -0.056701
   hacia a₂:  -0.113401 · -0.40 = 0.045360

5 Atravesar la sigmoid oculta: dL/dz₁

Otra vez por a(1−a), ahora con las activaciones ocultas:

a₁·(1-a₁): [0.524979·0.475021, 0.475021·0.524979] = [0.249377, 0.249377]

dL/dz₁ = dL/da₁ · a₁·(1-a₁)
   z₁ de h₁:  -0.056701 · 0.249377 = -0.014140
   z₁ de h₂:  0.045360 · 0.249377 = 0.011312

6 Gradiente de los pesos de entrada: dL/dW₁ y dL/db₁

Igual que en el paso 3, pero la entrada ahora es x = (1, 0):

dL/dW₁ = x · dL/dz₁   (producto externo)

           h₁              h₂
  x₁=1:  1·-0.014140=-0.0141400.011312=0.011312
  x₂=0:  0·-0.014140=00.011312=0

dL/db₁ = dL/dz₁ = [-0.014140, 0.011312]
👀 Fíjate: los gradientes de los pesos que salen de x₂ son 0, porque x₂ = 0 en este ejemplo. Una entrada apagada no recibe corrección. Tiene todo el sentido.

4. El resultado: el gradiente completo

Acabamos de calcular, sin saltarnos nada, las derivadas de la pérdida respecto a los 9 valores entrenables:

Capa de salida:
  dL/dW₂ = [-0.059533, -0.053868]
  dL/db₂ = -0.113401

Capa oculta:
  dL/dW₁ = [[-0.014140, 0.011312], [0, 0]]
  dL/db₁ = [-0.014140, 0.011312]
Esto es backpropagation. Cada gradiente se obtuvo multiplicando "lo que llega desde la derecha" por "la derivada local". Nada más. En la lección 8 usaremos estos números en la regla w = w − lr·gradiente para mejorar la red de verdad. Y en la lección 9 comprobaremos que PyTorch (con autograd) calcula exactamente estos mismos números — automáticamente.