Dieciséis Días de Cómputo en Una GPU
Una Ejecución Larga Única
ANDREA-120M toma ~23 días en una RTX 4090 (FP16, 6 pasos/min, 200K pasos). Consumo de energía de la pared, pánicos del kernel, fallos del proxy, & cambios deliberados de configuración todos ocurren a lo largo de esa ventana. Sin puntos de control, un solo inconveniente descarta toda la ejecución.
v1 perdió 27K pasos por un error (lr=0.001 demasiado agresivo) porque no había un punto de control más cercano que el punto de lanzamiento. v2 absorbió esa lección: la cadencia de puntos de control bajó a cada 100 pasos, & un manejador de señales CUDA garantiza la escritura de un punto de control en SIGTERM.
Tres Roles
Un checkpoint cumple tres funciones a la vez:
1. Punto de recuperación. El proceso muere, la máquina se reinicia, pánico del kernel: reanuda desde el último step_NNNNNN.bin.
2. Pivote pulido. Paso 112,619: cambia el currículo sin reentrenar. SIGUSR1 fuerza un checkpoint limpio, el proxy se detiene, se envían nuevos límites superiores e inferiores, CUDA reanuda desde el punto guardado bajo una nueva política.
3. Bifurcación de auditoría. Compara dos configuraciones con los mismos pesos iniciales: copia un checkpoint, ejecuta dos ramas divergentes hacia adelante, observa cuál converge.
Cada 100 pasos da ~17 minutos de entrenamiento entre escrituras a 6 pasos/min. 100 pasos también coincide con sample_every: cada checkpoint corresponde a una auditoría de muestra fresca, & cada auditoría de muestra corresponde a un punto recuperable.
Tres Roles para Un Solo Archivo
Cinco Regiones en Un Solo Archivo
El Formato
Cada step_NNNNNN.bin empaqueta cinco regiones contiguas:
[int32 step] [int32 n_params] [n_params x float32 weights] [n_params x float32 m] [n_params x float32 v]
Región por Región
Encabezado (8 bytes en total). Un número de paso de 32 bits nos indica dónde en el entrenamiento se encuentra esta instantánea; un conteo de parámetros de 32 bits nos indica qué tan grandes son los tres arreglos siguientes.
Pesos (n_params x 4 bytes). Cada parámetro aprendido, aplanado. El orden coincide con el iterador de parámetros del modelo: embeddings de token y posición, luego pesos de atención y MLP por capa, luego la cabeza de salida.
Primer momento de Adam m (n_params x 4 bytes). EMA de gradientes pasados (beta1 = 0.9). Misma forma que los pesos. Requerido para la reanudación de AdamW.
Segundo momento de Adam v (n_params x 4 bytes). EMA de gradientes al cuadrado pasados (beta2 = 0.999). Misma forma que los pesos. Requerido para la reanudación de AdamW.
Tamaño Total
Bytes totales = 8 + 12 x n_params. ANDREA-12M (12.8M params): 154 MB en disco (147 MB redondeado). ANDREA-120M (~120M params) FP32: ~1.44 GB. Tres arrays de forma idéntica, apilados uno tras otro, con un pequeño encabezado.
Por qué guardar m & v
Adam vainilla rastrea tasas de aprendizaje por parámetro mediante m & v. Si se eliminan al escribir el checkpoint, una ejecución reanudada comienza con momento cero y estimación de varianza cero, equivalente a tasa de aprendizaje 0 por un paso y luego una rampa repentina. La pérdida se dispara; el modelo puede salir de su cuenca actual. Guardar m & v hace que la reanudación sea bit-equivalente (salvo aleatoriedad del dataloader) a la línea base que nunca se detuvo.
Dimensionamiento de un Checkpoint
SIGTERM & SIGUSR1
Por qué CUDA Maneja Señales
El entrenamiento se ejecuta como un proceso en primer plano de larga duración. Cuando el proxy o el operador quiere que la GPU se detenga, se envía una señal al motor CUDA. Sin un manejador, el SIGTERM predeterminado mata el proceso inmediatamente: el cálculo de gradientes en vuelo se descarta, los pesos más recientes desde el último punto de control se pierden. Con un manejador, el motor escribe un punto de control primero y luego sale de manera limpia.
SIGTERM: escribir y salir
Enviado por un botón de detención, un systemctl stop, o un kill desde un proxy padre. CUDA finaliza el paso actual, escribe step_NNNNNN.bin en disco, luego sale. La recuperación desde este estado solo necesita el último .bin: cero trabajo perdido más allá del paso parcial en vuelo.
SIGUSR1: escribir y continuar
Enviado bajo demanda por un operador o script proxy. CUDA finaliza el paso actual, escribe step_NNNNNN.bin, luego continúa el entrenamiento como si nada hubiera pasado. Útil para: activar un punto de auditoría justo antes de un cambio de configuración; capturar pesos en un momento conocido-bueno; alinear un punto de control con una ejecución de calificación de calidad de muestra externa.
La Secuencia de Pivoteo Polaco (paso 112,619)
1. El operador envía SIGUSR1 a CUDA. El checkpoint se escribe en el siguiente límite de 100 pasos (paso 112,700).
2. El operador detiene el proxy.
3. .samples.json & .state.json se archivan (registro de muestras & estado del bandit preservados como registro histórico).
4. .loss.json permanece en su lugar. Historial de entrenamiento acumulativo; nunca archivado.
5. El proxy se reinicia con nuevos límites superiores & inferiores.
6. CUDA reanuda desde step_112700.bin con un bandit fresco pero pesos completos, m, & v.
El historial de pérdidas continúa sin interrupciones a través del pivote. El registro de muestra se reinicia limpiamente. Bandit obtiene un nuevo comienzo bajo la nueva política.
Elegir la Señal
Historial de Entrenamiento Acumulativo
Tres Archivos Secundarios
Junto a cada punto de control, el proxy mantiene tres archivos secundarios JSON en el directorio de ejecución:
- .loss.json -- una entrada por paso, siempre. ~200,000 entradas al final de la ejecución. Historial acumulativo de entrenamiento.
- .samples.json -- muestras generadas recientes para auditoría. Se restablece en pivotes de pulido.
- .state.json -- tirones de brazos de bandido, recompensas EMA, contadores de fase. Se restablece en pivotes de pulido.
Qué Se Restablece, Qué Persiste
Los pivotes de pulido son cambios de política, no reinicios de ejecución. Los pesos del modelo, m, v y el historial de pérdida continúan ininterrumpidos. Las recompensas acumuladas del bandit NO continúan: los nuevos techos y suelos definen una política diferente, y el bandit debe re-aprender bajo la nueva política desde un estado limpio.
Por qué .loss.json Permanece
El historial de pérdida sirve como el rastro de auditoría de la ejecución. Toda afirmación publicada sobre ANDREA-120M (EMA de pérdida en el paso 110K, recuperación post-pivote de pulido, convergencia en el paso 112K) se remonta a entradas en este archivo. Archivar .loss.json entre fases obligaría a los lectores a unir fragmentos para reconstruir la ejecución; mantenerlo solo en modo append y sin tocar preserva la procedencia.
La Lección del Brazo Zombi
El paso 112,619 encontró un brazo repo-docstrings en .state.json con peso 1.546 de una ejecución previa. El estado del bandit se había preservado a través de un reinicio anterior, pero la fuente de datos ya no estaba disponible, produciendo tirones zombis que distorsionaban la contabilidad de exploración. Lección: el estado del bandit SÍ puede desviarse a través de reinicios de maneras sorprendentes. El historial de pérdida es el único archivo que debe permanecer intocado durante toda la vida de la ejecución.
Una Regla para Gobernarlas Todas
Archiva .samples.json y .state.json libremente entre fases. Nunca archives .loss.json. El .loss.json más reciente es siempre el historial de entrenamiento canónico.
Aplicando la Regla
Qué se Construyó & Por Qué
Cinco Decisiones
1. Cadencia: cada 100 pasos. Granularidad del punto de recuperación ~17 minutos. Alineado con sample_every para que cada punto de control corresponda a una auditoría de muestra fresca.
2. Formato: encabezado + 3 arreglos. Mínimo: encabezado de 8 bytes nos dice qué tan grande es cada arreglo subsiguiente. Sin hinchazón de metadatos. Reanuda bit por bit cuando se guardan m & v.
3. Señales: SIGTERM & SIGUSR1. Dos roles, dos señales. El apagado predeterminado de systemd obtiene un punto de control limpio vía SIGTERM; los puntos de auditoría bajo demanda obtienen un punto de control limpio vía SIGUSR1 sin detenerse.
4. Continuidad de pérdida: nunca archivada. El historial acumulativo de entrenamiento persiste a través de pivotes de pulido, reinicios & cambios de política. Una sola pista de auditoría para toda la ejecución.
5. Estado de Bandit: reseteos permitidos. La política de Bandit vive bajo una configuración a la vez. Los pivotes de pulido resetean; el historial de pérdida continúa. Dos vidas diferentes comparten el mismo directorio de ejecución.
A qué se conecta esta lección
- Actividad 23 (grow_a_language_model_sample_audit). La cadencia sample_every coincide con la cadencia de checkpoint; ambas se activan cada 100 pasos.
- Actividad 24 (grow_a_language_model_microgpt_to_andrea). El colapso v1, el parche v2.5, el pivote de pulido v3 todos requieren checkpoints limpios para operar.
- Actividad 10 (grow_a_language_model_adamw). Guardar m & v en el checkpoint importa porque la regla de actualización de AdamW depende de ambos. Omitirlos & reanudar diverge.
Una última verdad de ingeniería
El código sobrevive a los autores. La infraestructura sobrevive a los constructores. Un formato de checkpoint simple sobrevive a todos los esquemas de reanudación sofisticados que prometieron omitir el guardado del estado del optimizador. Ahorra los bytes; ahorra la ejecución.