This repository was archived by the owner on Jul 17, 2026. It is now read-only.
Commit 331b168
* three_pool: move checkpoint consolidation off the train loop (async)
The 3-pool save was fully synchronous: rank 0 serially read ~100 GB of
per-rank partials to assemble the canonical ThreePoolTrainingState while
all other ranks waited at a rejoining barrier. At XL that read overran the
NCCL watchdog (killed run 34446) and forced a 30-min PG timeout; over a
200k-step run it stalled the loop for hours.
New flow:
- snapshot() (on the train loop) writes a SELF-CONTAINED partial per rank
(owned model params via the leader key-partition + optimizer state + PPGD
sources) plus a rank-0 meta.pth, with one pre-write and one post-write
barrier. No rank-0 read, no live-NCCL model gather, no model assembly.
- consolidate_step() (new three_pool/consolidate.py, runs in the async
job, off the loop) reads all partials, assembles model_<step>.pth +
training_<step>.pth, prunes training_*.pth to the last 3 (all model_*.pth
kept), deletes the scratch dir. Idempotent.
- checkpoint.py: gather_full_state_dict_to_rank0 (NCCL) replaced by
assemble_model_state_dict_from_partials (file-only) + leader key-partition
helpers (owned_model_state_keys / ci_fn_state_keys).
- ThreePoolRunSink.checkpoint -> checkpoint_written(step, final); the 3-pool
sink now only fires the on_save hook.
- submit_slurm_async_slow_eval -> submit_slurm_async_consolidate_and_eval:
always submitted for 3-pool (consolidation is mandatory even with no slow
metrics); async_eval consolidates first (rank 0 + barrier), then evals.
- Resume reads the latest CONSOLIDATED training_<step>.pth; if a run dies
before consolidation, resume from the prior consolidated step (at most one
save-interval lag; unconsolidated partials remain on disk).
- _DEFAULT_PG_TIMEOUT 30min -> 10min: the longest on-loop collective gap is
now the fast-eval pass + a partial-write barrier, not the rank-0 read.
Validated on an 8-GPU 3-block topology (job 34739/34740):
- save snapshot wall time ~450ms/save (was a multi-minute rank-0 read)
- consolidation produces valid model/training files; assembly is
byte-equivalent to the live ComponentModel state_dict
- resume from a consolidated checkpoint continues training
- prune keeps all model_*.pth, trims training_*.pth to last 3
- run survives a tight 120s PG timeout across 5 saves; a 30s rank-0 sleep
injected into consolidation runs off-loop without touching the train PG
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* three_pool: fix async-consolidation glue — don't resolve a checkpoint pre-consolidation
The live train->child chain failed: async_eval.main opened with
SavedLMRun.from_path(run), which eagerly resolves a model_<step>.pth. For a
3-pool save that file doesn't exist yet — this job assembles it — so every
child consolidate job crashed with "No files found with prefix model" before
ever calling consolidate_step.
Read the config straight from run_meta.yaml instead, consolidate, and only
resolve the checkpoint afterwards (for the eval pass). Also add a
PD_ASYNC_EVAL_DP override so the consolidate+eval child's GPU count isn't a
hardcoded 8 (lets a small-topology smoke fit train + child within one node,
and lets a cheap eval not match train width in production).
Found by the live end-to-end smoke (6-GPU train firing real 2-GPU child
jobs) that the prior validation had stubbed out via PD_3POOL_SKIP_ASYNC_ONSAVE.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* three_pool: consolidate before CUDA/NCCL init (the child job hung otherwise)
The fixed glue got the child past the checkpoint-resolution crash, but it then
hung in assemble_model_state_dict_from_partials: building the full
ComponentModel (incl. the transformer CI fn) AFTER get_device()/init_distributed
makes that construction land on a contended GPU and stall (the same assembly is
2.6s on a clean CPU process).
Move consolidation to a CPU-only prelude that runs BEFORE any CUDA/NCCL init:
rank 0 (read from torchrun's RANK env, since the PG isn't up yet) assembles on
CPU; the other ranks poll the shared FS for training_<step>.pth, then everyone
inits distributed for the eval pass. No process group is needed for the wait.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* three_pool: Option C config fork — standalone ThreePoolLMExperimentConfig + pd-lm-3pool
Splits the 3-pool path into its own composition root + config types, baking the
3-pool's constraints into the types so misconfigs fail at YAML parse instead of
minutes into a multi-node launch.
- ThreePoolConstrainedPDConfig (subclass of core PDConfig): frozen Literal scalars
(sampling/n_mask_samples/use_delta_component/identity_decomposition_targets) + a
typed ThreePoolLosses(faith, imp, stoch, ppgd) struct replacing the generic
loss_metrics list. Derives loss_metrics from the struct (excluded from dump).
- ThreePoolRuntimeConfig (subclass of core RuntimeConfig) carries topology, so nothing
enters core's RuntimeConfig.
- ThreePoolLMExperimentConfig: standalone sibling; LMExperimentConfig drops three_pool.
- pd-lm-3pool entry + three_pool_run.py composition root (fresh/resume/--dp submit);
run.py back to single-pool only. Shared pure builders imported from run.py.
- ThreePoolTrainer reads pd.losses.* directly; deleted _validate_pd_config_for_three_pool
+ the by_type/isinstance dance. Cross-field checks (batch divisibility, rank-0) move to
a load-time model_validator; site coverage stays in _build_runtime.
- SavedThreePoolLMRun reload sibling; init_pd_run / _build_eval_loop relaxed to structural
protocols.
- Resume provenance now lives on the config (resume_provenance field) → flows to
run_meta.yaml + wandb.config; dropped the write-only FS side-file.
- Migrated the two 3-pool YAMLs; parse-rejection + roundtrip + provenance tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* three_pool: init distributed before consolidation; CPU-pin assembly; file-poll wait
Building target_model requires the distributed state to be initialized
(ensure_cached_and_call asserts via get_distributed_state), so consolidation
can't fully precede init_distributed. Reorder: init_distributed + build_target
first, then consolidate.
To keep the multi-second CPU read+assemble off any GPU collective:
- non-rank-0 ranks WAIT by polling the shared FS for training_<step>.pth (which
consolidate_step writes last), not on an NCCL barrier;
- rank-0 assembly runs under `torch.device("cpu")` so the full ComponentModel
buffer (incl. transformer CI fn) is pinned to CPU rather than landing on the
selected, shared GPU (the original hang).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* three_pool: fix consolidation hang root cause (unfrozen target) + fail-fast + rerun CLI
Root cause of the hung child consolidate jobs: assemble_model_state_dict_from_partials
builds a ComponentModel from the target returned by build_target, which only
.eval()s it — its params still have requires_grad=True. ComponentModel asserts
the target is frozen, so rank 0 crashed on that assertion. In the multi-rank
child this surfaced as a HANG: rank 0 died mid-consolidation while the other
rank sat in the wait, holding both GPUs until the timeout.
Fixes:
- Root cause: freeze the target (eval + requires_grad_(False)) inside the
assembly, before constructing the ComponentModel buffer.
- Fail-fast, never hang: rank 0 writes a .consolidate_failed_<step> sentinel and
re-raises on any consolidation error; the waiting ranks poll for the success
file OR the sentinel and bail out (raising) on either the sentinel or a bounded
timeout — so a failed child errors and releases its GPUs instead of wedging.
- Partials persist on failure (already true: consolidate_step rmtrees scratch
only after a successful write) + a recovery CLI:
python -m param_decomp_lab.three_pool.consolidate_cli <run> [--step N]
consolidates every unconsolidated step (partials present, no training_<step>.pth),
making "it failed, just rerun it" a one-liner. CLI lives in its own module to
avoid an import cycle with experiments.lm.run.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test: 4-GPU single-block 3-pool config for live e2e validation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* three_pool: make prune race-tolerant + clean stale scratch on already-consolidated
Two concurrent child consolidation jobs prune the same old training_<step>.pth;
the second crashed with FileNotFoundError (after already writing its checkpoint),
marking the job FAILED and leaving its scratch behind. Use unlink(missing_ok=True)
— a concurrent pruner removing the file first is benign. Also clean any leftover
scratch when consolidate_step early-returns on an already-existing training file,
so a step that died in prune doesn't keep looking unconsolidated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test: 4-GPU 2-save config (peak 8 GPU) for live e2e re-validation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test: resume YAML from live-produced p-livee2e05 checkpoint
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* three_pool: document consolidation reliability (fail-fast, rerun CLI) + drop throwaway resume YAMLs
CLAUDE.md: add the async-job reliability contract (CPU-only post-init assembly,
target-freeze, rank-0-assembles / others-file-wait-fail-fast, partials-persist +
recovery CLI, concurrency-safe prune) and the consolidate_cli.py table entry.
Remove two resume pointer YAMLs that referenced now-deleted validation runs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* three_pool: migrate #540's validation YAMLs to the new ThreePoolLMExperimentConfig shape
#540's four resumption-validation configs were authored in the pre-fork format
(top-level three_pool, flat loss_metrics). The only 3-pool entry point is now
pd-lm-3pool, so migrate them: loss_metrics -> pd.losses struct, three_pool ->
runtime.topology, drop the frozen-Literal pd fields. All parse + round-trip.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* xl: 200k production config in the new ThreePoolLMExperimentConfig shape
The config the human will launch for the ~5-day run. Recreated from the b48
3-pool production config: steps 200000, PPGD optimizer lr warmup_pct 0.05;
everything else identical. Parses + round-trips under pd-lm-3pool.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(3pool): drop duplicate topology key when validating runtime_config on resume
Integration seam between #540 and #541: the consolidated training_<step>.pth
stores runtime_config as a ThreePoolRuntimeConfig dump (base scalars + topology),
but from_snapshot validated it as base RuntimeConfig -> pydantic extra_forbidden
on `topology`. Topology is already carried by three_pool_config (identical to the
dumped topology), so drop the duplicate key before validating the base scalars.
Caught by the resume gate (#540's consolidated checkpoints are only now read by
#541's from_snapshot path).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 0b40f17 commit 331b168
27 files changed
Lines changed: 3201 additions & 1271 deletions
File tree
- param_decomp_lab
- experiments
- lm
- _resumption_validation
- _xl_production
- resumption
- tests
- three_pool
- param_decomp
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
155 | 155 | | |
156 | 156 | | |
157 | 157 | | |
158 | | - | |
| 158 | + | |
| 159 | + | |
159 | 160 | | |
160 | 161 | | |
161 | 162 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
| 20 | + | |
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
55 | | - | |
56 | | - | |
57 | | - | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
58 | 61 | | |
59 | 62 | | |
60 | 63 | | |
61 | 64 | | |
62 | | - | |
| 65 | + | |
63 | 66 | | |
64 | 67 | | |
65 | 68 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
| 15 | + | |
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | | - | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
20 | 22 | | |
21 | 23 | | |
22 | 24 | | |
23 | 25 | | |
24 | 26 | | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
25 | 51 | | |
26 | 52 | | |
27 | 53 | | |
| |||
Lines changed: 149 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
Lines changed: 141 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
0 commit comments