Regresión Lineal con Gradient Descent

Clickeá en el gráfico para agregar puntos. Apretá "Un paso" para ver cómo se ajusta la recta.
Datos reales
Predicción (recta)
Error por punto

Parámetros del modelo

m (pendiente)1.000
b (intercepto)0.000
MSE (error)
Iteración0

Controles

Escala logarítmica. Muy alto = explota. Muy bajo = lento.
Zona segura

Gradientes actuales

∂MSE/∂m
∂MSE/∂b
El modelo resta el gradiente × learning rate para bajar el error. Mirá cómo los gradientes tienden a 0 cuando la recta converge.

Datos

Click en el canvas = agregar punto. Shift+click = borrar punto cercano.
¿Qué es una derivada? (con visualizador)

Antes que nada: sin derivadas, gradient descent es magia negra. Son literalmente la brújula del ML.

¿Qué es una función? Una regla que a cada entrada le asigna una salida. f(x) = x · 2 es una función: le metés 3 y te devuelve 6. Le metés 5 y te devuelve 10. La entrada se llama x, la salida se llama f(x) (que se lee "efe de equis").

Qué es una derivada. Una derivada te dice qué tan rápido cambia la salida de una función cuando movés su entrada un poquito.

Entendamos primero el ejemplo del auto — por qué la velocidad "cambia".

Imaginá que tenés una función posición(tiempo) que te dice en qué kilómetro de la ruta estás en cada segundo. Si vas siempre a la misma velocidad (120 km/h constante), la función es una línea recta y la velocidad es siempre la misma.

Pero en la vida real no vas siempre a la misma velocidad: acelerás, frenás, parás en un semáforo. La velocidad cambia en cada momento. Si el semáforo te frena, tu posición deja de cambiar por un rato (velocidad = 0). Cuando apretás el acelerador, la posición cambia cada vez más rápido (velocidad creciente).

La derivada de posición(tiempo) es una NUEVA función que te dice la velocidad en cada momento. No es un solo número — es un número distinto para cada instante. Eso es lo importante: la derivada depende del punto donde la estás midiendo.

Por qué usamos f(x) = x² en el visualizador. Es solo un ejemplo, no algo sagrado. Elegimos (equis al cuadrado, o sea x · x) porque:

  • No es una recta — es una curva, así la pendiente (y por lo tanto la derivada) cambia según dónde mires.
  • Es la función más simple que tiene esa propiedad. Si usáramos una recta, la derivada sería siempre el mismo número y sería aburrido.
  • Es la forma del "tazón" del MSE de la app principal. El MSE es esencialmente una suma de cuadrados de errores, así que su forma es parecida a pero en 3D. Entender cómo se comportan las derivadas en te prepara directamente para entender el MSE.

Visualizador. Abajo graficamos la función f(x) = x² (la curva amarilla). Movés el slider → el punto rojo se desliza por la curva. La línea azul es la tangente en ese punto — una recta que "toca" la curva sin cruzarla, y que tiene exactamente la misma inclinación que la curva en ese punto. La pendiente de esa tangente ES la derivada.

f(x) = x²1.00
f'(x) = 2x2.00
Pendiente2.00
Mirá qué pasa en x = 0 — la curva es plana, la tangente es horizontal, la derivada es 0. En x = 2 sube empinada, derivada = 4. En x = -3 baja, derivada = -6 (negativa).
¿Qué representaría en el ejemplo del auto?

Renombremos las letras para darle sentido físico. En vez de f(x) = x², escribimos posición(tiempo) = tiempo². O sea, x ahora es el tiempo (en segundos) y f(x) es la posición (en metros).

Veamos cómo se mueve el auto con esa función:

tiempo (s) | posición (m) | avanzó ese segundo ────────────┼────────────────┼───────────────────── 0 | 0 | — 1 | 1 | 1 m 2 | 4 | 3 m 3 | 9 | 5 m 4 | 16 | 7 m 5 | 25 | 9 m

Mirá la última columna: cada segundo avanzás más metros que el anterior. Eso significa una sola cosa: estás acelerando. Es exactamente lo que le pasa a un auto que arranca parado y apreta el acelerador a fondo, o a una piedra que cae desde un puente por gravedad.

