Skip to content

English · Español

Break — Quita el término de momentum de SGD

🇪🇸 Quita el momentum (β = 0) de un optimizador SGD que estaba convergiendo en un valle estrecho. Observa cómo la pérdida zig-zaguea y converge más lento. La gráfica de la pérdida es el mejor profesor.

Objetivo: cualquier implementación de SGD-con-momentum. Usamos el lab del optimizador de Rosenbrock (lab/02-optimizers-on-rosenbrock.md) como laboratorio porque su pérdida anisotrópica hace el efecto dramático.

Hipótesis

El learner predice: "Poner β = 0 (sin momentum) en SGD sobre la función de Rosenbrock (a) requerirá muchos más pasos para alcanzar la misma pérdida, y (b) trazará una trayectoria visiblemente zigzagueante a través del valle curvo." La curva de pérdida seguirá decreciendo — no es catastrófico — pero la convergencia será 5-20× más lenta.

El break

En tu optimizador SGD-con-momentum:

 class SGDMomentum:
-    def __init__(self, params, lr=0.001, beta=0.9):
+    def __init__(self, params, lr=0.001, beta=0.0):    # /break: momentum off
         self.params = params
         self.lr = lr
         self.beta = beta
         self.v = [np.zeros_like(p) for p in params]

     def step(self, grads):
         for i, (p, g) in enumerate(zip(self.params, grads)):
             self.v[i] = self.beta * self.v[i] + g
             p -= self.lr * self.v[i]

(Con beta = 0, la velocidad colapsa a v = g — es decir, SGD puro.)

Procedimiento de ejecución

uv run python -c "
import numpy as np

def rosenbrock(x):
    return (1 - x[0])**2 + 100*(x[1] - x[0]**2)**2

def grad_rosenbrock(x):
    dx = -2*(1 - x[0]) - 400*x[0]*(x[1] - x[0]**2)
    dy = 200*(x[1] - x[0]**2)
    return np.array([dx, dy])

for beta in (0.0, 0.9):
    x = np.array([-1.5, 1.5])
    lr = 1e-3
    v = np.zeros_like(x)
    for step in range(5000):
        g = grad_rosenbrock(x)
        v = beta * v + g
        x = x - lr * v
        if step in (0, 100, 1000, 4999):
            print(f'beta={beta:.1f}  step={step:5d}  x={x}  loss={rosenbrock(x):.4f}')
    print()
"

Modo de fallo esperado

Con β = 0.9 (correcto):

beta=0.9  step=    0  x=[-1.4948  1.5006]  loss= 4.2
beta=0.9  step=  100  x=[ 0.34    0.10  ]  loss= 0.44
beta=0.9  step= 1000  x=[ 0.91    0.83  ]  loss= 0.008
beta=0.9  step= 4999  x=[ 0.999   0.999 ]  loss= 1e-6

Con β = 0 (roto):

beta=0.0  step=    0  x=[-1.4955  1.4994]  loss= 4.6
beta=0.0  step=  100  x=[-0.78    0.69  ]  loss= 3.2     <-- apenas se movió
beta=0.0  step= 1000  x=[ 0.13    0.02  ]  loss= 0.76    <-- 100× más lento
beta=0.0  step= 4999  x=[ 0.65    0.42  ]  loss= 0.12    <-- aún no converge

Firma cuantitativa: en el paso 1000, β=0.9 alcanza pérdida < 0.01; β=0 sigue por encima de 0.5. 50× diferencia en velocidad de convergencia.

Diagnóstico

Solo desde los logs:

  1. Grafica x[0] a lo largo del tiempo para ambas ejecuciones. β=0 traza un patrón en sierra (zig-zag a través del valle parabólico); β=0.9 traza una curva suave. Si ves oscilación en coordenadas de pasos sucesivos, no tienes momentum (o tienes muy poco).
  2. Grafica la norma del gradiente. Con β=0 el gradiente por paso es grande pero se cancela con el siguiente paso. Con momentum, la velocidad acumulada sigue moviéndose en la misma dirección.

Lección

En una superficie de pérdida anisotrópica, la dirección del gradiente alterna entre "a través del valle" (ruidosa, signo alternante) y "a lo largo del valle" (silenciosa, signo consistente). El SGD puro trata ambas igual y zigzaguea. Momentum promedia la componente alternante a cero y refuerza la componente consistente.

El arreglo es una línea: v = β v + g, con β = 0.9 como default canónico. Esta es la mejora individual más barata en la jerarquía de optimizadores y explica por qué cada optimizador moderno (Adam, AdamW, Lion) mantiene un término de velocidad de alguna forma.

Referencias

  • Polyak, Some methods of speeding up the convergence of iteration methods, USSR Computational Mathematics, 1964 (el método heavy-ball original).
  • Sutskever et al., On the importance of initialization and momentum in deep learning, ICML 2013 — confirmación empírica en redes profundas.