En los artículos anteriores construimos todas las piezas sueltas:
- Neurona: suma ponderada + bias
- Funciones de activación (sigmoid, tanh)
- Función de pérdida (Binary Cross-Entropy)
- 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:
- Forward pass → hacer una predicción
- Calcular la pérdida → medir el error
- Backward pass → calcular gradientes
- 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 npX = 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.
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 linealy_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.1epochs = 5000for 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