De hecho la fórmula real de caída libre es distancia = ½ · g · tiempo² (con g ≈ 9.8 m/s²). El tiempo al cuadrado. Por eso caer de 10 pisos es MUCHO peor que caer de 5 — no es el doble, es mucho más que el doble.

Acá cobra sentido total la derivada. Dijimos que la derivada de es 2x. Traduciendo: velocidad(tiempo) = 2 · tiempo.

tiempo | posición (t²) | velocidad (2t) ────────┼─────────────────┼───────────────── 0 | 0 | 0 (parado) 1 | 1 | 2 m/s 2 | 4 | 4 m/s 3 | 9 | 6 m/s 4 | 16 | 8 m/s 5 | 25 | 10 m/s

La velocidad crece linealmente con el tiempo → eso es aceleración constante. La derivada te dice "en este instante exacto, estás yendo a esta velocidad".

Mirá el auto en acción. Dale play y observá cómo arranca lento y cada segundo avanza más. Las marcas en la ruta son las posiciones de la tabla (1m, 4m, 9m, 16m, 25m).

🚗
tiempo0.00 s
posición = t²0.00 m
velocidad = 2t0.00 m/s

El cierre:

  • En x = 0 la tangente del visualizador es horizontal → el auto todavía está parado, velocidad = 0.
  • A medida que x crece, la tangente se empina → el auto va cada vez más rápido, por eso la posición cambia más fuerte.
  • Del lado negativo la curva sube también: matemáticamente la función existe, aunque físicamente "tiempo negativo" no tenga sentido (sería como rebobinar el video).
¿De dónde sale que la derivada de es 2x?

No es un invento arbitrario. Sale de la definición de derivada: agarrás dos puntos muy cercanos de la función, calculás cuánto cambia la salida dividido cuánto cambiaste la entrada, y hacés que la distancia entre esos puntos sea casi cero.

Probemos con $f(x) = x^2$ en un punto $x$, y un punto muy cerca $x + h$ (donde $h$ es chiquito):

$$\frac{\text{cambio en } f}{\text{cambio en } x} = \frac{f(x+h) - f(x)}{h} = \frac{(x+h)^2 - x^2}{h}$$

Expandiendo $(x+h)^2 = x^2 + 2xh + h^2$:

$$\frac{x^2 + 2xh + h^2 - x^2}{h} = \frac{2xh + h^2}{h} = 2x + h$$

Ahora hacemos $h$ lo más chico posible ($h \to 0$). El término $h$ desaparece y nos queda $2x$. Por eso la derivada de $x^2$ es $2x$. Si probás con $f(x) = x^3$ sale $3x^2$. De ahí viene la regla general $x^n \to n \cdot x^{n-1}$.

Qué te dice una derivada, en concreto:

  • Cuánto cambia f si movés x un poco. Si f'(x) = 5, significa: "si aumento x en 0.1, entonces f aumenta aprox 5 · 0.1 = 0.5".
  • La pendiente de la tangente en ese punto. Positiva = sube, negativa = baja, cero = plana.
  • La dirección del cambio: f'(x) > 0 creciendo, f'(x) < 0 decreciendo, f'(x) = 0 punto crítico (máximo, mínimo o meseta).

Ese último caso es lo que explota gradient descent: el mínimo de una función está donde la derivada es 0. Por eso cuando los gradientes tienden a 0 en la app principal, sabemos que la recta convergió.

Reglas prácticas (con esto derivás casi cualquier polinomio):

$$\begin{aligned} f(x) = c &\quad\Rightarrow\quad f'(x) = 0 \\ f(x) = x &\quad\Rightarrow\quad f'(x) = 1 \\ f(x) = x^n &\quad\Rightarrow\quad f'(x) = n \cdot x^{n-1} \\ f(x) = c \cdot g(x) &\quad\Rightarrow\quad f'(x) = c \cdot g'(x) \\ f(x) = g(x) + h(x) &\quad\Rightarrow\quad f'(x) = g'(x) + h'(x) \end{aligned}$$

Donde $c$ es una constante, $n$ es un exponente cualquiera, y $g$, $h$ son otras funciones.

