Capítulo 1

Descenso de Gradiente

1.1 Descenso de Gradiente

xt+1=xtηf(xt)\mathbf{x}_{t+1} = \mathbf{x}_t - \eta \nabla f(\mathbf{x}_t). El gradiente apunta en la dirección de máximo crecimiento, así que nos movemos en dirección opuesta.

1.2 Visualización 2D

Contornos de f(x,y)=x2+2y2+0.3xyf(x,y) = x^2 + 2y^2 + 0.3xy. El punto amarillo es el inicio.

xy

1.3 Variantes

Batch GD

Usa todos los datos para calcular el gradiente. Preciso pero lento.

SGD

Un solo ejemplo por paso. Ruidoso pero rápido y escapa de mínimos locales.

Mini-batch GD

Compromiso: un batch pequeño (~32-256) por paso.

Momentum

vt+1=βvt+f(xt)v_{t+1} = \beta v_t + \nabla f(x_t)

Acumula gradientes pasados para suavizar la trayectoria.

1.4 Implementación

python
import numpy as np
from sklearn.linear_model import SGDRegressor
from sklearn.datasets import make_regression

X, y = make_regression(n_samples=1000, n_features=10, noise=0.1)

# SGD para regresión lineal
model = SGDRegressor(
    max_iter=1000,
    learning_rate='adaptive',
    eta0=0.01,
    penalty=None  # sin regularización
)
model.fit(X, y)
print(f"Coeficientes: {model.coef_[:5]}...")
print(f"Score R²: {model.score(X, y):.4f}")

# Implementación manual de momentum
def gradient_descent_momentum(grad_fn, x0, lr=0.01, beta=0.9, steps=100):
    x = x0.copy()
    v = np.zeros_like(x)
    for i in range(steps):
        g = grad_fn(x)
        v = beta * v + lr * g
        x -= v
    return x

1.5 Tasa de Aprendizaje

Problemas

  • η muy grande → oscila o diverge
  • η muy pequeña → converge muy lento
  • Learning rate scheduling: reducir η con el tiempo

Adaptativos

  • AdaGrad: η específico por parámetro
  • RMSProp: media móvil del gradiente²
  • Adam: momentum + RMSProp (el más usado)
python
from sklearn.linear_model import SGDRegressor
# SGDRegressor usa por defecto 'adaptive' o 'invscaling'
# Para Adam-like, usar optimizadores de PyTorch/TensorFlow

# En PyTorch:
# optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
# optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)

# Learning rate schedule simple
import numpy as np
def schedule(epoch, lr0=0.1, decay=0.01):
    return lr0 / (1 + decay * epoch)

for epoch in range(10):
    lr = schedule(epoch)
    print(f"Epoch {epoch}: lr = {lr:.5f}")