Skip to content

exp108: 3B Qwen3 contacts-v1 sweep on CoreWeave GPU (batch priority)#111

Open
timodonnell wants to merge 13 commits into
mainfrom
claude/musing-euclid-fd5ea5
Open

exp108: 3B Qwen3 contacts-v1 sweep on CoreWeave GPU (batch priority)#111
timodonnell wants to merge 13 commits into
mainfrom
claude/musing-euclid-fd5ea5

Conversation

@timodonnell

Copy link
Copy Markdown
Member

First MarinFold GPU/CoreWeave training run — issue #108. A scale-up of Eric's #75 tuning sweep to see whether we beat #75's best eval loss (~2.7).

What this is

Key design decision — batch priority via direct dispatch

#108 requires iris batch priority for all work. --priority batch only sets the driver band; the marin executor submits child jobs without a band (→ interactive), and there's no executor knob for it. So dispatch_train.py submits each training gang itself as a fray.JobRequest(priority=3) — grug-style — while still reusing marin's run_levanter_train_lm + _build_train_lm_config (AdamW/TrainerConfig/mesh/checkpointer). Data is tokenized on the fly from raw S3 parquet (auto_build_caches=True), so there's no separate executor tokenize step.

Files

  • dispatch_train.py — direct batch-priority Fray dispatch (the crux).
  • train_qwen_3b_contacts_v1_sweep.py — sweep entry point.
  • contacts_v1_train_common.py — shared S3/tokenizer/GPU constants + HF export.
  • export_qwen_3b_contacts_v1.py, stage_data_to_coreweave.py.
  • models/pyproject.toml — new gpu extra (marin-core[gpu]).

Status

  • Auth (kubeconfig + object-storage key) verified; corpus staged to CoreWeave S3 (2067 train + 22 val shards, ~13 GB).
  • marinfold-models pinned to 62ba9db (carries the gpu extra).
  • Not yet run. Pre-launch: a single-LR ~50-step smoke run to validate the direct-dispatch path live (cloudpickle across the Fray boundary, cache build, batch band, checkpoint layout). See the README "Batch priority" and "Implementation notes".

Closes #108 is intentionally not set — experiments are closed by humans.

🤖 Generated with Claude Code

timodonnell and others added 11 commits July 6, 2026 17:37
…riority)

