📝 Pseudocódigo del Descenso del Gradiente

El descenso del gradiente es el algoritmo de optimización fundamental en el aprendizaje automático. Ajusta iterativamente los parámetros para minimizar una función de coste siguiendo la dirección de mayor pendiente.

El Algoritmo Principal

Descenso del Gradiente por Lotes (Una Época)

ALGORITMO: Descenso del Gradiente por Lotes (Una Época)
─────────────────────────────────────────────────────────────────

ENTRADA:
    θ: Vector de parámetros actual
    X: Conjunto de datos completo (n_muestras, n_características)
    y: Valores objetivo (n_muestras,)
    α: Tasa de aprendizaje
    función_pérdida: Función para calcular la pérdida
    función_gradiente: Función para calcular el gradiente

SALIDA:
    θ: Vector de parámetros actualizado

PROCEDIMIENTO:
    1. Calcular predicciones para todas las muestras:
       ŷ ← predecir(X, θ)
    
    2. Calcular pérdida (opcional, para monitoreo):
       L ← función_pérdida(y, ŷ)
    
    3. Calcular gradiente sobre todo el conjunto de datos:
       ∇L ← función_gradiente(X, y, ŷ, θ)
    
    4. Actualizar parámetros:
       θ ← θ - α · ∇L
    
    5. DEVOLVER θ

Bucle de Entrenamiento Completo

ALGORITMO: Entrenamiento con Descenso del Gradiente
─────────────────────────────────────────────────────────────────

ENTRADA:
    X: Datos de entrenamiento de forma (n_muestras, n_características)
    y: Valores objetivo de forma (n_muestras,)
    α: Tasa de aprendizaje (ej., 0.01)
    max_épocas: Número máximo de épocas
    tolerancia: Umbral de convergencia (ej., 1e-6)
    función_pérdida: Función para calcular la pérdida
    función_gradiente: Función para calcular el gradiente

SALIDA:
    θ: Vector de parámetros optimizado
    historial: Lista de valores de pérdida por época

PROCEDIMIENTO:
    1. Inicializar parámetros θ aleatoriamente o a ceros
    
    2. historial ← lista vacía
    
    3. PARA época = 1 HASTA max_épocas:
        
        a. // Paso hacia adelante: calcular predicciones
           ŷ ← predecir(X, θ)
        
        b. // Calcular y registrar pérdida
           L ← función_pérdida(y, ŷ)
           AÑADIR L a historial
        
        c. // Calcular gradiente
           ∇L ← función_gradiente(X, y, ŷ, θ)
        
        d. // Actualizar parámetros (paso del gradiente)
           θ ← θ - α · ∇L
        
        e. // Verificar convergencia
           SI ||∇L|| < tolerancia:
               IMPRIMIR "Convergido en época", época
               ROMPER
    
    4. DEVOLVER θ, historial

📋 Variantes del Descenso del Gradiente

Usamos Batch GD cuando queremos una dirección de descenso estable en cada paso, calculada con todo el dataset. Es la variante más didáctica para entender el algoritmo base y comparar convergencia.

ALGORITMO: Descenso del Gradiente por Lotes (Una Época)
─────────────────────────────────────────────────────────────────

ENTRADA:
    θ: Vector de parámetros actual
    X: Conjunto de datos completo (n_muestras, n_características)
    y: Valores objetivo (n_muestras,)
    α: Tasa de aprendizaje
    función_pérdida: Función para calcular la pérdida
    función_gradiente: Función para calcular el gradiente

SALIDA:
    θ: Vector de parámetros actualizado

PROCEDIMIENTO:
    1. Calcular predicciones para todas las muestras:
       ŷ ← predecir(X, θ)
    
    2. Calcular pérdida (opcional, para monitoreo):
       L ← función_pérdida(y, ŷ)
    
    3. Calcular gradiente sobre todo el conjunto de datos:
       ∇L ← función_gradiente(X, y, ŷ, θ)
    
    4. Actualizar parámetros:
       θ ← θ - α · ∇L
    
    5. DEVOLVER θ

Características:

  • Utiliza todo el conjunto de datos en cada actualización
  • Actualización única por época
  • Convergencia suave y estable
  • Mayor consumo de memoria
  • Ideal para conjuntos de datos pequeños

Incluimos el bucle completo para mostrar cómo Batch GD se usa realmente en entrenamiento: múltiples épocas, registro de pérdida y criterio de parada. Esta vista conecta la idea matemática con una implementación práctica.

ALGORITMO: Entrenamiento con Descenso del Gradiente
─────────────────────────────────────────────────────────────────

ENTRADA:
    X: Datos de entrenamiento de forma (n_muestras, n_características)
    y: Valores objetivo de forma (n_muestras,)
    α: Tasa de aprendizaje (ej., 0.01)
    max_épocas: Número máximo de épocas
    tolerancia: Umbral de convergencia (ej., 1e-6)
    función_pérdida: Función para calcular la pérdida
    función_gradiente: Función para calcular el gradiente

SALIDA:
    θ: Vector de parámetros optimizado
    historial: Lista de valores de pérdida por época

PROCEDIMIENTO:
    1. Inicializar parámetros θ aleatoriamente o a ceros
    
    2. historial ← lista vacía
    
    3. PARA época = 1 HASTA max_épocas:
        
        a. // Paso hacia adelante: calcular predicciones
           ŷ ← predecir(X, θ)
        
        b. // Calcular y registrar pérdida
           L ← función_pérdida(y, ŷ)
           AÑADIR L a historial
        
        c. // Calcular gradiente
           ∇L ← función_gradiente(X, y, ŷ, θ)
        
        d. // Actualizar parámetros (paso del gradiente)
           θ ← θ - α · ∇L
        
        e. // Verificar convergencia
           SI ||∇L|| < tolerancia:
               IMPRIMIR "Convergido en época", época
               ROMPER
    
    4. DEVOLVER θ, historial

