Implementación de Mini-batch Gradient Descent para Regresión Lineal

Introducción al Descenso de Gradiente

El descenso de gradiente es un algoritmo de optimización utilizado para minimizar una función, comúnmente en aprendizaje automático e inteligencia artificial para minimizra la función de pérdida y encontrar los valores óptimos de los parámetros del modelo.

Las variantes principales del algoritmo de descenso de gradiente son:

  • Descenso de Gradiente por Lotes (Batch Gradient Descent, BGD): Utiliza todo el conjunto de datos en cada iteración para calcular el gradiente.
  • Descenso de Gradiente Estocástico (Stochastic Gradient Descent, SGD): Utiliza un solo dato en cada iteración para calcular el gradiente.
  • Descenso de Gradiente por Mini-lotes (Mini-batch Gradient Descent, MBGD): Utiliza un pequeño subconjunto de datos en cada iteración, situándose entre BGD y SGD.

Ventajas del Descenso de Gradiente por Mini-lotes

La fórmula de cálculo del gradiente es:

[\nabla_{\boldsymbol{W}} J(\boldsymbol{W}) = -\frac{1}{n} \mathbf{X}^\top (\mathbf{XW - y}) ]

Donde:

  • \(\nabla_{\boldsymbol{W}} J(\boldsymbol{W})\): Representa el gradiente de la función de pérdida \(J\) con respecto a la matriz de parámetros \(\boldsymbol{W}\).
  • \(n\): Es el número total de muestras en el conjunto de datos.
  • \(\mathbf{X}\): Es una matriz de características de tamaño \(n \times m\), donde \(m\) es el número de características.
  • \(\boldsymbol{W}\): Es una matriz de parámetros de tamaño \(m \times 1\).
  • \(\mathbf{y}\): Es un vector de tamaño \(n \times 1\) que continee los valores objetivo de las \(n\) muestras.

La complejidad temporal de este algoritmo crece cuadráticamente con el número de muestras \(n\).

En escenarios reales, los conjuntos de datos suelen contener miles o más muestras. El uso de BGD enfrentaría problemas de convergencia lenta y alto costo computacional. Por otro lado, SGD, al usar solo una muestra por iteración, produce estimaciones del gradiente con alta varianza y ruido. Esto puede hacer que las actualizaciones de parámetros sean inestables.

MBGD divide las muestras en lotes más pequeños, procesándolos de manera secuencial, lo que garantiza estabilidad algorítmica mientras se logra una convergencia más rápida y se reduce el costo computacional.

En este ejemplo, generaremos datos aleatorios que siguen una ecuación lineal simple con término de sesgo, implementaremos un modelo de regresión usando descenso de gradiente por mini-lotes y visualizaremos los resultados.

Implementación

Código Principal (mini_batch_gradient_descent.py)

import matplotlib.pyplot as plt
import numpy as np
import visualization_helper as vh

# Configuración inicial
NUM_SAMPLES, NUM_FEATURES = 128, 1

# 1. Creación del conjunto de datos
datos_x = np.random.rand(NUM_SAMPLES, NUM_FEATURES)
peso_real, sesgo_real = np.random.randint(1, 10, size=2)
# Añadir ruido a las etiquetas
datos_y = peso_real * datos_x + sesgo_real + np.random.randn(NUM_SAMPLES, NUM_FEATURES)

# 2. Visualización de la línea real y los puntos de datos
vh.plot_points(datos_x, datos_y)
vh.plot_line(peso_real, sesgo_real, 'g-')

# 3. Añadir término de sesgo a los datos
datos_x = np.concatenate((datos_x, np.ones((NUM_SAMPLES, 1))), axis=1)

# 4. Función de programación de tasa de aprendizaje
tasa_inicial, decaimiento = 5, 500
def calcular_tasa_aprendizaje(iteracion):
    return tasa_inicial / (iteracion + decaimiento)

# 5. Hiperparámetros
epocas = 100
tamano_lote = 16
num_lotes = int(NUM_SAMPLES / tamano_lote)

# 6. Inicialización de parámetros
parametros = np.random.randn(NUM_FEATURES + 1, 1)

# 7. Bucle de entrenamiento con descenso de gradiente
for epoca in range(epocas):
    # Mezclar los datos al inicio de cada época
    indices = np.arange(NUM_SAMPLES)
    np.random.shuffle(indices)
    datos_x = datos_x[indices]
    datos_y = datos_y[indices]
    
    for lote in range(num_lotes):
        # Obtener el mini-lote actual
        inicio = lote * tamano_lote
        fin = inicio + tamano_lote
        x_lote = datos_x[inicio:fin]
        y_lote = datos_y[inicio:fin]
        
        # Calcular gradiente
        prediccion = x_lote.dot(parametros)
        error = prediccion - y_lote
        gradiente = x_lote.T.dot(error)
        
        # Actualizar parámetros
        tasa = calcular_tasa_aprendizaje(epoca * NUM_SAMPLES + lote)
        parametros = parametros - tasa * gradiente

print("Valores reales (peso, sesgo):", peso_real, sesgo_real)
print("Valores calculados (peso, sesgo):", parametros)

# Visualizar la línea resultante
vh.plot_line(parametros[0], parametros[1], 'r-')
vh.mostrar_grafico()

Código de Visualización (visualization_helper.py)

import matplotlib.pyplot as plt
import numpy as np

def plot_points(datos_x, datos_y):
    """Dibuja los puntos de datos en un gráfico de dispersión"""
    plt.scatter(datos_x, datos_y)

def plot_line(pendiente, intercepto, estilo):
    """Dibuja una línea recta con la pendiente e intercepto dados"""
    x_vals = np.linspace(0, 1, 100)  # Generar 100 puntos entre 0 y 1
    y_vals = pendiente * x_vals + intercepto  # Calcular valores y según la ecuación lineal
    plt.plot(x_vals, y_vals, estilo, label=f'Ecuación: y = {pendiente:.2f}x + {intercepto:.2f}')

def mostrar_grafico():
    """Muestra el gráfico final con leyenda y título"""
    plt.title("Ajuste de Regresión Lineal con Mini-batch Gradient Descent")
    plt.xlabel("Variable X")
    plt.ylabel("Variable Y")
    plt.legend()
    plt.grid(True)
    plt.show()

Resultados

El código genera un gráfico que muestra:

  • Puntos de datos originales con ruido
  • Línea verde: La función lineal real generada
  • Línea roja: La línea ajustada por el modelo entrenado

La implementación converge hacia parámetros cercanos a los valores reales, demostrando la eficacia del descenso de gradiente por mini-lotes para problemas de regresión lineal simple.

Etiquetas: gradiente_descendente regresión_lineal optimización aprendizaje_automático NumPy

Publicado el 6-30 17:27