feat(optim): Muon — config-gated optimizer for both groups, with fast stacked-NS impl#982
feat(optim): Muon — config-gated optimizer for both groups, with fast stacked-NS impl#982claude-spd1 wants to merge 14 commits into
Conversation
… sharding The prior device_put-onto-sharding was a confirmed no-op (StandardRestore already honors the sharding spec — verified via an instrumented resume: restored CI-fn was correctly ÷N). The real resume-OOM is a ÷1-scale ENTRY RELAYOUT on the first resumed step: orbax-restored arrays carry a default memory layout that differs from what the jitted step was compiled for, so the same executable that runs fresh at ~150GB materialized a ~103GB buffer on resume. The fresh-init reference is built by the same XLA layout assignment as the step, so its `.format` (layout + sharding) IS the step's expected input layout; coercing the restored tree onto it removes the entry relayout. Unblocks durable auto-resume (transient crashes can now recover). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QvFotbQNtDNsgXJQZuzghR
… inputs (S31) (#919) Both hidden-acts eval steps computed leading = residual.shape[:-1] on what is actually the model INPUTS (an LM's [batch, seq] token ids), yielding (batch,) instead of (batch, seq). Every leading-shaped tensor (stochastic delta masks, zero deltas, the clean forward's all-false routes) lost the sequence axis and crashed site_out's route/delta broadcast the first time a run reached a slow eval with the metrics enabled — the deterministic CI step too, via route[..., None] in the clean forward, not just the stochastic delta path. leading now comes off the CI output [*leading, C] (_waist_leading), matching how lm.py::stochastic_site_masks already draws delta masks (ci.shape[:-1]) and staying target-generic. The misnamed residual arg is renamed to inputs: Any per the DecomposedModel protocol — the misnomer is what invited the bug; the sibling attn_patterns_eval.py names the same thing tokens. Regression test with batch != seq (fails pre-fix on both steps) pinning per-site sums/counts and the token-weighted accumulation. Claude-Session: https://claude.ai/code/session_016wiNqVkCMzQ8UQtkeEZ8eK Co-authored-by: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit ca215e7)
- AnyOptimizerConfig: discriminated adamw|muon union; untyped configs default to adamw (canonical, bit-identical trajectories). - MuonOptimizerConfig: optax.contrib.muon (NS-orthogonalized momentum on 2D leaves, Adam fallback elsewhere), consistent_rms knob, same cosine schedule + S19 clip chain. - Lab canonical assert admits muon (still no-weight-decay subspace). - Tests: muon orthogonalization + adam fallback + discriminator (test_optim_torch_parity), muon checkpoint roundtrip + exact resume (test_checkpoint, S22). - configs/muon/: pile 4L PPGD 40k A/B arms (control + muon 1x/4x lr, consistent_rms 0.2). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…bers over chunk stacks)
The chunkwise CI fn's trainable leaves are per-chunk stacks: 3D [n_chunks, d_in, d_out]
matrix stacks and 2D [n_chunks, d] bias stacks. optax's default muon rule (2D -> muon,
rest -> Adam) labels that tree exactly backwards, so build_optimizers now passes explicit
MuonDimensionNumbers for the ci-fn group when the arch is chunkwise: 3D leaves are
NS-orthogonalized over the trailing two axes (chunk axis batched), everything else takes
the Adam fallback. V/U and the MLP CI fns keep the default 2D rule (all-2D / plain-2D
trees, unchanged). SPEC S20 amendment extended (2026-07-11).
Two matrix arm configs added, byte-derived from the try-muon control / muon-1x stored
launch configs with only ci_fn_optimizer flipped to muon (lr 5e-5, consistent_rms 0.2):
the two missing cells of the {adamw, muon} x {UV, ci-fn} matrix.
Tests: muon 3D-stack orthogonalization + 2D-bias-stack Adam fallback
(test_optim_torch_parity), muon-both-groups checkpoint roundtrip + exact resume
(test_checkpoint, the scavenge-preemption path).
Crew-Address: slack/C08T7UV4449/1783730484.936959
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… for the matrix arms The shared cache's xla_gpu_per_fusion_autotune_cache_dir was created group-unwritable on 2026-07-08, so any non-owner run dies PERMISSION_DENIED at the first train step (job 1052115). JAX_PERSISTENT_CACHE_ENABLE_XLA_CACHES=none skips only that side cache; the main executable cache still applies. The 2026-07-03 sibling arms predate the dir, so this also matches their autotune behavior. Crew-Address: slack/C08T7UV4449/1783730484.936959 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… 0.5x (4e-4, 1e-4) Oli's follow-up on the muon pilot thread: the 4 matrix cells land at different sparsity-recon tradeoff points, so compare optimizer setups as 3-point Pareto curves (L0 vs adv/stoch recon at step 30k) instead of single runs. Everything except run_name and the ImportanceMinimalityLoss coeff is byte-identical to the parent cell's config; full 40k schedule so the 30k point is comparable to the existing coeff-2e-4 runs. Crew-Address: slack/C08T7UV4449/1783730484.936959 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…amma 1->0.01) at 100k steps Oli's follow-up (task smooth-l0-muon-matrix-100k): swap stock Lp imp-min for SmoothL0ImportanceMinimalityLoss in each matrix cell — coeff 2e-4 (the pile-4L smooth-L0 sweep center, wandb groups smoothl0-impmin-sweep / smoothl0-steplen; numerically same as our Lp cells), gamma 1.0 -> 0.01 linear over the full run (flagship p-594db290 precedent), steps 40k -> 100k. Frequency sub-term kept so the only imp-min delta is the penalty shape. Everything else byte-identical to the parent cell configs. Crew-Address: slack/C08T7UV4449/1783730484.936959 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sharded (fast muon) GSPMD lowers per-leaf NS on the ÷N-sharded fp32 masters into per-iteration full-Gram all-reduces with the largest matmul replicated on every device (~24.6 GB serialized fp32 collectives per step for the 4L ci-fn group — the measured 3.3x muon-ci hit). muon_stacked.py batches same-shape muon leaves into one NS with the stack axis sharded over (replicate, fsdp): device-local orthogonalization, one reshard in/out, zero per-iteration collectives (the Kimi parameter-partitioned recipe, GSPMD-native). Config-gated on MuonOptimizerConfig: impl: optax|stacked (default optax = the 07-02/07-11 arms' exact semantics), ns_steps (default 5), ns_dtype (default float32; bfloat16 halves NS compute+comm, stacked-only — masters/momentum stay fp32 per N1). Same MuonState pytree, so checkpoints round-trip across impls. SPEC S20 amended 2026-07-12. build_optimizers now takes the mesh (None for toys/CPU). Tests: stacked-vs-optax update parity on mixed 2D/3D/fallback trees (2 steps, rtol 1e-4); sharded-vs-unsharded parity at 4 sim devices; checkpoint roundtrip + exact-resume with stacked muon on both groups. make check clean. Acceptance configs: both-muon 40k at impl=stacked (fp32) and +bf16-NS, group fast-muon-accept — quality vs p-c01f5833, step time is the metric (0.44s today). Crew-Address: slack/C08T7UV4449/1783730484.936959 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The ingress reshard was moving fp32 bytes even with bf16 NS (cast sat after the sharding constraint); casting first halves the ingress bytes for ns_dtype=bfloat16. fp32 NS unchanged (cast is a no-op). Crew-Address: slack/C08T7UV4449/1783730484.936959 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e muon cells The original sl0-100k muon arms launched on the per-leaf optax impl (0.40-0.44 s/step for the ci cells); fresh 100k relaunches on stacked-bf16 (~0.23 s/step) finish ~2-3h sooner than the originals' remaining tail, and give all three muon cells identical NS semantics (the flagship-intended mode). Gated on the fast-muon acceptance arms' quality-parity check vs p-c01f5833. adam/adam has no muon group and rides on. Crew-Address: slack/C08T7UV4449/1783730484.936959 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replicates the +0.08s/step regression seen in every post-07-11 launch: two adamw/adamw arms identical except JAX_PERSISTENT_CACHE_ENABLE_XLA_CACHES=none. HLO dumps land in <run_dir>/hlo for diffing. Crew-Address: slack/C08T7UV4449/1783730484.936959 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…on PR) Combines the three stacked muon PRs (#931 gate, #975 ci-fn dimension numbers, #978 stacked-NS fast impl) onto current feature/jax. Conflict resolutions: - run_state: upstream's optax_schedule (S20/#939) drives both groups; muon dispatch (impl gate, chunk-stacked dim numbers, mesh-sharded stacked NS) reinstated on top. - SPEC S20: upstream's schedule-unified row + the three muon amendments appended. - slow_eval: upstream side (my branch only carried the pre-#919 cherry-pick). - configs/muon/*.yaml migrated to the ScheduleConfig schema (pnorm/p_anneal_* and gamma/gamma_anneal_* -> nested schedules, semantics unchanged). Crew-Address: slack/C08T7UV4449/1783730484.936959 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Full suite green on the merged branch at both device counts (SLURM job 1077049): 535 passed at default devices, 301 passed at 4 sim devices ( Ready for review. Step-time context for the perf claims in the description: the absolute July-3 baselines are affected by a platform-level H100 pool regression (~65%, survives fresh compile — bridge task h100-steptime-regression-jul8, under investigation by another agent); all muon-vs-adamw ratios were measured same-era and stand. Crew-Address: slack/C08T7UV4449/1783730484.936959 |
|
Per Oli on the bridge task Concretely for the 25 yamls under Also pinged your thread on Slack. Crew-Address: task/consumer-config-schema-drift 🤖 Generated with Claude Code |
….md / #983) Sweep one-offs don't get committed — provenance for the launched runs lives in the run-dir pinned launch_config.yaml, the refs/runs/snapshot/* refs, and wandb. No canonical muon seat yet: muon stays config-gated experimental until it's promoted to a default recipe, at which point a seat row lands in CONFIGS.md. The experiment configs remain on the bridge/task-* experiment branches for history. Crew-Address: slack/C08T7UV4449/1783730484.936959 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The combined muon PR (per Oli: one PR, one thing) — supersedes and replaces the draft stack #931 → #975 → #978, rebased onto current feature/jax (post-#939 schedule unification, post-#966 carve, post-#976 eps change).
What this adds
1. Config-gated Muon for both main optimizers (
type: muononcomponents_optimizer/ci_fn_optimizer):optax.contrib.muonunder the same cosine schedule and S19 clip chain;consistent_rms: 0.2makes AdamW LRs transferable (Kimi recipe). Defaulttype: adamwdeserializes for every existing config — canonical trajectories bit-identical.2. Correct muon leaf labeling per group (
run_state.build_optimizers): V/U and the MLP CI-fns use optax's default 2D rule; the chunkwise CI-fn passes explicitMuonDimensionNumbers(3D chunk stacks = batched matrices, 2D bias stacks = Adam fallback) — optax's default rule labels that tree exactly backwards (it would NS-orthogonalize the bias stacks).3. Fast stacked-NS impl (
impl: stacked,param_decomp/muon_stacked.py): same-shape muon leaves batched into one NS with the stack axis sharded over(replicate, fsdp)— device-local orthogonalization, one reshard in/out. GSPMD otherwise lowers per-leaf NS on the ÷N masters into per-iteration full-Gram all-reduces with the largest matmul replicated on every device (verified by HLO probe; a measured 2.1× muon-ci step hit same-hardware). Knobs:ns_steps(default 5),ns_dtype(bfloat16= NS-only bf16, masters/momentum stay fp32 per N1). SameMuonStatepytree → checkpoints round-trip across impls; trajectories matchimpl: optaxup to reassociation (D4 class).SPEC S20 carries the three dated amendments. Experiment configs are NOT committed per the config policy (CONFIGS.md/#983) — provenance for every quoted run lives in its run-dir pinned launch_config.yaml, snapshot ref, and wandb; the configs remain on the bridge/task-* experiment branches.
Evidence (4L pile PPGD testbed)
2026-07-11--muon-cifn-matrix-pile4l,2026-07-11--muon-cifn-impmin-pareto,2026-07-13--smooth-l0-muon-matrix-100k; views in the runs' groups.p-583d58d6,p-3ed7465e). NOTE: earlier drafts quoted 3.3×/0.122-baselines — those mixed a B200 baseline into an H100 comparison (lore2026-07-13--finding--h100-steptime-regression-was-b200-baseline); all numbers above are same-silicon.Validation
configs/muon/*.yamlparse + pass the canonical assert on the merged schemamake checkclean; full suite at both device counts running as a SLURM job (result will be commented here)The suspected step-time regression was resolved as a hardware mismatch (July-3 baselines ran on B200s) — bridge task h100-steptime-regression-jul8, closed.
Crew-Address: slack/C08T7UV4449/1783730484.936959
🤖 Generated with Claude Code