SolveConPython

Gradientes y Backpropagation en Python — cómo el error se convierte en ajuste de pesos

En el artículo anterior introdujimos la función de pérdida, que responde a una pregunta clave:

¿Qué tan mal lo está haciendo la red neuronal?

Ahora toca la siguiente — y más importante — pregunta:

¿Cómo usamos ese error para mejorar el modelo?

La respuesta es el corazón del aprendizaje automático:

👉 gradientes + backpropagation

La idea central (sin matemáticas aún)

Una red neuronal aprende ajustando sus pesos y bias para reducir la pérdida.

Pero hay un problema:

  • La pérdida depende de la salida
  • La salida depende de los pesos
  • Todo está conectado

Necesitamos una forma sistemática de responder:

“Si cambio este peso un poco…
¿la pérdida sube o baja?”

Eso es exactamente lo que nos dicen los gradientes.

La idea central (sin matemáticas aún)

Una red neuronal aprende ajustando sus pesos y bias para reducir la pérdida.

Pero hay un problema:

  • La pérdida depende de la salida
  • La salida depende de los pesos
  • Todo está conectado

Necesitamos una forma sistemática de responder:

“Si cambio este peso un poco…
¿la pérdida sube o baja?”

Eso es exactamente lo que nos dicen los gradientes.

Visualizando la idea del gradiente

Piensa en la pérdida como una colina:

  • El gradiente indica la pendiente
  • El descenso por gradiente busca siempre bajar

Recordemos el flujo completo de la red

Hasta ahora, nuestra red hace esto:

  1. Forward pass
    • Calcula la predicción ŷ
  2. Loss
    • Mide el error L(y, ŷ)
  3. Backward pass
    • Calcula gradientes
  4. Update
    • Ajusta pesos

Este artículo se centra en el paso 3.

El caso más simple: una neurona con sigmoide

Tenemos:z=XW+bz = XW + bz=XW+b y^=σ(z)\hat{y} = \sigma(z)y^​=σ(z) L=BCE(y,y^)L = \text{BCE}(y, \hat{y})L=BCE(y,y^​)

Todo está encadenado.
Para calcular los gradientes usamos la regla de la cadena.

La clave matemática (buena noticia)

Cuando combinamos:

  • Sigmoide
  • Binary Cross-Entropy

Ocurre algo muy conveniente:Lz=y^y\frac{\partial L}{\partial z} = \hat{y} – y∂z∂L​=y^​−y

Esto es enorme por dos razones:

  • Evita fórmulas largas
  • Hace el aprendizaje estable

No es magia: es matemática bien elegida.

Implementando el gradiente en Python

Supongamos:

  • y → valor real (0 o 1)
  • y_hat → predicción del modelo
dZ = y_hat - y

dZ = y_hat – y

Gradientes de pesos y bias

Recordemos:z=XW+bz = XW + bz=XW+b

Entonces:LW=XTdZ\frac{\partial L}{\partial W} = X^T \cdot dZ∂W∂L​=XT⋅dZ Lb=dZ\frac{\partial L}{\partial b} = \sum dZ∂b∂L​=∑dZ

Código en Python

dW = X.T @ dZ
db = dZ.sum()

Esto nos dice:

  • Cómo ajustar cada peso
  • Cómo ajustar el bias

Actualización de los pesos (gradient descent)

Una vez tenemos los gradientes, actualizamos:W=WηdWW = W – \eta \cdot dWW=W−η⋅dW b=bηdbb = b – \eta \cdot dbb=b−η⋅db

Donde η es la tasa de aprendizaje (learning rate).

Código

learning_rate = 0.1
W = W - learning_rate * dW
b = b - learning_rate * db

Eso es aprender.

Backpropagation explicado en una frase

Backpropagation es aplicar la regla de la cadena desde la pérdida hacia atrás, capa por capa, para calcular gradientes.

No es un algoritmo mágico.
Es cálculo ordenado.

Mini ejemplo completo (una iteración)

# forward
Z = X @ W + b
y_hat = sigmoid(Z)
# loss gradient
dZ = y_hat - y
# gradients
dW = X.T @ dZ
db = dZ.sum()
# update
W -= learning_rate * dW
b -= learning_rate * db

Este patrón se repetirá miles de veces durante el entrenamiento.

Pieza reutilizable (guárdala)

def backward_linear(X, y, y_hat):
dZ = y_hat - y
dW = X.T @ dZ
db = dZ.sum()
return dW, db

Esta función será parte del motor de entrenamiento.

Qué viene después

En el Artículo #6 uniremos todo lo aprendido hasta ahora:

Entrenando una red neuronal paso a paso (loop completo)