You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(multipool): clean up orphaned .snapshot_scratch partials
Scratch partials under runs/<id>/.snapshot_scratch/step_<S>/ were only ever
removed by consolidate_step (after it assembles a step's checkpoint). When the
async consolidation job stalls, is preempted, or is never submitted, nothing
removes them and they accumulate — in practice runs that never consolidated a
single step each held multiple TB of dead partials (one sweep reclaimed ~6.3 TB).
Two small, complementary cleanups, both safe because resume reads only the
consolidated training_<S>.pth, never raw partials:
* _prune_scratch_through(scratch_dir, S) in consolidate_step (off the loop):
drops every step_<=S>, not just S. The final save is the highest step, so its
consolidation sweeps the whole run — a completed run ends with zero scratch,
even if some intermediate consolidations were skipped.
* prune_old_scratch(scratch_dir, keep_last_n=2) in snapshot() (rank 0, off the
collective): keeps only the newest KEEP_LAST_N_SCRATCH snapshots — the backstop
for when consolidation never runs at all, so a stuck run can't grow without
bound (residue at most keep_last_n step dirs).
CPU-only unit tests for both helpers; three_pool/CLAUDE.md updated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: param_decomp_lab/three_pool/CLAUDE.md
+23-3Lines changed: 23 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -19,7 +19,7 @@ layer's output independently — is a separate, stable concept the chunkwise poo
19
19
|`config.py`|`ThreePoolTopology` (`ci` / `ppgd` / `chunkwise``PoolSpec`s of per-rank batch + `sites_per_chunk`) + `resolve(ordered_sites, batch_size) -> ResolvedLayout`. Authors per-rank batch, NOT rank ids; the resolver derives ranks/chunks/world_size in canonical order. Parse-time validation = cross-divisibility of the three per-rank batches |
20
20
|`layout.py`|`World` topology + the runtime `Chunk` (`.ranks` / `.sites`); `build_world` constructs every process group (threading `pg_timeout` into each); `BatchEdge` — symmetric per-edge batch-slice geometry (CI↔chunk, CI↔PPGD) answering routing for both fan directions |
21
21
|`checkpoint.py`| offline state_dict assembly from on-disk partials (`assemble_model_state_dict_from_partials`) + the leader key-partition helpers (`owned_model_state_keys` / `ci_fn_state_keys`) |
22
-
|`consolidate.py`|`consolidate_step` — async, off-train-loop, **streaming** assembly of `model_<step>.pth` + `training_<step>.pth` from a step's small (parameter-shaped) scratch partials; prunes old `training_*.pth` + `ppgd_*/`; deletes the scratch dir. The data-shaped PPGD sources are NOT here — each adversary rank writes its own `ppgd_<step>/rank_<r>.pth` at snapshot time, in parallel (see "Checkpoint save" below). `load_ppgd_shard` reads a rank's shard on resume; `unconsolidated_steps` lists recoverable steps |
22
+
|`consolidate.py`|`consolidate_step` — async, off-train-loop, **streaming** assembly of `model_<step>.pth` + `training_<step>.pth` from a step's small (parameter-shaped) scratch partials; prunes old `training_*.pth` + `ppgd_*/`; drops scratch at/below the step (`_prune_scratch_through`). The data-shaped PPGD sources are NOT here — each adversary rank writes its own `ppgd_<step>/rank_<r>.pth` at snapshot time, in parallel (see "Checkpoint save" below). `load_ppgd_shard` reads a rank's shard on resume; `unconsolidated_steps` lists recoverable steps. `prune_old_scratch` (called on-loop from `snapshot()`) bounds scratch when consolidation stalls/never runs|
23
23
|`consolidate_cli.py`|`python -m …consolidate_cli <run> [--step N]` — manual CPU-only recovery for a failed/preempted async consolidation (separate module to avoid an import cycle with `experiments.lm.run`) |
24
24
|`role.py`|`PoolRole = CIRole \| ChunkRole \| PPGDRole` — this rank's pool role; per-pool fields are union variants, not optional attrs |
25
25
|`context.py`|`PoolContext = CIContext \| ChunkContext \| PPGDContext` — `world` + `role` + this pool's portals; the trainer matches on it to dispatch step fns |
@@ -186,7 +186,9 @@ the assembled CPU model, never the full partial set) → assembles the full
0 commit comments