Características:

  • Bucle completo de entrenamiento con múltiples épocas
  • Monitorea la pérdida en cada época
  • Incluye criterio de convergencia
  • Retorna historial de pérdida para análisis
  • Base para todos los métodos de optimización modernos

Usamos SGD cuando el dataset es grande o queremos actualizaciones muy frecuentes y baratas. Introduce ruido útil en el entrenamiento, lo que puede ayudar a escapar de mínimos locales y acelerar el aprendizaje inicial.

ALGORITMO: Descenso del Gradiente Estocástico (Una Época)
─────────────────────────────────────────────────────────────────

ENTRADA:
    θ: Vector de parámetros actual
    X: Datos de entrenamiento de forma (n_muestras, n_características)
    y: Valores objetivo de forma (n_muestras,)
    α: Tasa de aprendizaje

SALIDA:
    θ: Vector de parámetros actualizado

PROCEDIMIENTO:
    1. Barajar los índices del conjunto de datos
    
    2. PARA cada muestra i en orden barajado:
        
        a. Obtener muestra individual: xᵢ, yᵢ
        
        b. Calcular predicción: ŷᵢ ← predecir(xᵢ, θ)
        
        c. Calcular gradiente para muestra individual:
           ∇Lᵢ ← gradiente(xᵢ, yᵢ, ŷᵢ, θ)
        
        d. Actualizar parámetros:
           θ ← θ - α · ∇Lᵢ
    
    3. DEVOLVER θ

Características:

  • Actualización para cada muestra individual
  • Muy ruidoso pero rápido en memoria
  • Puede escapar mínimos locales
  • Excelente para conjuntos de datos muy grandes
  • Menos estable que Batch GD

Usamos Mini-Batch GD para equilibrar estabilidad y eficiencia: cada actualización ve más de una muestra, pero no todo el dataset. Por eso es la variante estándar en deep learning y entrenamiento moderno.

ALGORITMO: Descenso del Gradiente por Mini-Lotes (Una Época)
─────────────────────────────────────────────────────────────────

ENTRADA:
    θ: Vector de parámetros actual
    X: Datos de entrenamiento de forma (n_muestras, n_características)
    y: Valores objetivo de forma (n_muestras,)
    α: Tasa de aprendizaje
    tamaño_lote: Número de muestras por lote (ej., 32)

SALIDA:
    θ: Vector de parámetros actualizado

PROCEDIMIENTO:
    1. n ← número de muestras
    
    2. Barajar el conjunto de datos
    
    3. n_lotes ← techo(n / tamaño_lote)
    
    4. PARA idx_lote = 0 HASTA n_lotes - 1:
        
        a. // Extraer mini-lote
           inicio ← idx_lote × tamaño_lote
           fin ← min(inicio + tamaño_lote, n)
           X_lote ← X[inicio:fin]
           y_lote ← y[inicio:fin]
        
        b. // Paso hacia adelante
           ŷ_lote ← predecir(X_lote, θ)
        
        c. // Calcular gradiente sobre mini-lote
           ∇L ← gradiente(X_lote, y_lote, ŷ_lote, θ)
        
        d. // Actualizar parámetros
           θ ← θ - α · ∇L
    
    5. DEVOLVER θ

Características:

  • Equilibrio perfecto entre Batch GD y SGD
  • Actualización para cada mini-lote (típicamente 32-256 muestras)
  • Buen balance entre velocidad y estabilidad
  • Menos ruido que SGD, más eficiente en memoria que Batch GD
  • Método más utilizado en práctica moderna

Fundamento Matemático

Para una función de pérdida diferenciable $L(\theta)$, el descenso del gradiente actualiza los parámetros como:

$$\theta_{t+1} = \theta_t - \alpha \nabla_\theta L(\theta_t)$$

Donde:

  • $\theta_t$ es el vector de parámetros en la iteración $t$
  • $\alpha$ es la tasa de aprendizaje (tamaño del paso)
  • $\nabla_\theta L$ es el gradiente de la pérdida respecto a los parámetros

Condiciones de Convergencia

Para funciones convexas con gradientes Lipschitz-continuos, el descenso del gradiente converge cuando:

  1. La tasa de aprendizaje satisface: $\alpha < \frac{2}{L}$ donde $L$ es la constante de Lipschitz
  2. Para la tasa de convergencia: $L(\theta_t) - L(\theta^*) \leq \frac{\|\theta_0 - \theta^*\|^2}{2\alpha t}$

Comparación de Variantes

VarianteFrecuencia de ActualizaciónConvergenciaUso de MemoriaNivel de Ruido
GD por LotesUna vez por épocaSuave, estableAltoBajo
SGDUna vez por muestraRuidoso, puede escapar mínimos localesBajoAlto
Mini-LotesUna vez por loteBuen equilibrioMedioMedio

Hiperparámetros Clave

  1. Tasa de Aprendizaje (α): Muy alta → divergencia; muy baja → convergencia lenta
  2. Tamaño del Lote: Mayor → más estable; menor → más ruido, mejor generalización
  3. Número de Épocas: Suficientes para converger pero evitando sobreajuste

Referencias