Skip to content

fix(harvest): per-worker local_batch_size; GPU assert + mem-fraction for 8B restores#949

Open
ocg-goodfire wants to merge 1 commit into
feature/jaxfrom
fix/harvest-local-batch
Open

fix(harvest): per-worker local_batch_size; GPU assert + mem-fraction for 8B restores#949
ocg-goodfire wants to merge 1 commit into
feature/jaxfrom
fix/harvest-local-batch

Conversation

@ocg-goodfire

Copy link
Copy Markdown
Collaborator

What

Three fixes from the first attempt to harvest an 8B JAX run (p-289e3178, L18-MLP 200k) on the sharded SLURM path:

  1. HarvestConfig.batch_sizelocal_batch_size (per-worker). The sharded launcher divided the global batch_size across the array (ShardServer process_count=n_gpus), so any production config quietly ran every GPU at a local batch of 1 — e.g. batch_size: 128 on 128 GPUs. Workers now always forward local_batch_size sequences per batch and the schedule's global batch derives as local_batch_size × world_size; total sequences = n_batches × local_batch_size × world_size. No back-compat alias — old configs fail loudly on the removed field.

  2. Fail-fast GPU assert for sharded workers. A venv without CUDA jaxlib fell back to CPU silently; a 64-GPU array burned its allocation at ~100× slowdown with nothing in the logs but a jax warning. Sharded workers (--rank given) now assert jax.default_backend() == "gpu". Single-process CPU spot-checks stay allowed.

  3. XLA_PYTHON_CLIENT_MEM_FRACTION=0.95 default in the worker. open_jax_run restores the full TrainState (fp32 masters + Adam + persistent-PGD sources — 60GB checkpoint for the L18 runs) plus the frozen 8B target onto one device; restore staging pushes the peak past the default 0.75 pool (RESOURCE_EXHAUSTED at ~135GB on a B200). Set before backend init, setdefault so callers can override.

A structural follow-up worth considering separately: open_jax_run could partially restore only components + ci_fn (orbax 0.12 partial_restore) — the optimizer states and adversary sources it materializes are dead weight for every consumer, and dropping them would halve harvest GPU pressure. Kept out of this PR to stay minimal.

Testing

  • basedpyright param_decomp_lab/harvest/ clean; harvest test suite (62) passes.
  • 1-GPU probe of the exact worker command on p-289e3178 confirmed the OOM and the 0.95 fix; overnight 128-GPU harvests of p-289e3178/p-fc8b6c7a run from this branch (results by morning).

🤖 Generated with Claude Code

https://claude.ai/code/session_01PVGsKRCYkqeeVhizuPnVuD

…for 8B restores

Three fixes from the first attempt to harvest an 8B JAX run (p-289e3178) at scale:

- HarvestConfig.batch_size (global) -> local_batch_size (per-worker): the sharded
  launcher divided the global batch over workers, so production configs quietly ran
  every GPU at batch 1. Workers now always forward local_batch_size sequences and
  the schedule's global batch derives as local_batch_size * world_size.
- run_worker asserts backend == gpu for sharded runs: a venv without CUDA jaxlib
  silently fell back to a ~100x-slower whole-array CPU harvest.
- XLA_PYTHON_CLIENT_MEM_FRACTION defaults to 0.95 in the worker: restoring a full
  8B-run TrainState (60GB checkpoint + restore staging + frozen target) exceeds
  the default 0.75 pool on one device (RESOURCE_EXHAUSTED at ~135GB).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PVGsKRCYkqeeVhizuPnVuD
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant