El Proceso de Entrenamiento de una Red Neuronal
El Proceso de Entrenamiento de una Red Neuronal
🎯 Introducción
El entrenamiento de una red neuronal es un ciclo de optimización cuyo objetivo es ajustar los parámetros del modelo (pesos y sesgos) para minimizar su error.
Este proceso se fundamenta en tres pilares matemáticos:
- 📉 Función de Costo
- ⬇️ Descenso de Gradiente
- 🔄 Retropropagación
1️⃣ La Función de Costo: Cuantificación del Error
La función de costo J(w,b) cuantifica cuán equivocadas están las predicciones del modelo.
Analogía
Como una balanza desequilibrada: el objetivo es ajustarla hasta alcanzar el equilibrio (error mínimo).
Fórmula General
1J(w,b) = (1/m) · Σ L(y⁽ⁱ⁾, a[L]⁽ⁱ⁾)
Componentes:
- m: Número total de ejemplos de entrenamiento
- L: Función de pérdida (un ejemplo)
- y⁽ⁱ⁾: Etiqueta verdadera
- a[L]⁽ⁱ⁾: Predicción del modelo
Error Cuadrático Medio (MSE)
1L(y, ŷ) = (y − ŷ)²
python1import numpy as np 2 3def costo_mse(y_true, y_pred): 4 m = len(y_true) 5 return (1/m) * np.sum((y_true - y_pred)**2) 6 7# Ejemplo 8y_true = np.array([1, 0, 1, 1, 0]) 9y_pred = np.array([0.9, 0.1, 0.8, 0.7, 0.2]) 10print(f"Costo: {costo_mse(y_true, y_pred):.4f}")
Objetivo: Encontrar W y b que minimicen J(w,b).
2️⃣ Descenso del Gradiente: El Algoritmo de Optimización
El Descenso de Gradiente Estocástico (SGD) es el algoritmo más utilizado para minimizar la función de costo.
🏔️ Analogía: Descenso de una Montaña
Imagina que estás en una montaña con niebla densa. Para bajar:
- Sientes la pendiente del terreno
- Das un paso en la dirección más inclinada hacia abajo
- Repites hasta llegar al valle
Matemáticamente: Moverse en la dirección opuesta al gradiente.
Variante Moderna: Mini-Batch Gradient Descent
Actualiza parámetros usando un pequeño lote de muestras:
- Más eficiente que procesar todo el dataset
- Más estable que usar un solo ejemplo
Pasos del Algoritmo
python1# Pseudocódigo 2def entrenar_red(X, y, epochs, learning_rate): 3 # 1. Inicialización 4 W, b = inicializar_parametros_aleatorios() 5 6 for epoch in range(epochs): 7 for batch in crear_mini_batches(X, y): 8 # 2. Cálculo del gradiente 9 gradientes = calcular_gradientes(batch, W, b) 10 11 # 3. Actualización de parámetros 12 W = W - learning_rate * gradientes['dW'] 13 b = b - learning_rate * gradientes['db'] 14 15 return W, b
Ecuaciones de Actualización
1w⁽ⁱ⁺¹⁾ = w⁽ⁱ⁾ − α · (∂J/∂w) 2b⁽ⁱ⁺¹⁾ = b⁽ⁱ⁾ − α · (∂J/∂b)
α = tasa de aprendizaje (learning rate)
- Muy pequeña → Convergencia lenta
- Muy grande → Puede no converger
python1# Ejemplo de actualización 2W_nuevo = W_actual - 0.01 * gradiente_W 3b_nuevo = b_actual - 0.01 * gradiente_b
3️⃣ Retropropagación: Cálculo Eficiente de Gradientes
La backpropagation calcula los gradientes aplicando la regla de la cadena del cálculo diferencial.
Concepto Clave: El Error δ[l]
1δ[l] = (∂J/∂a[l]) ⊙ σ'(z[l])
- ⊙: Producto de Hadamard (elemento a elemento)
- σ'(z[l]): Derivada de la función de activación
Algoritmo de Backpropagation
python1def backpropagation(X, y, cache): 2 m = X.shape[1] 3 L = len(cache) # Número de capas 4 5 # 1. Calcular error en la capa de salida 6 delta_L = cache['A_L'] - y 7 8 # 2. Propagar hacia atrás 9 gradientes = {} 10 for l in reversed(range(1, L+1)): 11 # Gradientes de pesos y sesgos 12 gradientes[f'dW{l}'] = (1/m) * np.dot(delta, cache[f'A{l-1}'].T) 13 gradientes[f'db{l}'] = (1/m) * np.sum(delta, axis=1, keepdims=True) 14 15 # Error de la capa anterior 16 if l > 1: 17 delta = np.dot(cache[f'W{l}'].T, delta) * sigmoid_derivative(cache[f'Z{l-1}']) 18 19 return gradientes
Derivada de la Sigmoide
python1def sigmoid_derivative(z): 2 s = sigmoid(z) 3 return s * (1 - s)
Propagación hacia Atrás - Paso a Paso
1Capa de Salida (L) ─────────────────┐ 2 ↑ │ 3 │ Calcular δ[L] │ 4 │ │ 5Capa Oculta 2 ──────────────────────┤ 6 ↑ │ 7 │ δ[L-1] = W[L]ᵀ·δ[L] ⊙ σ' │ Backprop 8 │ │ 9Capa Oculta 1 ──────────────────────┤ 10 ↑ │ 11 │ δ[L-2] = W[L-1]ᵀ·δ[L-1] │ 12 │ │ 13Capa de Entrada ────────────────────┘
Cálculo de Gradientes Finales
Para los pesos:
1∂J/∂W[l] = δ[l] · a[l−1]ᵀ
Para los sesgos:
1∂J/∂b[l] = δ[l]
🔄 El Ciclo Completo de Aprendizaje
python1def ciclo_entrenamiento(X, y, arquitectura, epochs, alpha): 2 # Inicializar parámetros 3 parametros = inicializar_red(arquitectura) 4 5 for epoch in range(epochs): 6 # 1. FORWARD PROPAGATION 7 cache = forward_propagation(X, parametros) 8 9 # 2. CALCULAR COSTO 10 costo = calcular_costo(cache['A_L'], y) 11 12 # 3. BACKWARD PROPAGATION 13 gradientes = backpropagation(X, y, cache) 14 15 # 4. ACTUALIZAR PARÁMETROS 16 parametros = actualizar_parametros(parametros, gradientes, alpha) 17 18 if epoch % 100 == 0: 19 print(f"Epoch {epoch}: Costo = {costo:.4f}") 20 21 return parametros
📊 Visualización del Proceso
1┌─────────────────────────────────────────────────────┐ 2│ CICLO DE ENTRENAMIENTO │ 3├─────────────────────────────────────────────────────┤ 4│ │ 5│ 1. Forward Pass │ 6│ X → Z1 → A1 → Z2 → A2 → ... → Ŷ │ 7│ │ 8│ 2. Calcular Pérdida │ 9│ L = (Y - Ŷ)² │ 10│ │ 11│ 3. Backward Pass │ 12│ ∂L/∂Ŷ → ∂L/∂W[L] → ... → ∂L/∂W[1] │ 13│ │ 14│ 4. Actualizar Parámetros │ 15│ W = W - α·∂L/∂W │ 16│ │ 17│ 5. Repetir hasta convergencia │ 18│ │ 19└─────────────────────────────────────────────────────┘
💡 Consejos Prácticos
Elegir la Tasa de Aprendizaje
python1# Prueba diferentes valores 2learning_rates = [0.001, 0.01, 0.1, 1.0] 3 4for lr in learning_rates: 5 modelo = entrenar(X, y, learning_rate=lr) 6 print(f"LR={lr}: Costo Final={modelo.costo:.4f}")
Monitorear el Entrenamiento
python1import matplotlib.pyplot as plt 2 3def plot_training(historial_costos): 4 plt.plot(historial_costos) 5 plt.xlabel('Época') 6 plt.ylabel('Costo') 7 plt.title('Evolución del Costo durante el Entrenamiento') 8 plt.show()
📚 Referencias
- Goodfellow, I., Bengio, Y., & Courville, A. (2016). Deep learning. MIT Press.
- Mazur, M. (2015). A Step by Step Backpropagation Example.
- Ng, A. (2017). Neural Networks and Deep Learning. Coursera.
Anterior: ← Fundamentos del Deep Learning
Próximo: Aplicación Práctica con Keras →