Ejemplo: $f(x) = 3x^2 + 5x + 7$

  • Derivada de $3x^2 \to 3 \cdot 2x = 6x$
  • Derivada de $5x \to 5$
  • Derivada de $7$ (constante) $\to 0$
  • Total: $f'(x) = 6x + 5$

Derivadas parciales (∂) — lo que usamos en la app principal. Cuando una función tiene varias entradas (como nuestro MSE que depende de m y b), hay una derivada por cada variable. Se escriben con (una d redondeada) en vez de d:

  • ∂L/∂m = "cómo cambia L si muevo solo m, dejando b fijo"
  • ∂L/∂b = "cómo cambia L si muevo solo b, dejando m fijo"

Misma idea que la derivada normal, pero "congelás" las otras variables mientras derivás respecto a una.

El gradiente es el vector que junta todas las derivadas parciales: ∇L = (∂L/∂m, ∂L/∂b). Ese vector apunta en la dirección donde L crece más rápido. Por eso gradient descent RESTA el gradiente: para ir al revés y bajar hacia el mínimo.

Resumen para ML: Sin derivadas, el modelo no sabe hacia dónde ajustar sus parámetros. Todo el entrenamiento es: calcular gradientes → moverse en la dirección opuesta → repetir hasta que las derivadas sean ≈ 0.
¿Qué es un gradiente? (con visualizador del "tazón")

Ya tenés todo lo necesario para entenderlo. Un gradiente es simplemente la versión multivariable de la derivada. Nada más.

De derivada a gradiente. Cuando una función tiene una sola entrada (como f(x) = x²), tiene una sola derivada. Pero en ML las funciones casi nunca tienen una sola entrada: el MSE de la app depende de DOS (m y b). Una red neuronal depende de millones de pesos.

La solución: calculamos una derivada por cada variable (las derivadas parciales) y las juntamos en un vector. Ese vector es el gradiente.

$$\nabla L = \left( \frac{\partial L}{\partial m},\; \frac{\partial L}{\partial b} \right)$$

El símbolo se lee "nabla". El gradiente es un vector (una flecha con dirección y longitud). Para una red con un millón de pesos, el gradiente es un vector de un millón de números.

Visualizador del "tazón". Esto es el paisaje del error visto desde arriba. Cada curva de nivel (como un mapa topográfico) une puntos con el MISMO error. El centro azul es el mínimo (error bajo), los bordes rojos son error alto. Arrastrá el punto blanco y mirá cómo la flecha (el gradiente) siempre apunta hacia donde el error sube más rápido.

m-1.50
b1.20
L (error)
|∇L|
∂L/∂m
∂L/∂b
La flecha roja es el gradiente (∇L) — apunta cuesta arriba. La flecha azul punteada es hacia donde gradient descent se moverá (sentido opuesto). Mirá cómo cuando el punto está lejos del centro, la flecha es larga (pendiente empinada). Cerca del centro, se hace cortita hasta desaparecer.

Qué te dice un gradiente (tres cosas a la vez):

  • Dirección de máxima subida. Si estás parado en la ladera del tazón, el gradiente apunta hacia donde la pendiente es más empinada para ARRIBA.
  • Magnitud (qué tan empinada es esa subida). El vector es largo en pendientes bruscas, corto en zonas planas. En el mínimo exacto, el vector es de longitud cero — por eso en la app principal los gradientes tienden a 0 cuando converge.
  • Contribución de cada variable. Mirando las componentes por separado podés decir "el error cambia mucho cuando muevo m, pero poco cuando muevo b".
Por qué gradient descent RESTA el gradiente. El gradiente apunta hacia arriba. Nosotros queremos bajar. Por eso nos movemos en la dirección opuesta: $$(m, b) \;\leftarrow\; (m, b) \;-\; \text{lr} \cdot \nabla L$$ "El nuevo punto es el viejo menos un pasito en la dirección contraria al gradiente". Esto es EXACTAMENTE la misma regla que usabas en la app principal con m ← m - lr · ∂L/∂m, solo que escrita en forma vectorial.
La analogía de la montaña nublada. Imaginate que estás perdido en una montaña con niebla espesa, no ves nada a más de un metro. Querés bajar al valle pero no sabés dónde está. Lo único que podés hacer: tantear con el pie qué dirección baja más rápido desde donde estás, dar un paso, y repetir. En algún momento llegás al fondo.

