Sedici Giorni di Calcolo su Una GPU
Una Singola Esecuzione Lunga
ANDREA-120M richiede ~23 giorni su una RTX 4090 (FP16, 6 step/min, 200K step). Consumi elettrici, panico kernel, crash del proxy, & cambiamenti deliberati di configurazione accadono tutti in quella finestra. Senza checkpoint un singolo intoppo scarta l'intera esecuzione.
v1 ha perso 27K step per un errore (lr=0.001 troppo aggressivo) perché nessun checkpoint era più vicino del punto di lancio. v2 ha assorbito quella lezione: cadenza checkpoint ridotta a ogni 100 step, & un gestore di segnale CUDA garantisce una scrittura checkpoint su SIGTERM.
Tre Ruoli
Un checkpoint svolge tre funzioni contemporaneamente:
1. Punto di recupero. Il processo muore, la macchina si riavvia, kernel panic: riprendi dall'ultimo step_NNNNNN.bin.
2. Punto di pivot pulito. Step 112.619: cambia curriculum senza ritraining. SIGUSR1 forza un checkpoint pulito, il proxy si ferma, nuovi caps & floors vengono inviati, CUDA riprende dal punto salvato sotto una nuova policy.
3. Fork di audit. Confronta due configurazioni agli stessi pesi iniziali: copia un checkpoint, esegui due rami divergenti in avanti, osserva quale converge.
Ogni 100 passi fornisce ~17 minuti di addestramento tra le scritture a 6 passi/min. 100 passi corrispondono anche a sample_every: ogni checkpoint corrisponde a un audit di campione fresco, & ogni audit di campione corrisponde a un punto di recupero.
Tre Ruoli per Un Solo File
Cinque Regioni in Un Solo File
Il Formato
Ogni step_NNNNNN.bin contiene cinque regioni contigue:
[int32 step] [int32 n_params] [n_params x float32 weights] [n_params x float32 m] [n_params x float32 v]
Regione per Regione
Intestazione (8 byte totali). Un numero di step a 32 bit ci dice dove si trova questo snapshot nell'addestramento; un conteggio di parametri a 32 bit ci dice quanto sono grandi i tre array successivi.
Pesi (n_params x 4 byte). Ogni parametro appreso, appiattito. L'ordine corrisponde all'iteratore di parametri del modello: embedding di token e posizione, poi pesi di attenzione e MLP per layer, poi la testa di output.
Primo momento Adam m (n_params x 4 byte). EMA dei gradienti passati (beta1 = 0.9). Stessa forma dei pesi. Richiesto per la ripresa di AdamW.
Secondo momento di Adam v (n_params x 4 byte). EMA dei gradienti al quadrato passati (beta2 = 0.999). Stessa forma dei pesi. Richiesto per la ripresa di AdamW.
Dimensione Totale
Byte totali = 8 + 12 x n_params. ANDREA-12M (12.8M parametri): 154 MB su disco (147 MB arrotondati). ANDREA-120M (~120M parametri) FP32: ~1.44 GB. Tre array della stessa forma, accatastati uno dopo l'altro, con un piccolo header.
Perché Salvare m & v
Adam vanilla traccia i tassi di apprendimento per parametro tramite m & v. Se li si elimina alla scrittura del checkpoint, una run ripresa parte con momentum zero e stima di varianza zero, equivalente a learning rate 0 per un passo poi un improvviso ramp. La loss schizza; il modello può cadere fuori dal suo bacino corrente. Salvare m & v rende la ripresa bit-equivalente (modulo casualità del dataloader) al baseline mai fermato.
Dimensionamento di un Checkpoint
SIGTERM & SIGUSR1
Perché CUDA Gestisce i Segnali
Il training viene eseguito come un processo in foreground a lunga durata. Quando il proxy o l'operatore vuole fermare la GPU, un segnale viene inviato al motore CUDA. Senza un handler, il SIGTERM predefinito uccide il processo immediatamente: il calcolo del gradiente in corso viene scartato, i pesi più recenti dal último checkpoint vanno persi. Con un handler, il motore scrive prima un checkpoint e poi esce in modo pulito.
SIGTERM: scrivi & esci
Inviato da un pulsante di stop, un systemctl stop, o un kill da un proxy genitore. CUDA termina il passo corrente, scrive step_NNNNNN.bin su disco, poi esce. Il recupero da questo stato richiede solo l'ultimo .bin: zero lavoro perso oltre al passo parziale in corso.
SIGUSR1: scrivi & continua
Inviato su richiesta da un operatore o script proxy. CUDA termina il passo corrente, scrive step_NNNNNN.bin, poi continua il training come se nulla fosse accaduto. Utile per: attivare un punto di audit subito prima di un cambio di configurazione; catturare i pesi in un momento noto-buono; allineare un checkpoint con una run di valutazione della qualità del campione esterno.
La Sequenza Pivot Polacca (step 112,619)
1. L'operatore invia SIGUSR1 a CUDA. Il checkpoint viene scritto al prossimo confine di 100 step (step 112,700).
2. L'operatore ferma il proxy.
3. .samples.json & .state.json vengono archiviati (log di campionamento & stato bandit preservati come record storico).
4. .loss.json rimane al suo posto. Cronologia cumulativa dell'addestramento; mai archiviata.
5. Il proxy riavvia con nuovi caps & floors.
6. CUDA riprende da step_112700.bin con un bandit fresco ma pesi, m, & v completi.
La cronologia delle perdite continua ininterrotta attraverso il pivot. Il log di esempio si resetta in modo pulito. Bandit ottiene un nuovo inizio sotto la nuova policy.
Scegliere il Segnale
Cronologia Cumulativa dell'Addestramento
Tre File Sidecar
Accanto a ogni checkpoint, il proxy mantiene tre sidecar JSON nella directory di esecuzione:
- .loss.json -- una voce per step, sempre. ~200.000 voci alla fine della run. Cronologia cumulativa dell'addestramento.
- .samples.json -- campioni generati recenti per audit. Reset su pivot di polish.
- .state.json -- bandit arm pulls, EMA rewards, contatori di fase. Reset su pivot di polish.
Cosa Si Resetta, Cosa Persiste
I pivot di polish sono cambiamenti di policy, non reset della run. I pesi del modello, m, v e la storia delle loss continuano ininterrotti. Le ricompense accumulate dal bandit NON continuano: i nuovi cap e floor definiscono una policy diversa, e il bandit deve ri-imparare sotto la nuova policy da uno stato pulito.
Perché .loss.json Rimane
La storia delle loss funge da traccia di audit della run. Ogni affermazione pubblicata su ANDREA-120M (EMA della loss al passo 110K, recupero dal pivot di polish, convergenza al passo 112K) risale alle voci in questo file. Archiviare .loss.json tra le fasi costringerebbe i lettori a cucire insieme frammenti per ricostruire la run; mantenerlo append-only e intoccato preserva la provenienza.
La Lezione del Braccio Zombie
Al passo 112,619 è stato trovato un braccio repo-docstrings in .state.json con peso 1.546 da una run precedente. Lo stato del bandit era stato preservato attraverso un riavvio precedente, ma la fonte dati non era più disponibile, producendo estrazioni zombie che distorcevano la contabilità dell'esplorazione. Lezione: lo stato del bandit È consentito driftare attraverso i riavvii in modi sorprendenti. La storia delle loss è l'unico file che deve rimanere intoccato per l'intera durata della run.
Una Regola per Governare Tutte
Archivia liberamente .samples.json & .state.json tra le fasi. Non archiviare mai .loss.json. L'ultima .loss.json è sempre la storia canonica dell'addestramento.
Applicare la Regola
Cosa è stato costruito e perché
Cinque Decisioni
1. Cadenza: ogni 100 passi. Granularità del punto di recupero ~17 minuti. Allineato con sample_every in modo che ogni checkpoint corrisponda a un audit di un campione fresco.
2. Formato: header + 3 array. Minimo: header di 8 byte ci dice quanto è grande ogni array successivo. Nessun gonfiore di metadati. Ripresa bit-equivalente quando m & v vengono salvati.
3. Segnali: SIGTERM & SIGUSR1. Due ruoli, due segnali. Lo spegnimento predefinito di systemd ottiene un checkpoint pulito tramite SIGTERM; i punti di audit su richiesta ottengono un checkpoint pulito tramite SIGUSR1 senza fermarsi.
4. Continuità della loss: mai archiviata. La storia cumulativa dell'addestramento persiste attraverso pivot di polish, riavvii e cambiamenti di policy. Un unico trail di audit per l'intera esecuzione.
5. Stato bandit: reset consentiti. La policy bandit vive sotto una config alla volta. I pivot di polish resettano; la storia della loss continua. Due vite diverse condividono la stessa directory di run.
A Cosa Si Collega Questa Lezione
- Attività 23 (grow_a_language_model_sample_audit). La cadenza sample_every corrisponde alla cadenza del checkpoint; entrambi si attivano ogni 100 step.
- Attività 24 (grow_a_language_model_microgpt_to_andrea). Il collasso v1, la patch v2.5, il pivot di lucidatura v3 richiedono tutti checkpoint puliti per funzionare.
- Attività 10 (grow_a_language_model_adamw). Salvare m & v nel checkpoint è importante perché la regola di aggiornamento di AdamW dipende da entrambi. Ometterli & riprendere causa divergenza.
Un'Ultima Verità sull'Ingegneria
Il codice sopravvive agli autori. L'infrastruttura sopravvive ai costruttori. Un semplice formato di checkpoint sopravvive a ogni schema di ripresa elaborato che prometteva di saltare il salvataggio dello stato dell'ottimizzatore. Risparmia i byte; salva l'esecuzione.