English · Español
02 — La regla de la cadena y el gradiente de softmax + cross-entropy¶
🇪🇸 La regla de la cadena para funciones vectoriales es producto de Jacobianos. Aplicada a softmax + cross-entropy, colapsa en una línea:
∂CE/∂x = softmax(x) - one_hot(y). Esta página deriva ambos.
Esta es la página de teoría de la Fase 4. Vuelve a derivar todo lo de abajo desde una página en blanco hasta que sea mecánico.
Regla de la cadena de una variable¶
Para h(x) = f(g(x)):
La derivada de la función externa evaluada en la interna, por la derivada de la interna. Memoriza.
Trabajado: h(x) = sin(x²). Con f(u) = sin(u), g(x) = x²:
Regla de la cadena multivariable (la versión que usa backprop)¶
Para f: R^k → R^m y g: R^n → R^k, sea h = f ∘ g: R^n → R^m. Entonces:
Producto matricial de Jacobianas. Formas: (m × n) = (m × k) · (k × n). La dimensión interna k coincide por construcción (salida de g = entrada de f).
Para una pérdida escalar L = f(g(x)) con f: R^k → R y g: R^n → R^k:
J_f = ∇_y L^Tes un vector fila1 × k(transpuesta del gradiente).J_gesk × n.J_h = ∇_x L^T = ∇_y L^T · J_ges1 × n.
Transponiendo para obtener el gradiente como columna:
Esta es la fórmula que usa backprop. Léela como: "para calcular el gradiente respecto a la entrada de g, multiplica la Jacobiana de g (transpuesta) por el gradiente respecto a la salida de g".
Aplica capa por capa:
leyendo de derecha a izquierda. Empieza con el gradiente en la salida (∇_y L, normalmente trivial — p. ej., para L = escalar, ∇_y L = 1). En cada capa, multiplica por la Jacobiana transpuesta de la capa. Continúa de vuelta hasta la entrada.
Este recorrido es lo que implementa cada framework de autograd. La Fase 7 lo programará directamente.
¿Por qué de derecha a izquierda?¶
Dos formas equivalentes de calcular el gradiente:
-
Modo directo (izquierda a derecha): propaga Jacobianas hacia adelante, multiplicando
(m × k) × (k × n)en cada paso. Para redes profundas conm = 1(pérdida escalar) peronenorme (millones de parámetros), cada paso es un gran producto matriz-matriz. -
Modo inverso (derecha a izquierda): empieza con el vector
∇_y L: (m,) = (1,)y propágalo hacia atrás. En cada paso, solo multiplicas matriz × vector, nunca matriz × matriz.
Para redes profundas donde m = 1 (una pérdida) y n enorme (parámetros del modelo), el modo inverso es enormemente más barato: O(parámetros) por pase hacia atrás vs O(parámetros²) para el modo directo.
A la inversa, si m es enorme (muchas salidas) y n pequeño (pocas entradas), gana el modo directo.
Para ML: siempre modo inverso. Esta es la razón de que "retropropagación" sea el nombre — propagas gradientes hacia atrás a través del grafo.
Trabajado: y = Wx + b luego L = ||y||²¶
Capas: L = f(y), y = g(x) = Wx + b.
f(y) = ||y||² = y^T y.∇_y L = 2y. (Columna.)g(x) = Wx + b.J_g(x) = W.
Por tanto:
Comprobación: expansión directa. L(x) = ||Wx + b||² = (Wx + b)^T (Wx + b). Gradiente directo: ∇_x L = 2 W^T (Wx + b). Misma respuesta.
El punto no es esta fórmula concreta; es que la regla de la cadena vía Jacobianas produce la respuesta correcta mecánicamente, sin re-derivar desde cero cada vez.
Trabajado: gradiente de cross-entropy a través de softmax¶
Esta es la derivación de gradiente más importante en la Fase 4. La haremos de tres formas: a mano, vía regla de la cadena, y como comprobación.
Planteamiento¶
- Logits
x ∈ R^V(V = tamaño del vocab). - Probabilidades
p = softmax(x), así quep_i = e^{x_i} / Σ_j e^{x_j}. - Etiqueta verdadera
y ∈ {0, ..., V-1}. - Pérdida
L = -log p_y = -x_y + log Σ_j e^{x_j}(la forma CE estable de la Fase 2).
Queremos ∂L/∂x_i para cada i.
A mano¶
Dos términos.
Primer término: ∂(-x_y)/∂x_i = -δ_{iy} (delta de Kronecker: 1 si i = y, sino 0).
Segundo término: ∂(log Σ_j e^{x_j}) / ∂x_i. Sea S = Σ_j e^{x_j}. Entonces log S se deriva como (1/S) · ∂S/∂x_i = (1/S) · e^{x_i} = p_i.
Combina:
O como vector:
Esto colapsa a una sola línea. Sin log, sin exp, sin inversa — el cálculo intermedio engorroso se cancela.
Por qué es bello¶
Tres razones:
-
Numérico: calcular
softmax(x) - one_hot(y)es una resta. Sin riesgo de underflow / overflow más allá de lo questable_softmaxya maneja. El autograd de la Fase 7 implementa esto directamente como el backward de cross-entropy. -
Computacional: si el pase hacia adelante del modelo calculó
p = softmax(x), entonces el pase hacia atrás solo resta one_hot. Cero cómputo nuevo necesario. Por eso cada framework fusiona softmax + cross-entropy como una sola op. -
Pedagógico: la función de pérdida más usada en aprendizaje profundo tiene el gradiente más limpio posible. Hay una razón por la que esta es la pérdida que todos usan para clasificación — su cálculo es amable.
Vía la regla de la cadena¶
Por completitud, hagámosla como composición de dos Jacobianas (así vemos la cancelación explícita del matmul).
- Capa interna:
p = softmax(x). JacobianaJ_softmax(x) = diag(p) - p p^T(la derivarás en el lab 00). - Capa externa:
L = -log(p_y). Gradiente∇_p L = -(1/p_y) · e_ydondee_yes el vector base estándar. Así que(∇_p L)_i = -δ_{iy} / p_y.
Aplica regla de la cadena:
Calcula el producto matriz-vector:
diag(p) · (-e_y / p_y) = -e_y(la entradae_y-ésima esp_y · (-1/p_y) = -1; las demás son 0).p p^T · (-e_y / p_y) = -p_y · p / p_y = -p.
Por tanto:
Misma respuesta. La estructura diagonal-más-rango-uno de la Jacobiana intermedia se cancela exactamente en la resta one-hot.
Esto es lo que el código de autograd de la Fase 7 implementará implícitamente — es por lo que cross_entropy_with_logits existe como op fusionada en cada framework.
Comprobación vía diferencias finitas¶
En el lab 00 verificarás el resultado analítico con diferenciación numérica. Usa diferencias centradas:
con h = 1e-4. Las respuestas numérica y analítica deben coincidir hasta aproximadamente 1e-4 — limitado por el error de truncamiento h².
Si ves un desacuerdo mayor que 1e-3, tu derivación analítica está mal. (No le eches la culpa al ruido numérico sin re-derivar.)
Trabajado: gradiente de (W_2 relu(W_1 x))¶
Una cadena de dos capas lineal-relu-lineal. No la derivaremos completamente aquí (el lab 01 lo hace), pero el recorrido de la regla de la cadena es:
- Forward:
z_1 = W_1 xa_1 = relu(z_1)z_2 = W_2 a_1-
L = función escalar de z_2 -
Backward (empieza con
g_2 = ∇_{z_2} L): ∇_{a_1} L = W_2^T g_2(Jacobiana de capa lineal = W^T).∇_{z_1} L = ∇_{a_1} L * relu'(z_1)(elemento a elemento * porque la Jacobiana de relu es diagonal).∇_x L = W_1^T · ∇_{z_1} L.
Los gradientes de los parámetros:
∇_{W_2} L = g_2 · a_1^T(producto exterior — el gradiente es contribución de rango 1 por muestra).∇_{W_1} L = (∇_{z_1} L) · x^T.
Volverás a derivar esto en el lab 01 y verificarás con diferencias finitas.
Problemas de práctica¶
Soluciones en solutions/02-chain-rule-and-backprop-ref.md en la apertura de fase.
- Deriva
∂/∂x sigmoid(x). Demuestra que es igual aσ(x)(1 - σ(x)). - Deriva
J_softmax(x)paraxde longitudn. Demuestra que esdiag(p) - p p^T. - Deriva
∂ L / ∂ W_1para la MLP de 2 capas de arriba. Demuestra que la respuesta es el producto exteriorg_1 · x^Tdondeg_1 = ∇_{z_1} L. - La función "log-softmax" es
log_softmax(x)_i = x_i - log_sum_exp(x). Deriva su Jacobiana. Demuestra que∂ log_softmax(x)_i / ∂ x_j = δ_{ij} - p_j. - ¿Por qué
-log(softmax(x)_y)colapsa tan limpiamente mientras quesoftmax(x)_ypor sí mismo no? (Pista: ellogdeshace uno de losexp.) - Para la pérdida
L = -log softmax(x)_y, verifica numéricamente (diferencias centradas,h = 1e-4) que∇_x L = softmax(x) - one_hot(y)para unxespecífico de tu elección.
Recapitulación en un párrafo¶
La regla de la cadena para funciones vectoriales es multiplicación de matrices Jacobianas, aplicada de derecha a izquierda al calcular el gradiente de una pérdida escalar — el "modo inverso" de la diferenciación automática que implementa backprop. El gradiente más limpio en aprendizaje profundo es para cross-entropy a través de softmax: ∇_x L = softmax(x) - one_hot(y), derivable en tres líneas y calculado esencialmente gratis a partir del pase hacia adelante. Cada operación de autograd de la Fase 7 en adelante es solo un caso especial de "almacenar valores intermedios durante el forward; recorrer el grafo al revés, multiplicando por Jacobianas transpuestas". El trabajo de la Fase 4 es hacer esa derivación refleja; la Fase 7 la convierte en código.
Siguiente: theory/03-optimizers-derived.md.