Eso ES gradient descent. El gradiente es tu pie tanteando. El lr es qué tan largos son los pasos. El mínimo es el fondo del valle. Si los pasos son demasiado grandes, en vez de bajar cuidadosamente pegás saltos olímpicos con los ojos vendados — y te estrellás contra la ladera opuesta. 💀

Resumen derivada vs gradiente:

Concepto
1 variable  |  varias variables
Función
f(x)  |  L(m, b, ...)
Cambio
f'(x), un número  |  ∇L, un vector
Qué dice
pendiente en ese punto  |  dirección + magnitud de máxima subida
Es 0 en
máximos/mínimos  |  máximos/mínimos
GD
x ← x - lr·f'(x)  |  params ← params - lr·∇L
Glosario — qué significa cada letra

Antes de ver las fórmulas, esto es lo que significa cada símbolo. Volvé acá cuando te pierdas:

x
Entrada (input). En el ejemplo: los metros cuadrados de una casa.
y
Salida real (el valor verdadero que queremos predecir). En el ejemplo: el precio real.
ŷ
"y con sombrero" = predicción del modelo. Lo que el modelo cree que vale y.
m
Pendiente de la recta. Cuánto sube y cuando x aumenta 1. Es uno de los parámetros que el modelo aprende.
b
Intercepto. El valor de y cuando x = 0 (donde la recta cruza el eje vertical). El otro parámetro que se aprende.
n
Cantidad de puntos de datos que tenés. Si tenés 15 casas, n = 15.
i
Índice. Cuando ves xᵢ o yᵢ, es "el x (o y) del punto número i". Va de 1 hasta n.
Σᵢ
"Sumatoria sobre i" = sumá esto para todos los puntos (de i=1 hasta i=n).
L
Loss (pérdida) = el error total del modelo. Un número que queremos hacer chico. Acá usamos MSE.
MSE
Mean Squared Error = promedio del error al cuadrado. Una forma específica de calcular L.
∂L/∂m
"Derivada parcial de L respecto a m". Cuánto cambia el error si movés m un poquitito. Es un gradiente.
∂L/∂b
Lo mismo pero para b. Cuánto cambia el error si movés b un poquitito.
lr
Learning rate = tasa de aprendizaje. Un número chico (ej: 0.0003) que controla qué tan grande es cada paso.
"Se actualiza a". Cuando ves "m ← m - ...", significa que el nuevo valor de m es el viejo menos eso.
¿Qué estamos haciendo matemáticamente?

1) El modelo. Asumimos que la relación entre x (input) e y (salida real) es una recta:

$$\hat{y} = m \cdot x + b$$

Donde $\hat{y}$ es la predicción (lo que el modelo cree), $m$ es la pendiente y $b$ el intercepto. Los parámetros que el modelo aprende son $m$ y $b$. Los datos $(x_i, y_i)$ son fijos — el algoritmo no los toca.

2) La loss function (MSE). Un número que mide qué tan mal está el modelo:

$$L(m, b) = \frac{1}{n} \sum_{i=1}^{n} (\hat{y}_i - y_i)^2 = \frac{1}{n} \sum_{i=1}^{n} (m \cdot x_i + b - y_i)^2$$

Traducción palabra por palabra:

  • L(m, b) = la pérdida depende de los valores actuales de m y b.
  • ŷᵢ - yᵢ = el error del punto número i (predicción menos valor real).
  • ( )² = elevado al cuadrado, para que errores negativos y positivos no se cancelen y para castigar más los errores grandes.
  • Σᵢ = sumá eso para todos los puntos.
  • 1/n = dividí por la cantidad de puntos para obtener el promedio.

Esas líneas rojas verticales en el gráfico son justo (ŷᵢ - yᵢ), el error crudo de cada punto antes de elevarlo al cuadrado.

3) Los gradientes. Son derivadas parciales de $L$: dicen cuánto cambia el error si movés un parámetro un poquitito.

$$\begin{aligned} \frac{\partial L}{\partial m} &= \frac{2}{n} \sum_{i=1}^{n} x_i \cdot (m \cdot x_i + b - y_i) \\[6pt] \frac{\partial L}{\partial b} &= \frac{2}{n} \sum_{i=1}^{n} (m \cdot x_i + b - y_i) \end{aligned}$$

