Redes Neuronales — Módulo 5: backpropagation — el motor que hace posible el aprendizaje
Quinto módulo del curso de Redes Neuronales: cómo backpropagation calcula el gradiente de cada peso propagando el error hacia atrás con la regla de la cadena, qué hace loss.backward() por debajo con autograd, y por qué entender la idea importa aunque no derives a mano.
☰ Índice del contenido
En el Módulo 4 quedamos con una idea y un hueco. La idea: entrenar es minimizar una loss (pérdida, el número que mide cuán mal lo hace la red) bajando por su pendiente con descenso de gradiente. El hueco: para bajar por la pendiente necesitas el gradiente — cuánto cambia la pérdida si mueves cada peso un poquito — y una red seria tiene millones de pesos. Calcular eso peso por peso, a mano o por fuerza bruta, tardaría una eternidad. Este módulo es cómo se resuelve ese hueco: backpropagation, el algoritmo que consigue el gradiente de todos los pesos de una sola pasada hacia atrás.
La tesis del módulo
Backpropagation no es magia ni cálculo imposible: es la regla de la cadena del colegio, aplicada de la salida hacia la entrada. Una pasada hacia adelante calcula la predicción y el error; una pasada hacia atrás reparte la culpa de ese error entre todos los pesos. Ese reparto es el gradiente.
Primero, las dos pasadas
Entrenar un ejemplo son siempre dos viajes por la red:
- Forward pass (pasada hacia adelante): metes los datos por la entrada, cada capa hace sus multiplicaciones y activaciones, y sale una predicción. Comparas con la respuesta correcta y obtienes la loss: un solo número.
- Backward pass (pasada hacia atrás): tomas ese número y lo empujas de vuelta por la red, capa por capa, calculando para cada peso cuánto contribuyó al error. El resultado es el gradiente de cada peso.
El forward dice qué predijo la red. El backward dice a quién culpar y cuánto. Con esa culpa repartida, el optimizer (que veremos en el Módulo 6) ajusta cada peso en la dirección que baja la pérdida.
La regla de la cadena, sin miedo
La regla de la cadena (chain rule) es una regla del cálculo para derivar funciones anidadas: funciones dentro de funciones. Y una red neuronal es exactamente eso — una función metida dentro de otra dentro de otra, una por capa.
La intuición sin fórmulas: imagina una cadena de engranajes. Giras el primero, que mueve al segundo, que mueve al tercero. Si quieres saber cuánto gira el último cuando mueves el primero, multiplicas los efectos de cada engranaje en el camino. La regla de la cadena dice justo eso: el efecto total de un peso sobre la pérdida es el producto de los efectos locales a lo largo de la cadena que va desde ese peso hasta la loss.
Formalmente, si la pérdida L depende de a, que depende de z, que depende del peso w, entonces:
∂L/∂w = (∂L/∂a) · (∂a/∂z) · (∂z/∂w)
Cada factor es una derivada local y sencilla: cuánto cambia una cosa respecto de la de justo al lado. Backpropagation calcula esos factores locales una vez y los va multiplicando hacia atrás, reutilizando lo ya calculado. Por eso es rápido: no recalcula la cadena entera para cada peso, la comparte.
Ojo:
∂L/∂w(la “d curva”) es solo notación para “cuánto cambia L si muevo w un pelito”. No necesitas saber derivar para usar redes — PyTorch lo hace por ti. Pero sí necesitas la idea: el gradiente es una multiplicación de efectos encadenados hacia atrás.
Repartir la culpa
La forma más humana de entender el backward pass es como un juicio de responsabilidades. La loss es el error total: “fallamos por 8 puntos”. Backpropagation pregunta, capa por capa desde el final: ¿cuánto de estos 8 puntos es culpa tuya?
FORWARD: los datos avanzan y se calcula el error
entrada ──► capa 1 ──► capa 2 ──► salida ──► LOSS
BACKWARD: la culpa del error vuelve repartida
┌─────┐ ┌───────┐ ┌───────┐ ┌──────┐
│ w1 │◄───│ culpa │◄───│ culpa │◄───│ LOSS │
│ ... │ │ capa1 │ │ capa2 │ │ = 8 │
└─────┘ └───────┘ └───────┘ └──────┘
cada peso recibe SU parte del error total
La capa de salida recibe la culpa directa. Esa capa se la pasa hacia atrás a la anterior, ponderada por qué tanto influyó cada conexión. Y así hasta la primera capa. Un peso que empujó fuerte en la dirección equivocada recibe mucha culpa (gradiente grande) y se corregirá harto; uno que casi no influyó recibe poca (gradiente chico) y apenas se toca.
Forward vs backward, lado a lado
| Forward pass | Backward pass | |
|---|---|---|
| Dirección | Entrada → salida | Salida → entrada |
| Qué calcula | La predicción y la loss | El gradiente de cada peso |
| Operación clave | Multiplicar pesos, activar | Multiplicar derivadas locales (chain rule) |
| Qué guarda | Los valores intermedios de cada capa | Los usa para calcular las derivadas |
| En PyTorch | pred = modelo(x) y loss = ... | loss.backward() |
| Analogía | Predecir | Repartir la culpa |
Fíjate en la fila “qué guarda”: el forward pass almacena los valores intermedios de cada capa porque el backward los necesita para calcular las derivadas locales. Por eso entrenar consume más memoria que solo inferir — hay que guardar todo el camino de ida para poder recorrerlo de vuelta.
En código: qué hace loss.backward()
En PyTorch nunca escribes la cadena de derivadas a mano. Lo hace autograd (differentiation automática): el sistema que registra cada operación que haces sobre los tensores y arma solo el “mapa de vuelta” para el backward.
import torch
# Un peso y un dato de ejemplo. requires_grad=True le dice a autograd:
# "sigue la pista de este tensor, voy a querer su gradiente".
w = torch.tensor([2.0], requires_grad=True)
x = torch.tensor([3.0])
y_real = torch.tensor([10.0])
# --- FORWARD PASS ---
# Autograd va anotando cada operación en un grafo a medida que ocurre.
z = w * x # z = 6.0
pred = z + 1 # una "capa" tonta: pred = 7.0
loss = (pred - y_real) ** 2 # error cuadrático: (7 - 10)^2 = 9.0
# --- BACKWARD PASS ---
# Una línea recorre el grafo hacia atrás aplicando la regla de la cadena
# y deposita el gradiente en .grad de cada tensor con requires_grad.
loss.backward()
print(w.grad) # ∂loss/∂w = -18.0 (cuánto baja la loss si muevo w)
Lo que ocurrió por debajo en esa única línea loss.backward():
loss = (pred - y_real)²
│ ∂loss/∂pred = 2·(pred - y_real) = 2·(7-10) = -6
▼
pred = z + 1
│ ∂pred/∂z = 1
▼
z = w · x
│ ∂z/∂w = x = 3
▼
∂loss/∂w = (-6) · (1) · (3) = -18 ◄── regla de la cadena
Autograd multiplicó los tres efectos locales hacia atrás y guardó -18 en w.grad. Multiplica esto por un peso real (millones de tensores, decenas de capas) y tienes backpropagation completo — misma idea, más engranajes.
Ojo: los gradientes en PyTorch se acumulan. Cada
loss.backward()suma al.gradexistente en vez de reemplazarlo. Por eso el training loop del Módulo 6 empieza siempre conoptimizer.zero_grad(): si no borras los gradientes del paso anterior, se van sumando y el entrenamiento se corrompe.
Errores comunes
- Creer que hay que derivar a mano. No. Autograd lo hace. Tu trabajo es entender la idea (culpa repartida hacia atrás), no calcular derivadas. La derivación manual es para quien construye frameworks, no para quien los usa.
- Olvidar
zero_grad(). Como los gradientes se acumulan, sin borrarlos el modelo entrena con basura sumada de pasos anteriores. Es el bug silencioso más clásico del principiante. - Confundir forward con backward. El forward calcula la predicción; el backward, el gradiente. Si tu loss no baja, muchas veces el forward está bien y el problema está en el paso de actualización — no en backprop.
- Pensar que backprop “entrena” la red. Backprop solo calcula los gradientes. Quien mueve los pesos es el optimizer (Módulo 6). Son dos etapas distintas: primero calcular la culpa, después actuar sobre ella.
- No entender por qué entrenar gasta tanta memoria. El forward guarda todos los valores intermedios para el backward. Redes profundas o batches grandes = más memoria retenida en el camino de ida.
La frase para llevarse
“Backpropagation es un juicio de responsabilidades a la inversa: la loss acusa, y capa por capa hacia atrás cada peso recibe exactamente su parte de la culpa. Esa parte es su gradiente.”
Qué viene
Módulo 6: entrenar en la práctica. Ya sabes calcular el gradiente; ahora el loop real que lo usa una y otra vez — épocas, batches, el learning rate que decide el tamaño del paso, y los optimizers (SGD, momentum, Adam) que convierten esos gradientes en pesos entrenados.
Material relacionado
Preguntas sobre este curso
Regístrate gratis para hacer preguntas y guardar tu progreso.
✉ Entérate de lo nuevo
Recibe un aviso cuando publique nuevos cursos, workshops o investigaciones. Sin spam.