SolveConPython

Entrenar una red neuronal en Python — el loop completo paso a paso

En los artículos anteriores construimos todas las piezas sueltas:

  1. Neurona: suma ponderada + bias
  2. Funciones de activación (sigmoid, tanh)
  3. Función de pérdida (Binary Cross-Entropy)
  4. Gradientes y backpropagation

Ahora llega el momento clave:

Unir todo en un loop de entrenamiento real.

Aquí no hay magia, librerías ocultas ni atajos.
Solo matemática + Python + repetición.

Qué significa “entrenar” una red neuronal

Entrenar una red neuronal significa repetir este ciclo muchas veces:

  1. Forward pass → hacer una predicción
  2. Calcular la pérdida → medir el error
  3. Backward pass → calcular gradientes
  4. Actualizar pesos → reducir el error

Ese ciclo se llama training loop.

El problema de ejemplo (clasificación binaria simple)

Vamos a usar un ejemplo pequeño y claro:

  • Dos entradas
  • Una salida binaria (0 o 1)
import numpy as np
X = np.array([
[0.0, 0.0],
[0.0, 1.0],
[1.0, 0.0],
[1.0, 1.0]
])
y = np.array([[0], [1], [1], [0]])

Este dataset no es trivial, y más adelante veremos por qué.

Inicializar los parámetros (pesos y bias)

Antes de entrenar, necesitamos valores iniciales.

Python
rng = np.random.default_rng(42)
W = rng.normal(0, 1, size=(2, 1))
b = 0.0

No importa que sean “malos”.
El entrenamiento los ajustará.

Funciones que ya conocemos (reutilización)

def sigmoid(x):
return 1 / (1 + np.exp(-x))
def binary_cross_entropy_mean(y_true, y_pred):
eps = 1e-9
y_pred = np.clip(y_pred, eps, 1 - eps)
return np.mean(
-(y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred))
)

Estas funciones vienen directamente de artículos anteriores.

Forward pass

def forward(X, W, b):
Z = X @ W + b
y_hat = sigmoid(Z)
return Z, y_hat

Aquí:

  • Z → salida lineal
  • y_hat → predicción del modelo

Backward pass

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

Esto calcula:

  • Cómo cambiar los pesos
  • Cómo cambiar el bias

El loop de entrenamiento completo

Ahora sí.
Aquí está el corazón del aprendizaje.

learning_rate = 0.1
epochs = 5000
for epoch in range(epochs):
# forward
Z, y_hat = forward(X, W, b)
# loss
loss = binary_cross_entropy_mean(y, y_hat)
# backward
dW, db = backward(X, y, y_hat)
# update
W -= learning_rate * dW
b -= learning_rate * db
if epoch % 500 == 0:
print(f"Epoch {epoch} | Loss: {loss:.4f}")

Esto es exactamente lo que hacen frameworks como TensorFlow o PyTorch…
pero aquí lo vemos sin capas ocultas.

Qué está pasando realmente aquí

Cada iteración:

  • Hace una predicción
  • Mide el error
  • Ajusta ligeramente los pesos
  • Repite

Después de miles de repeticiones, la pérdida baja.

Eso es aprender.

Ver las predicciones finales

_, y_hat = forward(X, W, b)
print("Predicciones:")
print(y_hat.round(3))
print("Clases:")
print((y_hat >= 0.5).astype(int))

Aquí ya puedes comparar:

  • Lo que el modelo predice
  • Con los valores reales

Lo importante (y lo que falta)

Aunque el código funciona, hay una limitación muy importante:

Este modelo NO puede aprender el patrón XOR correctamente.

¿Por qué?

Porque:

  • Solo tiene una capa
  • Todo sigue siendo casi lineal

Esto no es un error.
Es el punto exacto donde una sola neurona no es suficiente.

Lo que viene ahora (muy importante)

En el Artículo #7 daremos el salto real:

Añadiendo una capa oculta — construyendo una red neuronal real