Leyendo $\frac{\partial L}{\partial m}$: "de-ele sobre de-eme" = la derivada parcial de $L$ respecto a $m$. Salen de aplicar la regla de la cadena al MSE. En el panel lateral ves sus valores en vivo — mirá cómo se van acercando a 0 cuando la recta converge.

4) La regla de update. En cada iteración:

$$\begin{aligned} m &\leftarrow m - \text{lr} \cdot \frac{\partial L}{\partial m} \\[4pt] b &\leftarrow b - \text{lr} \cdot \frac{\partial L}{\partial b} \end{aligned}$$

La flecha significa "se reemplaza por". El nuevo valor de m es el viejo m menos lr · ∂L/∂m. El lr (learning rate) es un número chico que controla qué tan grande es el paso. El signo menos es clave: el gradiente apunta hacia donde el error SUBE, por eso restamos para bajar.

5) Convergencia. Cuando los gradientes son ≈ 0, los parámetros dejan de moverse. Estás en el fondo del "tazón" — la mejor recta posible bajo MSE.

¿Por qué al subir el learning rate el modelo enloquece?

La intuición geométrica es clave. Pensá el MSE como un tazón en 3D: los ejes horizontales son m y b, la altura es el error. En regresión lineal este tazón es convexo (una parábola) y tiene un único punto mínimo en el fondo.

El gradiente en cualquier punto apunta hacia arriba de la pendiente (máxima subida). Gradient descent resta lr · gradiente para ir al revés, hacia el fondo.

El problema: el gradiente te da la dirección, no cuánto moverte. Eso lo decide el lr.

  • lr chico → pasitos cortos. Bajás lento pero seguro hasta el fondo.
  • lr justo → pasos medidos. Llegás rápido al mínimo.
  • lr muy grande → pegás un salto tan largo que te pasás de largo y caés en la pared opuesta del tazón, más arriba que donde estabas. El próximo gradiente ahí es aún más grande (más pendiente). El siguiente salto te catapulta todavía más lejos. Los valores se disparan hasta NaN. 💀
Analogía. Es como bajar una escalera pegando saltos. Si el salto es del tamaño del escalón, bajás bien. Si es mucho más grande que el escalón, rebotás contra la pared de enfrente y salís volando.

Lo formal. Para que gradient descent converja en una función convexa, existe un umbral lr_max que depende de la curvatura del tazón (técnicamente, del mayor autovalor del Hessiano, o de la constante de Lipschitz del gradiente). Si lr < lr_max, cada paso reduce el error y converge. Si lr > lr_max, cada paso amplifica el error y el modelo diverge exponencialmente.

Por eso cuando movés el slider hacia arriba, en algún punto cruzás ese umbral y la cosa se rompe. No es gradual — es un umbral duro.

Probá esto en la app:
  • Con lr ≈ 0.0003 (default) mirá cómo converge suavecito.
  • Subilo a 0.001 y vas a ver que oscila un poco antes de asentarse.
  • Subilo más y mirá los valores de m y b — se disparan a millones y después NaN.
  • Bajalo a 0.00001 y dale "Auto" — vas a ver que converge pero tarda una eternidad.
¿Qué tiene que ver esto con redes neuronales?

Todo. Una neurona es básicamente esto:

$$\text{salida} = \sigma(w_1 \cdot x_1 + w_2 \cdot x_2 + \dots + w_n \cdot x_n + b)$$

Si sacás la función de activación, es literalmente una regresión lineal multivariable. Una red neuronal no es más que muchas de estas apiladas, con no-linealidades en el medio para que pueda aprender relaciones más complejas que una recta.

Y el algoritmo para entrenarla es el mismo loop:

  • Predecir con los pesos actuales
  • Calcular el error (loss function)
  • Calcular gradientes de la loss respecto a cada peso
  • Actualizar pesos restando lr · gradiente
  • Repetir

Lo único que cambia en una red profunda es cómo se calculan los gradientes: con backpropagation, que es la regla de la cadena aplicada capa por capa. Pero la idea central es la misma que acá. Si entendés esto, ya tenés el 70% de cómo se entrena cualquier modelo de ML moderno, incluso los LLMs.