Skip to content

English · Español

Lab 01 — Ablación de inicialización: el experimento estrella de las tres curvas

Objetivo: mostrar que la inicialización (init) por sí sola — mismos datos, misma arquitectura, mismo optimizador — convierte una red de "entrena" a "no entrena".

Tiempo estimado: 90–120 minutos.

Prerrequisito: lab 00 commiteado.


Qué produces

Un directorio experiments/10-init-matters/ que contiene:

  • train.py — tu script de entrenamiento.
  • losses.json — tres trayectorias de pérdida (uniforme, Xavier, Kaiming).
  • loss_curves.png — tres curvas en los mismos ejes.
  • manifest.json — estándar.
  • README.md (3–4 párrafos) explicando qué entrenaste y qué pasó.

El montaje

Un MLP de 12 capas con activaciones ReLU, dimensión oculta 256, entrenado durante 1000 pasos sobre el problema de clasificación de juguete de la Fase 9 (o generado sintéticamente aquí — ver abajo).

Tres ejecuciones idénticas que difieren sólo en la inicialización:

  1. Uniforme [-0.5, 0.5].
  2. Xavier N(0, 1/n_in).
  3. Kaiming N(0, 2/n_in).

Resultado esperado:

  • Uniforme: explosión del paso hacia adelante → NaN en ~20 pasos, o ReLU saturada → la pérdida se estanca al azar.
  • Xavier: entrena, pero lento. La curva de pérdida desciende perezosamente.
  • Kaiming: entrena como se espera. Descenso suave.

La figura estrella son las tres curvas en los mismos ejes, claramente diferenciadas.

Datos de juguete

Si no construiste ya el dataset "safe/unsafe token" de juguete de la Fase 9, genera uno sintético:

  • 1000 ejemplos de entrenamiento, 200 de validación.
  • Entrada: vectores gaussianos de 256 dimensiones.
  • Etiqueta: 0 si la suma de los primeros 10 elementos es negativa, 1 en caso contrario (determinista, linealmente separable en las primeras 10 dimensiones).

Esto es trivialmente aprendible por una red de 1 capa. El punto del experimento no es la dificultad de la tarea — es que una mala inicialización convierte una tarea trivialmente aprendible en irresoluble.

TODOs

Bloque A — escribe el bucle de entrenamiento

  • MLP de 12 capas, oculta 256, activaciones ReLU entre capas, sin norm, sin residual.
  • Usa minitorch.nn.Linear + minitorch.nn.ReLU de la Fase 9.
  • Pérdida: entropía cruzada.
  • Optimizador: SGD con momentum 0.9, LR 1e-3.
  • Tamaño de batch 64.
  • 1000 pasos en total.
  • Registra la pérdida en cada paso.

Bloque B — tres ejecuciones

  • Ejecución con init = uniforme[-0.5, 0.5]. Guarda la trayectoria de pérdida.
  • Ejecución con init = Xavier. Guarda.
  • Ejecución con init = Kaiming. Guarda.
  • Misma semilla para el barajado de datos entre ejecuciones (para que las tres vean secuencias de batches idénticas).
  • Semilla distinta para el muestreo de pesos de cada inicialización (para que las inicializaciones en sí sean draws independientes).

Bloque C — gráfico

  • matplotlib. eje x: paso (0 a 1000). eje y: pérdida (lineal o logarítmica — prueba ambas, elige la más informativa).
  • Tres curvas con colores distintos y leyenda.
  • Anota: marcadores de NaN si alguna ejecución diverge; marcadores de estancamiento si alguna se atasca en la pérdida aleatoria.
  • Guarda como loss_curves.png.

Bloque D — interpreta

En README.md, responde:

  1. ¿En qué paso produjo la inicialización uniforme su primer NaN (o saturación)?
  2. ¿Cuál es la pérdida final de Xavier vs la de Kaiming?
  3. ¿Está Xavier entrenando o casi sin entrenar? Calcula la pendiente de su curva de pérdida sobre los últimos 200 pasos.
  4. Predice, sin ejecutar: si aumentaras la profundidad de 12 a 24 capas, ¿cómo cambiaría cada una de las tres curvas? Justifica brevemente.

Bloque E — manifest

Estándar. results_summary debería incluir {steps_to_nan_uniform, final_loss_xavier, final_loss_kaiming}.

Restricciones

  • Sin normalización. El lab 02 es para eso.
  • Sin residuales. El lab 03 es para eso.
  • Misma semilla para datos, semillas independientes para pesos. No los confundas.
  • Ejecuta con el governor performance. La variación en tiempo por paso ruidearía la comparación.

Condiciones de parada

Hecho cuando:

  1. El directorio tiene los cinco archivos.
  2. El gráfico de tres curvas está commiteado y visualmente nítido.
  3. La ejecución uniforme diverge o se estanca; la de Kaiming entrena; la de Xavier está en algún punto intermedio.
  4. El README responde las cuatro preguntas del Bloque D.

Trampas

  • Las tres curvas se ven idénticas. Probablemente no estés re-inicializando entre ejecuciones. Comprueba que haces model = build_mlp(init=...) cada vez, no sólo optimizer.zero_grad().
  • Las tres curvas divergen. Tu LR es demasiado alto. Bájalo a 1e-4 e inténtalo de nuevo.
  • Las tres curvas entrenan bien. Tu profundidad es demasiado superficial. Súbela a 24 capas.
  • La uniforme no hace NaN, sólo se estanca. Podría ser que la ReLU está saturando (todo cero) — el gradiente es cero en todas partes, sin NaN, pero sin aprendizaje. Anótalo en el README; es un modo de fallo distinto a la explosión pero con la misma causa subyacente.

Pista de último recurso

Si llevas 90 minutos y la inicialización uniforme aún entrena: imprime np.var(model.layers[0].weight.data) tras la inicialización. Debería ser 1/12 ≈ 0.083. Si por accidente extrajiste uniforme [-0.05, 0.05], la varianza es ≈ 0.0008 — básicamente tipo Xavier. Revisa los límites de tu inicialización.

Cuándo consultar solutions/

Tras commitear los cinco archivos. Solución: solutions/01-init-ablation-ref.md (fase abierta).


Siguiente lab: lab/02-norm-ablation.md.