Sechzehn Tage Rechenleistung auf einer GPU
Ein einziger langer Lauf
ANDREA-120M dauert ~23 Tage auf einer RTX 4090 (FP16, 6 Schritte/Min, 200K Schritte). Stromausfälle, Kernel-Panics, Proxy-Abstürze & bewusste Konfigurationsänderungen passieren alles in diesem Zeitraum. Ohne Checkpoints verwirft ein einziger Ruck den gesamten Lauf.
v1 verlor 27K Schritte durch einen Fehler (lr=0.001 zu aggressiv), weil kein Checkpoint näher als der Startpunkt lag. v2 hat diese Lektion verinnerlicht: Checkpoint-Rhythmus auf alle 100 Schritte reduziert, & ein CUDA-Signal-Handler garantiert einen Checkpoint-Schreibvorgang bei SIGTERM.
Drei Rollen
Ein Checkpoint erfüllt drei Aufgaben gleichzeitig:
1. Wiederherstellungspunkt. Prozess stirbt ab, Maschine startet neu, Kernel-Panic: Fortsetzen vom neuesten step_NNNNNN.bin.
2. Polierter Pivot. Schritt 112.619: Lehrplan ändern ohne erneutes Training. SIGUSR1 erzwingt einen sauberen Checkpoint, Proxy stoppt, neue Caps & Floors werden eingereicht, CUDA setzt unter einer neuen Policy vom gespeicherten Punkt fort.
3. Audit-Gabelung. Zwei Konfigurationen bei denselben Startgewichten vergleichen: Checkpoint kopieren, zwei divergente Zweige vorwärts laufen lassen, beobachten, welcher konvergiert.
Jeder 100. Schritt ergibt ~17 Minuten Training zwischen den Schreibvorgängen bei 6 Schritten/Min. 100 Schritte passen auch zu sample_every: Jeder Checkpoint entspricht einer frischen Sample-Prüfung, & jede Sample-Prüfung entspricht einem wiederherstellbaren Punkt.
Drei Rollen für eine Datei
Fünf Regionen in einer Datei
Das Format
Jede step_NNNNNN.bin packt fünf zusammenhängende Bereiche:
[int32 step] [int32 n_params] [n_params x float32 weights] [n_params x float32 m] [n_params x float32 v]
Region für Region
Header (8 Bytes insgesamt). Eine 32-Bit-Schrittzahl teilt uns mit, wo in der Training dies Snapshot liegt; eine 32-Bit-Parameteranzahl teilt uns mit, wie groß die drei nachfolgenden Arrays jeweils sind.
Weights (n_params x 4 Bytes). Jeder gelernte Parameter, flach. Reihenfolge entspricht dem Parameter-Iterator des Modells: Token- & Position-Embeddings, dann pro-Layer Attention- & MLP-Gewichte, dann der Output-Head.
Adam first moment m (n_params x 4 Bytes). EMA vergangener Gradienten (beta1 = 0.9). Gleiche Form wie Weights. Erforderlich für AdamW-Fortsetzung.
Adam-Zweiter-Moment v (n_params x 4 Bytes). EMA vergangener quadratischer Gradienten (beta2 = 0.999). Gleiche Form wie die Gewichte. Erforderlich für AdamW-Wiederaufnahme.
Gesamtgröße
Gesamtbytes = 8 + 12 x n_params. ANDREA-12M (12,8M Parameter): 154 MB auf Disk (147 MB gerundet). ANDREA-120M (~120M Parameter) FP32: ~1,44 GB. Drei Arrays gleicher Form, hintereinander gestapelt, mit kleinem Header.
Warum m & v speichern
Vanilla Adam verfolgt parameter-spezifische Lernraten über m & v. Löscht sie beim Checkpoint-Schreiben, startet ein fortgesetzter Lauf mit null Impuls & null Varianzschätzung, äquivalent zu Lernrate 0 für einen Schritt dann plötzlichem Anstieg. Verlustspitzen; das Modell kann aus seinem aktuellen Becken fallen. Speichern von m & v macht die Wiederaufnahme bit-identisch (modulo Dataloader-Zufälligkeit) zur nie-gestoppten Baseline.
Größe eines Checkpoints
SIGTERM & SIGUSR1
Warum CUDA Signale behandelt
Das Training läuft als lang lebender Vordergrundprozess. Wenn der Proxy oder Betreiber möchte, dass die GPU stoppt, wird ein Signal an den CUDA-Engine gesendet. Ohne Handler tötet ein Standard-SIGTERM den Prozess sofort: laufende Gradientenberechnung verworfen, neueste Gewichte seit dem letzten Checkpoint verloren. Mit einem Handler schreibt der Engine zuerst einen Checkpoint und beendet dann sauber.
SIGTERM: schreiben & beenden
Gesendet durch einen Stopp-Knopf, ein systemctl stop oder ein kill von einem übergeordneten Proxy. CUDA beendet den aktuellen Schritt, schreibt step_NNNNNN.bin auf die Festplatte und beendet dann. Die Wiederherstellung aus diesem Zustand benötigt nur die neueste .bin: keine Arbeit verloren außer dem partiellen Schritt im Flug.
SIGUSR1: schreiben & fortsetzen
Auf Anfrage vom Betreiber oder Proxy-Skript gesendet. CUDA beendet den aktuellen Schritt, schreibt step_NNNNNN.bin und setzt das Training fort, als wäre nichts passiert. Nützlich für: Auslösen eines Audit-Punkts direkt vor einer Konfigurationsänderung; Erfassen von Gewichten in einem bekannten guten Moment; Ausrichten eines Checkpoints mit einem externen Sample-Qualitäts-Bewertungslauf.
Die Polnische Pivot-Sequenz (Schritt 112,619)
1. Operator sendet SIGUSR1 an CUDA. Checkpoint wird an der nächsten 100-Schritt-Grenze geschrieben (Schritt 112,700).
2. Operator stoppt den Proxy.
3. .samples.json & .state.json werden archiviert (Sample-Log & Bandit-Zustand als historischer Datensatz erhalten).
4. .loss.json bleibt an Ort und Stelle. Kumulierte Trainingshistorie; wird nie archiviert.
5. Proxy startet unter neuen Caps & Floors neu.
6. CUDA setzt von step_112700.bin mit einem frischen Banditen, aber vollständigen Weights, m & v fort.
Der Loss-Verlauf bleibt durch den Pivot hinweg ununterbrochen erhalten. Sample-Log wird sauber zurückgesetzt. Bandit erhält unter der neuen Policy einen frischen Start.
Das Signal auswählen
Kumulative Trainingshistorie
Drei Sidecar-Dateien
Neben jedem Checkpoint pflegt der Proxy drei JSON-Sidecars im Run-Verzeichnis:
- .loss.json -- ein Eintrag pro Schritt, immer. ~200.000 Einträge bis zum Laufende. Kumulative Trainingshistorie.
- .samples.json -- kürzlich generierte Samples für Audit. Reset bei Polish-Pivots.
- .state.json -- Bandit-Arm-Züge, EMA-Belohnungen, Phasen-Zähler. Reset bei Polish-Pivots.
Was wird zurückgesetzt, was bleibt bestehen
Polnische Pivots sind Richtungswechsel, keine Run-Resets. Die Modellgewichte, m, v & Loss-Historie werden alle nahtlos fortgesetzt. Die angesammelten Belohnungen des Banditen werden NICHT fortgesetzt: die neuen Caps & Floors definieren eine andere Policy, & der Bandit muss unter der neuen Policy aus einem sauberen Zustand neu lernen.
Warum .loss.json erhalten bleibt
Die Loss-Historie dient als Audit-Trail des Runs. Jede veröffentlichte Behauptung über ANDREA-120M (Loss-EMA bei Schritt 110K, Polish-Pivot-Wiederherstellung, Konvergenz bei Schritt 112K) lässt sich auf Einträge in dieser Datei zurückführen. Das Archivieren von .loss.json zwischen Phasen würde Leser zwingen, Fragmente zusammenzufügen, um den Run zu rekonstruieren; das append-only & unberührt Halten bewahrt die Provenienz.
Die Zombie-Arm-Lektion
Schritt 112,619 fand einen repo-docstrings-Arm in .state.json mit einem Gewicht von 1.546 aus einem früheren Run. Der Bandit-Zustand war über einen früheren Neustart hinweg erhalten geblieben, aber die Datenquelle war nicht mehr verfügbar, was zu Zombie-Pulls führte, die die Explorationsbuchhaltung verzerrten. Lektion: Der Bandit-Zustand DARF über Neustarts hinweg auf überraschende Weise abweichen. Die Loss-Historie ist die einzige Datei, die für die gesamte Laufzeit des Runs unberührt bleiben muss.
Eine Regel, die alles regiert
Archiviere .samples.json & .state.json frei zwischen den Phasen. Archiviere niemals .loss.json. Die neueste .loss.json ist immer die kanonische Trainingshistorie.
Die Regel anwenden
Was gebaut wurde & warum
Fünf Entscheidungen
1. Cadence: alle 100 Schritte. Granularität des Wiederherstellungspunkts ~17 Minuten. Abgestimmt auf sample_every, sodass jeder Checkpoint einem frischen Sample-Audit entspricht.
2. Format: Header + 3 Arrays. Minimal: 8-Byte-Header zeigt, wie groß jedes nachfolgende Array wird. Kein Metadaten-Bloat. Bit-identische Fortsetzung, wenn m & v gespeichert werden.
3. Signale: SIGTERM & SIGUSR1. Zwei Rollen, zwei Signale. Standard-Systemd-Shutdown erhält einen sauberen Checkpoint via SIGTERM; On-Demand-Audit-Punkte erhalten einen sauberen Checkpoint via SIGUSR1 ohne Stopp.
4. Loss-Kontinuität: nie archiviert. Kumulative Trainingshistorie bleibt über Polish-Pivots, Restarts & Policy-Änderungen hinweg erhalten. Ein Audit-Trail für den gesamten Lauf.
5. Bandit-Zustand: Resets erlaubt. Bandit-Policy lebt unter einer Config zur Zeit. Polish-Pivots resetten; Loss-Historie fährt fort. Zwei unterschiedliche Lebenszeiten teilen sich dasselbe Run-Verzeichnis.
Wozu diese Lektion verbindet
- Aktivität 23 (grow_a_language_model_sample_audit). sample_every-Kadenz passt zur Checkpoint-Kadenz; beide feuern alle 100 Schritte.
- Aktivität 24 (grow_a_language_model_microgpt_to_andrea). v1-Zusammenbruch, v2.5-Patch, v3-Poliervorlage – alle erfordern saubere Checkpoints zum Betrieb.
- Aktivität 10 (grow_a_language_model_adamw). Speichern von m & v im Checkpoint ist entscheidend, da die AdamW-Update-Regel auf beiden angewiesen ist. Fehlen sie, divergiert der Fortsetzungsprozess.
Eine letzte Ingenieurswahrheit
Code überdauert Autoren. Infrastruktur überdauert Baumeister. Ein einfaches Checkpoint-Format überdauert jedes schicke Fortsetzungsschema, das versprach, Optimizer-Zustand zu überspringen. Speichere die Bytes; speichere den Lauf.