English · Español
Break 00 — Desactivar el sigmoide de las puertas del LSTM (reemplazar por la identidad)¶
🇪🇸 Rompemos las puertas: el
σde las puertasforget,inputyoutputse reemplaza por la identidad. Las puertas dejan de estar en(0, 1)y pueden tomar valores no acotados. Predice: la celdac_tcrece sin control; el gradiente explota; la pérdida esNaNen pocos pasos.Anclas:
LYNX_CORTEX.md§4 / PHASE 14; theory §02 recurrencia de la RNN; theory §04 flujo del gradiente;.claude/commands/break.md.
La rotura¶
En src/minimodel/nn/lstm.py:
class LSTM(Module):
def forward(self, x_t: Tensor, h_prev: Tensor, c_prev: Tensor) -> tuple[Tensor, Tensor]:
z = self.input_to_hidden(x_t) + self.hidden_to_hidden(h_prev)
i, f, g, o = z.split(4, dim=-1)
# BUG: eliminados los sigmoides de las puertas.
i = i # era: i.sigmoid()
f = f # era: f.sigmoid()
o = o # era: o.sigmoid()
g = g.tanh() # el candidato mantiene tanh (sin cambios)
c_t = f * c_prev + i * g
h_t = o * c_t.tanh()
return h_t, c_t
Tres cambios de una línea. Fíjate en que mantenemos g.tanh() para que la actualización de la celda candidata siga acotada. Las puertas forget/input/output pierden su acotación.
Predice, luego ejecuta¶
El rango correcto de la puerta forget es (0, 1). Con la identidad, f_t puede valer -3, 5, -100, lo que sea. La actualización de la celda:
Ahora f_t no está acotada, así que c_t ya no está garantizado acotado. Peor: en el backward,
así que la autopista del gradiente a través de c_t es ahora Π_{t} f_t — un producto de reales no acotados. El gradiente explosivo es el modo de fallo dominante.
Predicciones¶
NaNen la pérdida de entrenamiento en 5-20 pasos cuandoc_tdesborde fp32 (>3.4e38).- Si reduces el LR por 1000×, el modelo aguanta un poco más pero converge a una solución degenerada donde
f_tsatura a ~0 (olvidándolo todo en la práctica — el LSTM se ha vuelto un mapeo feedforward). - Las normas del gradiente disparan por encima de
1e10antes del NaN.
Escribe predicciones en learners/borja/phase-14/notes/breaks.md antes de ejecutar.
Observa¶
Diagnósticos:
- Dibuja
||c_t||_∞por paso. Debería crecer sin acotarse. - Dibuja las normas del gradiente —
>1e6es la zona de peligro. - Tras el NaN: imprime los valores
i, f, odel último paso correcto. Deberían estar muy fuera de(0, 1).
Síntoma que Borja verá¶
loss = NaNen <20 pasos.c_t.max() > 1e30en el paso anterior al NaN.- Norma del gradiente
>1e8en los pasos previos al NaN.
Causa oculta (en una frase)¶
Se eliminó el sigmoide de las puertas forget/input/output, dejándolas no acotadas — c_t = f_t * c_{t-1} + i_t * g_t desborda porque f_t ya no está en (0, 1).
Cascada de pistas¶
- ¿Cuál es el rango de cada puerta del LSTM, y por qué? Imprime el rango empírico durante la ejecución.
- Calcula
c_tdurante unos pocos pasos a mano — ¿qué pasa sif_t > 1? - Mira el forward del LSTM en
nn/lstm.py. ¿Pasan todas las cuatro activaciones pre-puerta por su no-linealidad correcta?
Diff del arreglo¶
Por qué esto enseña el concepto¶
El sigmoide en las puertas del LSTM no es estético — es el requisito matemático del mecanismo de gating. f_t ∈ (0, 1) es lo que convierte c_t = f_t · c_{t-1} + ... en una operación controlable de olvido. Sin el sigmoide, ya no tienes "un LSTM" — tienes una recurrencia lineal arbitraria no acotada, que es exactamente la clase de modelo que los LSTM se inventaron para evitar (Hochreiter & Schmidhuber 1997, sección de motivación). Esta rotura es una demostración con las manos de por qué las funciones de activación en arquitecturas con puertas (LSTM, GRU, el softmax de la attention, las puertas de expertos en MoE) están restringidas por razones de flujo del gradiente — no por razones estilísticas.
Siguiente: el /break de la Fase 15 sobre el escalado sqrt(d_k) ausente.