First MarinFold GPU/CoreWeave training run (issue #108). Scale-up of Eric's #75
tuning sweep: Qwen3 at #75's 1.5B width with layers doubled 24->48 (~2.9B), LR
sweep {5e-4,1e-3,2e-3} at wd 0.2 / 10% warmup, 16 epochs, batch 128, seq 8192.

- dispatch_train.py: direct grug-style Fray dispatch of each training gang at
  iris batch priority (JobRequest(priority=3)), reusing marin's
  run_levanter_train_lm + _build_train_lm_config with concrete S3 paths and
  on-the-fly tokenize (auto_build_caches). The executor can't set a priority
  band, which #108 requires for all work.
- train_qwen_3b_contacts_v1_sweep.py: one batch-priority job per LR.
- contacts_v1_train_common.py: shared S3/tokenizer/GPU constants + HF export.
- stage_data_to_coreweave.py: GCS-mirror -> CoreWeave S3 corpus staging (done).
- models/: add a `gpu` extra (marin-core[gpu]) mirroring `tpu`.

Everything writes under a single s3://marin-us-east-02a/MarinFold/ prefix.
Pre-launch: pin marinfold-models rev; smoke run to validate the direct-dispatch
path live (cloudpickle, cache build, batch band, checkpoint layout).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
62ba9db carries the models/ `gpu` extra the CoreWeave run needs. Pins the
git source so the iris worker resolves marinfold-models[gpu] reproducibly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
marin 0.2.38 refactored its execution framework — the old executor surface
(ExecutorStep/this_output_path/executor_main/versioned/...) that the vendored
marinfold_models imported is gone, and marin.experiment.train.train_lm is now
the shipped assembler. exp85's committed uv.lock hid this by freezing old marin;
a fresh sync today breaks. (Chosen fix: refresh the shared harness, not a
one-off.)

- models/marinfold_models/defaults.py: full rewrite. Dropped the dead
  executor-based default_train/default_tokenize/_build_train_lm_config. New
  StepContext-free `build_train_lm_on_pod_config` reproduces train_lm's
  TrainerConfig/mesh/checkpointer/mp assembly but takes a concrete output_path
  and a levanter LmDataConfig directly — so the caller can direct-dispatch it at
  batch priority. __init__ exports it + SimpleTrainConfig + MARIN_PRECISION.
- exp108/dispatch_train.py: use the new builder (+ build the AdamW cosine
  optimizer in the driver); keep the JobRequest(priority=3) dispatch + the
  tokenize-on-the-fly S3 data config.
- exp108/pyproject.toml: fix stale/conflicting pins surfaced by uv sync —
  torch 2.10->2.11 (match marin-core[cpu]), python >=3.12 (marin dev dropped
  3.11), drop huggingface-hub>=1.5 (conflicts with marin's transformers),
  Linux-only environments.
- exp108/export: WIP stub (marin's HF-export API also moved; not needed until a
  run produces a checkpoint).

Validated live in the venv: build_train_lm_on_pod_config assembles a
TrainLmOnPodConfig against 0.2.38; all exp108 modules import clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bumps the marinfold-models git rev to 1f5653f (the modern-marin refresh) and
commits uv.lock to FREEZE the resolution at marin 0.2.38.dev202607060946 — the
root cause of this whole detour was the unpinned `<0.3` range silently drifting
to a marin build that broke the vendored code. The lock (like exp67/exp85's)
stops that. Verified: `uv sync` from the lock fetches marinfold-models@1f5653f
from git and the TrainLmOnPodConfig builds clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Smoke run surfaced two launch issues:
- The training gangs are CHILDREN of the driver job; with wait=False the driver
  exited immediately and iris finalized (killed) the gang. Fix: submit all gangs,
  then block on each (they run concurrently, driver stays alive for the run).
- The workstation launcher needs marin-iris[controller] to reach the CoreWeave
  k8s controller (CloudK8sService); added it + re-locked. (Also needs kubectl on
  PATH for the controller tunnel — installed out-of-band, not a repo change.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Left a wait={WAIT} in the summary print after removing the WAIT knob; the driver
crashed at import before dispatching. Now validated by running main() locally
with a stubbed dispatch (full driver path, no cluster submit).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Throughput investigation from the smoke run (~52k tok/s, ~15% MFU on 8xH100):
- Root cause of low attention throughput: transformer_engine isn't in the
  --extra gpu env, so levanter's default GPU NVTE attention silently fell back
  to the VANILLA O(seq^2) kernel — brutal at seq 8192. Added an EXP108_ATTN knob
  (default jax_flash = levanter's pallas flash, no TE dep). NB: measured no
  net speedup from flash alone — attention is only ~15% of FLOPs here; the
  bottleneck is systemic (FSDP collectives / gradient-checkpointing recompute,
  likely worsened by the CUDA fabric-memory fallback).
- dispatch_train now forwards XLA_FLAGS/NCCL_/JAX_ from the driver to the gang
  (like grug's dispatch) — the gang is a separate pod and wasn't inheriting
  launcher-set flags, so throughput was untunable via -e XLA_FLAGS. This is a
  correctness fix + the hook for further tuning.
- EXP108_RUN_SUFFIX isolates probe runs' S3 output paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Injects a ProfilerConfig (window past compile) into the trainer when
EXP108_PROFILE=1. Works (captures a perfetto trace), but note levanter uploads
only jaxpr/HLO to W&B, not the profiler dir — retrieving the timing trace off
the ephemeral pod needs extra plumbing (log_dir is a local PosixPath).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Probe confirmed grad-checkpointing-off OOMs (692 GiB activations for 48 layers
at seq 8192, even at 8 seq/GPU) — so it stays ON for the real run. Knob kept for
the record / future selective-checkpointing work.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Captures everything learned taking the sweep live on cw-rno2a:
- Workstation prereqs (kubectl, marin-iris[controller], wandb-from-netrc).
- Operational findings: driver must wait on gangs; node-count ceiling ~4
  (8-node JAX coordination bootstrap fails; likely NCCL env); launch runs as
  separate staggered drivers (3-from-one-driver collides); benign FABRIC warns.
- Throughput/scaling: ~20 s/step 1-node (~15% MFU), near-linear to ~5 s/step at
  4 nodes (~4-day full run); gradient_checkpointing mandatory (off = 692 GiB OOM);
  attention backend irrelevant.
- Results: smoke run validated the full path; real 3-LR sweep launched at 4
  nodes each (v2 runs), all three training. Target: beat #75's 2.7566 eval loss.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…e agents

Durable, cluster-general lessons from exp108's first MarinFold GPU run: the
kubectl + marin-iris[controller] launcher prereqs; S3 (not GCS) storage with
virtual-hosted addressing; batch priority not propagating to executor children
(dispatch directly); drivers must wait on child gangs; the ~4-node multi-node
ceiling + separate-staggered-drivers pattern; benign FABRIC warnings + the
missing-Transformer-Engine attention fallback; and always pin + uv.lock marin.
Recipe specifics stay in the exp108 README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
timodonnell and others added 2 commits July 7, 2026 21:25
… diverged

The v2 sweep (depth-doubled 24->48 layers) went unstable at all three LRs —
diff vs #75's stable 1.5B run showed the ONLY change was num_layers (48 vs 24);
everything else (LR/wd/warmup/init/clip/z_loss) was identical. LR transfers under
width scaling, not depth, so 48 layers lowered the stable-LR ceiling. Fix: widen
#75's 24-layer model instead (hidden 2048->2816, ff 8192->11264, GQA 4:1) to
~2.78B, and turn on Qwen3 QK-norm (was off) for deep-attention stability. #75's
recipe/LRs should now transfer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…e fix

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

exp: train a 3B qwen model contacts-v1 on coreweave GPUs

1 participant