|
Download code/docs/REFERENCE_GAP_ANALYSIS.md from viai957/align: direct link, hf CLI and curl.
- Browser
- Download file 39.2 kB
-
https://huggingface.co/viai957/align/resolve/main/code/docs/REFERENCE_GAP_ANALYSIS.md
- Command line
-
hf download hf://viai957/align/code/docs/REFERENCE_GAP_ANALYSIS.md
-
curl -L -o REFERENCE_GAP_ANALYSIS.md https://huggingface.co/viai957/align/resolve/main/code/docs/REFERENCE_GAP_ANALYSIS.md
39.2 kB
| # align: reference-repo gap analysis | |
| Scope: `/apps/development/rlhf/align` at HEAD 1d1c8ee (CPU suite 1107 passed / 13 skipped), compared against the read-only | |
| repos in `/apps/development/rlhf/reference-repos/`. Date of analysis: 2026-10-12. | |
| Method and honesty rules. Every status below comes from static reading and grep. No GPU job, no 7B load, no model download | |
| and no test run was done for this report. Where a number is my arithmetic or an assumption it is labelled. Items a | |
| verification pass corrected are already folded in. "Not found" means a search of the stated place came back empty. | |
| Paths are relative to `/apps/development/rlhf/align/` unless they start with `reference-repos/`. | |
| Hardware envelope used throughout: one node, 4x A10G (SM86, 23 GB usable, no FP8, no NVLink; `nvidia-smi topo -m` | |
| shows every pair as PHB, i.e. PCIe through the host bridge), 186 GB RAM, no swap, shared box. Host rules in | |
| `/apps/CLAUDE.md` (45 GB MemAvailable preflight, one heavy job at a time, nothing on `/` or `/tmp`) apply to every | |
| validation step named here. | |
| --- | |
| ## 1. Verdicts | |
| ### 1.1 Is align robust enough for real training today? | |
| **Conditionally yes for what it already does; no for multi-day, pretraining-scale runs.** | |
| What is strong (confirmed in code): | |
| - Lossless resume of weights, fp32 master/moments, scheduler, batch-stream position and sampler state | |
| (`align/train/trainer.py:626-746`, `:888-1019`); `.partial` staging plus `os.rename` publication and startup partial | |
| cleanup (`trainer.py:696-728`, `:869-876`). | |
| - Host-safety layer stronger than OLMo-core's: RAM/load/disk-queue preflight and exclusive flock | |
| (`align/utils/guard.py:377-478`), stage gate ladder (`align/train/stage_gates.py`), non-reentrant activation checkpointing, | |
| FSDP2 bf16/fp32-reduce (`align/train/fsdp.py:61-123`), chunked fused CE and DPO that never materialise full logits | |
| (`align/kernels/fused_ce.py:234`, `fused_dpo.py:526`), strong GRPO train/infer mismatch handling | |
| (`align/rl/grpo_loss.py:107-164`). | |
| What blocks "real run" status (all are concrete, mostly small): | |
| 1. **No graceful stop.** No SIGTERM/SIGINT handler in the trainer; `scripts/sft.py:143-147` documents a torchrun SIGTERM | |
| landing mid-save. No wall-clock limit. | |
| 2. **Silent NaN spin.** A non-finite gradient is skipped (`offload_adamw.py:193-201`), the scheduler does not advance on | |
| skips (`trainer.py:447-454`), so the horizon guard never trips, and `GradNormTripwire` is "blind" on NaN | |
| (`probes.py:325-326`). A permanently-NaN run burns GPU hours until data runs out. No consecutive-skip cap exists outside PPO | |
| (`ppo/health.py:221-232`). | |
| 3. **Clipping off by default.** `max_grad_norm` defaults to `None` (`config.py:136`); no shipped sft/dpo/pretrain TOML sets | |
| it; `offload_adamw` ignores it (`offload_adamw.py:606-620`). | |
| 4. **Tripwires unarmed for SFT and pretrain.** `TripwireConfig.armed` defaults to `()` (`config.py:329-335`); only `dpo_*.toml` | |
| and `grpo_stageb.toml:68` arm anything. The code exists (`probes.py:165-431`) but is not active. | |
| 5. **Save is a full-model gather.** Every rank gathers to CPU, rank 0 writes ~14 GB (`train_module.py:128-152`, | |
| `trainer.py:676-681`); the README projects 62.6 GB host peak (35.5 GB with per-rank optimizer files). Per-rank | |
| optimizer state cannot be resharded (`trainer.py:925-947`). | |
| 6. **FSDP reduce-scatters on every micro-batch.** No `no_sync` / `set_requires_gradient_sync` anywhere (grep over align/, | |
| tests/, docs/ is empty); `train_batch` calls `backward()` each micro-step (`train_module.py:88-97`) with grad_accum 8 | |
| (SFT) and 85 (`configs/grpo_stageb.toml:63-64`), over PCIe, in fp32. A throughput bug, unmeasured. | |
| 7. **Possibly rank-local logging and tripwires** (read from code, not executed): `Tracker` is constructed on every rank | |
| (`trainer.py:315-317`), logs `float(out.loss.detach())` unreduced (`:505-531`), and a HALT tripwire can raise on one rank | |
| only (`:551-589`), stranding peers until the NCCL timeout. Verify first, then fix. | |
| 8. **Loss normalisation is per-micro-batch mean**, equal-weighted across ranks (`train_module.py:88-97`, | |
| `sft_loss.py:97-116`). Biased with prompt-masked SFT or token-budget batching; becomes a hard interface problem for MoE. | |
| 9. **GPU evidence is thin.** README states adamw8bit is CPU-verified only (no GPU step time at 1.8B local elements, GPU/NCCL | |
| multi-rank unrun). The Triton FA2 backend is not selectable at HEAD: `.cache/kernel_gates/` is empty and | |
| `verify_equivalence_gate` raises without `triton_fa2_equivalence.json` there (`kernels/gate.py:40,138`); the file under | |
| `model/artifacts/` is not at the gate path. SDPA is the working backend. | |
| 10. Smaller: `latest_checkpoint` does not validate completeness and name-sorts (`trainer.py:878-886`); no fsync before the | |
| publishing rename; `pinned_checkpoints` is not persisted in `resume.pt`; no RNG state is saved; the optimizer has one | |
| param group. | |
| Corrections to stale premises (verified): python3.12 headers now exist at `/usr/include/python3.12/Python.h`, `.cache/pyheaders` | |
| is absent, so `kernels/_toolchain.py` is a no-op here. It also never blocked `torch.compile`; it only prepends headers to | |
| `CPATH` and is called only from `kernels/ops.py:156` and `kernels/flash_attention.py:92`. `torch.compile` is simply unused | |
| in align (grep hits are comments). | |
| ### 1.2 Can align serve as an OLMoE repo today? | |
| **No.** There is zero MoE code: no router, expert FFN, aux or z-loss, grouped GEMM, dispatch, expert-aware checkpoint keys, | |
| or MoE config fields (greps for moe/expert/router/top_k/all_to_all/z_loss over `align/`, `scripts/`, `configs/` find nothing | |
| relevant). The model is dense Mistral only (`align/model/mistral.py:354-366` `MLP`; `model/hf_config.py:49` hard-codes | |
| `MistralForCausalLM`; key tables `model/checkpoint.py:66-75` are dense `model.layers.N.*`). Also absent: QK-norm (OLMoE | |
| uses it; `grep qk_norm|q_norm|k_norm align/` is empty), from-scratch sharded init, token-addressed data order, data mixtures, | |
| doc-masked attention, WSD schedule, per-group weight decay, LM-head z-loss, in-loop eval. | |
| What carries over unchanged: RMSNorm, RoPE, GQA attention backends, fused chunked CE (needs a z-loss term), FSDP2 per-block | |
| sharding, activation checkpointing, the optimizer family, TrainModule/Trainer, resume machinery, config struct-mode, gates. | |
| The MoE core is roughly 10 work items (ROADMAP P1) on top of the P0 robustness fixes. | |
| Hardware reality for OLMoE-1B-7B itself (section 3): it fits on four free A10Gs at micro-batch 1x4096 (about 13.5 GiB per | |
| card, my arithmetic) but a 5T-token run is about 12 years on this node. "OLMoE-class" here means the architecture and recipe at | |
| reduced scale, not the published run. | |
| ### 1.3 Distance to a Leanstral-like build | |
| **Far, and the target is not defined from this side.** The Leanstral 1.5 recipe is pending a separate research report at | |
| `/apps/development/rlhf/research/notes/` (not consulted; nothing here assumes its architecture, size, context length, tokenizer | |
| or training stages). Whatever that report says, the code side needs these regardless: | |
| - **Lean verifier environment.** Nothing exists in align (`align/verify/*` is math-answer checking only). The only reference | |
| is `reference-repos/miles/examples/experimental/formal_math/single_round/reward_fn.py:18-41` (single-round, binary reward, | |
| Kimina server). It has known traps: it slices the response from its first `:=` (`:63-69`), and whether `sorry`, extra axioms or | |
| statement edits are rejected is delegated to a client library whose source is not in the repos. These must be tested | |
| adversarially before any reward is trusted. No multi-round proof repair exists in any reference. | |
| - **Long context.** Engine KV is contiguous per slot, no paging, no prefix sharing (`inference/engine.py:11-17`); on a 24 GB | |
| card next to ~14.5 GB of bf16 weights an 8k-token completion allows about 8 concurrent sequences (derived estimate). | |
| Packed training has no document masking. | |
| - **RL infrastructure.** Synchronous rollout (`rl/batch_source.py:246-247`), checkpoint-as-weight-sync, single rollout GPU, no | |
| external-process fault tolerance, no multi-turn token masks, no dynamic-sampling top-up, no pass@k eval. | |
| - **Tokenizer and chat format.** Only the Mistral v0.3 BPE and a single-turn `[INST]` template; no tool-call/multi-turn | |
| serialisation; no other tokenizer versions (`tokenizer/core.py:22-24` raises on other pipelines). | |
| - A Lean toolchain is an external binary; per `docs/DEPENDENCY_POLICY.md` it must be reached by stdlib subprocess/HTTP, with | |
| concurrency bounded by the host preflight. | |
| --- | |
| ## 2. Capability matrix | |
| Legend. **Status**: have / partial / missing / n-a. **Torch-only?**: yes = torch/numpy/safetensors/stdlib; triton = needs | |
| Triton (allowed); dep = needs a banned dependency. **A10G**: yes / degraded / no. **Effort**: S (<=2 days), M (~1 week), | |
| L (2-4 weeks), XL (>1 month). **For**: R = robust-training, O = olmoe, L = leanstral-like, N = nice-to-have. "Best reference" | |
| paths are under `reference-repos/`. | |
| ### 2.1 Training robustness | |
| | Capability | align status (path) | Best reference | Torch-only? | A10G | Effort | For | | |
| |---|---|---|---|---|---|---| | |
| | Coordinated SIGTERM/cancel, step-boundary final save, wall-clock limit | missing (`train/trainer.py:395-484` has no cancel path; `scripts/sft.py:143-147`) | `OLMo-core/src/olmo_core/train/trainer.py:641-667,1234-1250,1369-1392`; `OLMo/olmo/train.py:1057-1108` | yes | yes | S | R O L | | |
| | Non-finite loss halt + consecutive-skip cap | partial (skip exists `offload_adamw.py:193-201`; cap only in PPO `ppo/health.py:221-232`) | `OLMo-core/.../trainer.py:1430-1441` | yes | yes | S | R O | | |
| | Global grad-norm clipping on for every optimizer, pre-clip norm logged | partial (`adamw8bit.py:418-443` implements; `config.py:136` default None; offload ignores) | `OLMo-core/.../transformer/train_module.py:514-524,611-638` | yes | yes | S | R O | | |
| | Tripwires armed by default for SFT/pretrain | partial (code `train/probes.py:165-431`; `config.py:329-335` armed=()) | n/a (align's own design) | yes | yes | S | R | | |
| | Loss/grad spike skip-and-continue (rolling mean+sigma) and spike-rate metric | partial (HALT-only `probes.py:282-340`) | `OLMo-core/src/olmo_core/optim/skip_step_optimizer.py:12-116`; `train/callbacks/stability_monitor.py` | yes | yes | M | R O | | |
| | Token-count loss normalisation across micro-batches/ranks | partial (`train/train_module.py:88-97`, `sft_loss.py:97-116`) | `OLMo-core/.../transformer/train_module.py:354-422`; `nn/moe/loss.py:29-134` | yes | yes | M | R O L | | |
| | FSDP `no_sync` on non-final micro-batches | missing (grep empty; `train_module.py:88-97`) | `fairseq2/src/fairseq2/trainer.py:640-650`; `nn/fsdp/unified.py:113-122` | yes | yes | S | R | | |
| | Rank-reduced metrics, rank-0 writer, tripwire decisions from reduced values | partial / verify (`trainer.py:315-317,505-531,551-589`) | `OLMo-core/.../train/trainer.py:1037-1105,1394-1441` | yes | yes | M | R O | | |
| | Skip-ranges, hard stop, loss-based early stop | partial (`max_micro_steps` only `trainer.py:461-463`) | `OLMo-core/.../trainer.py:254-259,1487-1498`; `OLMo/olmo/train.py:1062-1125` | yes | yes | S | R O | | |
| | GC control (disable auto GC, periodic gen-1) | missing (manual only `scripts/sft.py:160`) | `OLMo-core/.../callbacks/garbage_collector.py:12-53` | yes | yes | S | R N | | |
| | Throughput/MFU and CUDA allocator counters in history | partial (`probes.py:528`, tokens/s only) | `OLMo-core/.../callbacks/speed_monitor.py`, `gpu_memory_monitor.py` | yes | yes | S | R N | | |
| | In-loop held-out NLL/perplexity eval | missing (stage-exit gate only `scripts/sft.py:176-185`) | `OLMo-core/.../callbacks/evaluator_callback.py:45-300` | yes | yes | M | R O L | | |
| | Launch supervisor (bounded retry gated on preflight and progress, GPU idle/temp check) | partial (`utils/guard.py:81-566`; no retry loop) | `OLMo-core/src/scripts/lambda/healthchecks.sh` (launch_with_retries.sh is a Slurm wrapper, unbounded retry, weaker model) | yes | yes | S | R | | |
| | RNG state in checkpoints; trainer/optimizer-state load split | partial (none saved; `trainer.py:888-1019`) | `OLMo-core/.../trainer.py:803-848`; `train/utils.py:31-95` | yes | yes | S | R O | | |
| | Atomic publish + retention | have (`trainer.py:626-728,856-886`); gaps: no fsync before rename, no completeness check in `latest_checkpoint`, pins not persisted | `OLMo-core/.../distributed/checkpoint/filesystem.py:105-160` | yes | yes | S | R | | |
| | Sparse permanent checkpoint tier (rewind target) | partial (keep 2, `config.py:166`) | `OLMo-core/.../callbacks/checkpointer.py:63-110` | yes | yes | S | R O | | |
| | LR schedules: WSD, linear, alpha_f floor, stateless token-denominated | partial (cosine only, stateful `trainer.py:172-212`) | `OLMo-core/src/olmo_core/optim/scheduler.py:160-503` | yes | yes | S | O R | | |
| | Param-group overrides (wd, quantisation floor) | missing (`adamw8bit.py:257-263` one group) | `OLMo-core/.../optim/config.py:44-229` | yes | yes | S | O | | |
| | Weight EMA | missing | `TinyRecursiveModels/models/ema.py` | yes | yes | S | N R | | |
| | Weight init: dense trunk N(0,0.02) exists; no depth-scaled, no meta/sharded init, no MoE init | partial (`model/mistral.py:559-566`, default `init_weights=True`) | `OLMo-core/.../nn/transformer/model.py:265-340`, `init.py:182-254` | yes | yes | M | O | | |
| | Low-memory optimizer for ~7B (8-bit moments, host offload) | partial, CPU-verified only (`train/adamw8bit.py`, `offload_adamw.py`; README status) | not in OLMo-core | yes | degraded | M | O | | |
| | Anomaly mode / fp16 scaler | missing | `fairseq2/src/fairseq2/trainer.py:513-665` | yes | yes | S | N | | |
| | Optimizers beyond AdamW family (Muon, Lion, schedule-free) | missing | `OLMo-core/src/olmo_core/optim/{muon,lion}.py` | yes | yes | S | N | | |
| ### 2.2 Distributed and checkpointing | |
| | Capability | align status (path) | Best reference | Torch-only? | A10G | Effort | For | | |
| |---|---|---|---|---|---|---| | |
| | Sharded topology-agnostic checkpoint (DCP-style), no rank-0 gather, bounded-memory unshard | partial (gather-based `train_module.py:128-152`, `trainer.py:676-746`; per-rank optimizer files refuse other world size `:925-947`; no DCP path for optimizer state) | `OLMo-core/.../distributed/checkpoint/__init__.py:71-393,465-`; `fairseq2/src/fairseq2/checkpoint/manager.py` | yes | yes | L | R O L | | |
| | Async checkpoint save | missing | `OLMo-core/.../train/checkpoint.py:136-181`; `callbacks/checkpointer.py:168-325` | yes | degraded (host staging copy vs 45 GB rule) | M | R O | | |
| | Data-reader state in checkpoint | have (`trainer.py` resume ~:960-985 refuses missing sampler state; `rl/batch_source.py:425,462`) | `fairseq2/.../checkpoint/manager.py:378-402` | yes | yes | n/a | R | | |
| | FSDP2 per-block, bf16 params, fp32 reduce | have (`train/fsdp.py:61-86`; embeddings/lm_head in root unit) | `OLMo-core/.../nn/transformer/model.py:859-935` | yes | yes | n/a | R O | | |
| | Distributed init: composite `cpu:gloo,cuda:nccl`, configurable timeout, set_device first | partial (`utils/dist.py:32-41`, `:108-121`) | `OLMo-core/src/olmo_core/train/__init__.py:85-148`; `distributed/utils.py:72-216` | yes | yes | S | R O | | |
| | Activation checkpointing: full block only, non-reentrant | partial (`fsdp.py:90-123`) | `OLMo-core/.../nn/transformer/model.py:726-838` | yes | yes | M | O R | | |
| | `torch.compile` per block | missing (comments only; no longer toolchain-blocked on this box) | `OLMo-core/.../model.py:840-857` | yes | yes (unmeasured) | M | O N | | |
| | HSDP / DDP / 2-D mesh | missing | `OLMo-core/.../distributed/parallel/__init__.py:110-253` | yes | degraded | M | N (substrate for EP) | | |
| | Expert parallelism, all-to-all | missing | `OLMo-core/.../nn/moe/parallel_mlp.py:206-871`; `ops/moe.py:224-281`; `torchfeather/torchfeather/distributed/expert_parallel.py:74-263` | yes | degraded (PCIe) | L-XL | O | | |
| | Tensor / context / pipeline parallel | missing | `OLMo-core/.../distributed/parallel/{tensor,context,pipeline}_parallel.py` | yes (ring CP needs ring_flash_attn: dep) | degraded | L-XL | N | | |
| | Float8 training | n-a | `OLMo-core/src/olmo_core/float8/__init__.py` | dep | **no** (SM86 has no FP8) | XL | none | | |
| | Multi-node, elastic resume | missing (`trainer.py:937-947`) | `OLMo-core` DCP | yes | n/a | L | none now | | |
| | Profiler callback | missing | `OLMo-core/.../callbacks/profiler.py` | yes | yes | S | N O | | |
| | Per-layer grad/activation stats | partial (`probes.py` TrunkMovementProbe) | `OLMo-core/.../callbacks/gap_monitor.py` | yes | yes | M | O N | | |
| ### 2.3 MoE (OLMoE recipe) | |
| | Capability | align status (path) | Best reference | Torch-only? | A10G | Effort | For | | |
| |---|---|---|---|---|---|---| | |
| | MoE block, ModelConfig fields, param naming, HF key tables | missing (`mistral.py:354-396`; `hf_config.py:49,68-91`; `checkpoint.py:66-75`) | `OLMo-core/.../nn/transformer/block.py:512-596`; `nn/moe/moe.py:123-251`; `nn/transformer/config.py:1079-1100` | yes | yes | L (M understated: config, hf_config, key tables, AC return contract, QK-norm all change) | O L | | |
| | QK-norm in attention | missing (`mistral.py:211-226`, grep empty) | `OLMoE/configs/OLMoE-1B-7B-0924.yml` (`attention_layer_norm: true`); `OLMo-core/.../config.py:1087` | yes | yes | M | O | | |
| | Router: fp32 linear gate, softmax top-k, no renorm (OLMoE-1B-7B) | missing | `OLMo-core/.../nn/moe/router.py:416-455`; `torchfeather/torchfeather/model/moe/moe.py:129-192` | yes | yes | S | O L | | |
| | Load-balancing aux loss (weight 0.01, /n_layers) | missing | `OLMo-core/.../nn/moe/loss.py:29-111`, `moe.py:147-151` | yes | yes | S | O | | |
| | Router z-loss (0.001) | missing | `OLMo-core/.../nn/moe/loss.py:114-138` | yes | yes | S | O | | |
| | Aux-loss gradient plumbing through FSDP2, AC, grad accum | missing (`train_module.py:44-69,88-97`) | `OLMo-core/src/olmo_core/ops/__init__.py:4-28` | yes | yes | M | O R | | |
| | Aux-loss-free bias balancing (DeepSeek style) | missing; not in the OLMoE recipe | `OLMo-core/.../router.py:303-328`; `torchfeather/.../components/optimizer.py:186-241` | yes | yes | M | L N | | |
| | Shared experts | missing; not in OLMoE-1B-7B | `OLMo-core/.../moe.py:241-249` | yes | yes | S | N | | |
| | Dropless dispatch (stable argsort, gather, scatter) | missing | `torchfeather/.../moe.py:202-407`; `OLMo-core/.../kernels/moe.py` | yes (triton optional) | yes | M | O | | |
| | Capacity-factor routing | missing; parity oracle for dropless | `OLMo-core/.../parallel_mlp.py:350-631` | yes | yes | S | N | | |
| | Grouped GEMM via `torch._grouped_mm` | missing. **A10G is firm "degraded"**: `libtorch_cuda` carries CUTLASS grouped kernels only for sm90/sm100 plus a fallback; `DeepSpeed/deepspeed/moe/group_gemm_triton.py:1-20` states sm80/sm86 falls back to a per-group `at::mm` loop with a device-to-host sync on `offs`. Inductor template gated at capability >=9.0 (`torch/_inductor/kernel/mm_grouped.py:225`) | `torchfeather/.../moe.py:51-86` | yes | degraded | S (correctness only) | O | | |
| | Triton grouped GEMM for SM86 (fwd, dX, dW) | missing | `DeepSpeed/deepspeed/moe/group_gemm_triton.py:56-355` (written for sm80/86, autograd, fits 99 KB smem); `Liger-Kernel/src/liger_kernel/ops/fused_moe*.py` (prune autotune to stages<=2) | triton | yes (unrun) | L | O | | |
| | Expert/router init (trunc-normal 0.02 incl. router and w2) and "no uninitialised param" test | partial (`mistral.py:562-566` visits Linear/Embedding only; bare 3-D expert Parameters would be missed) | `OLMo-core/.../init.py:182-254`; `OLMo-MoE/olmo/model.py:709-741` | yes | yes | S | O | | |
| | Expert-aware checkpoint layout + round-trip gate | missing (`checkpoint.py:281` is the place) | `OLMo-core/src/olmo_core/nn/hf/convert.py:50-53,203-278` | yes | yes | M | O R | | |
| | Sparse upcycling dense to MoE | missing | `OLMoE/scripts/sparsify_ckpt_unsharded.py:27-66` (no upcycling code in OLMo-core) | yes | yes | M | O L | | |
| | MoE telemetry and router-collapse tripwire | missing | `OLMo-core/.../router.py:370-414` | yes | yes | S | R O | | |
| | LM-head z-loss (1e-5) inside fused CE | missing (grep empty in `kernels/fused_ce.py`) | `OLMo-core/.../functional/cross_entropy_loss.py:12-50`; `Liger-Kernel/.../ops/cross_entropy.py:223` | yes | yes | S | O R | | |
| | EP x FSDP2 composition | partial (`train_module.py:154-199`: non-`(Shard(0),)` placements take the generic `distribute_tensor` branch, correct but puts each whole tensor on GPU; not wrong) | `OLMo-core/.../nn/moe/mlp.py:71-112` | yes | degraded | L | O | | |
| | Capacity of megablocks fork dependency | n-a: OLMoE 2024 run needed a megablocks fork (source not in reference-repos); OLMo-core has none | `OLMo-core` | yes | yes | S | O | | |
| ### 2.4 Data | |
| | Capability | align status (path) | Best reference | Torch-only? | A10G | Effort | For | | |
| |---|---|---|---|---|---|---| | |
| | Token-addressed, world-size-invariant data order (uint32 permutation memmap, offset = tokens/global_batch) | partial (`data/loader.py:52-168` ragged batches; `trainer.py:118` materialises `list(self.sampler)`; resume at other world size reorders silently) | `OLMo-core/.../data/data_loader.py:441-533,619-777` | yes | yes | L | R O | | |
| | Fixed-length memmap token dataset with doc lengths | partial (`data/store.py:304-372`; `pretrain_corpus.py:110-157` EOS-joined, no doc ids) | `OLMo-core/.../data/numpy_dataset.py:451-690`; `datatrove/.../pipeline/tokens/tokenizer.py` | yes | yes | M | O | | |
| | Data mixtures (target ratio, max repetition, apportionment) | missing | `OLMo-core/.../data/source_mixture.py:30-456`; `dolma/src/mixer.rs` | yes | yes | M | O L R | | |
| | Parallel resumable tokenise/shard build | partial (single process, serial; `pretrain_corpus.py:64` 500M ceiling; `store.py:316-319` loads every row's extras at open) | `datatrove/.../tokens/*`; `dolma/python/dolma/tokenizer/*` | yes | yes | L | R O | | |
| | Exact + MinHash dedup | missing | `datatrove/.../dedup/minhash.py:41-598`; `exact_dedup.py` | yes (numpy, disk-sorted) | yes (CPU) | M | R O | | |
| | Heuristic quality, language, URL/PII filters | missing (`data/argilla.py:82` is preference-pair only) | `datatrove/.../filters/gopher_quality_filter.py`; `DCLM/baselines/baselines_configs/dclm_baseline_refinedweb.yaml` | yes (fastText classifier is dep) | yes | M | R O L | | |
| | Text-level benchmark decontamination | partial (id-level `data/build.py:199-229`) | `datatrove/.../decont/n_grams.py:28-194` | yes | yes | S | R L | | |
| | Degenerate-instance filter, vocab-range check in collate | missing (only all-masked guard `sft_loss.py:84-93`) | `OLMo-core/.../data/utils.py:642-725`; `collator.py:31-40` | yes | yes | S | R O | | |
| | Doc-boundary attention masking | missing (`kernels/flash_attention.py:824-832` causal + key padding only) | `attention-gym/attn_gym/masks/document_mask.py:34-63`; torch `flex_attention` | yes | degraded (JIT and 99 KB smem unmeasured) | M-L | R O L | | |
| | Generic tokenizer (byte-level BPE with Unicode classes, other vocab sizes) | missing (`tokenizer/core.py:22-24`) | `mistral-common/.../tekken.py:109`; OLMoE uses `allenai/gpt-neox-olmo-dolma-v1_5` (`OLMoE/README.md:92-96`) | yes (stdlib has no `\p{L}`; use `unicodedata`) | yes | L | O L | | |
| | Chat template: multi-turn, tools, V3 tool-call tokens | partial (`data/schema.py:264-273` single `[INST]`) | `mistral-common/.../instruct.py:473-740` (port, deps pydantic/tiktoken banned) | yes | yes | M | L R | | |
| | Pretraining from scratch pipeline | missing (`scripts/pretrain.py` is continued pretrain from snapshot; config points at another repo's data dir `configs/pretrain.toml:52-55`) | `OLMo-core/src/scripts/train/OLMoE-1B-7B.py` | yes | degraded | M | O | | |
| ### 2.5 Kernels | |
| | Capability | align status (path) | Best reference | Torch-only? | A10G | Effort | For | | |
| |---|---|---|---|---|---|---| | |
| | Fused linear + chunked CE | have (`kernels/fused_ce.py:180-234`) | `Liger-Kernel/.../ops/fused_linear_cross_entropy.py:51` | yes | yes | n/a | R O L | | |
| | Fused DPO | have (`kernels/fused_dpo.py:375,526`; torch-only, no triton import) | n/a | yes | yes | n/a | R | | |
| | Triton FA2 fwd+bwd | present but **not selectable at HEAD** (gate absent from `.cache/kernel_gates`; square, no-KV-cache blocks only `mistral.py:321-340`); SDPA already ships FA2 kernels | `kernels/_fa2_reference_upload.py` | triton | yes | S (rerun gate on GPU) | R | | |
| | Fused RMSNorm/RoPE/SwiGLU with backward | partial (forward-only, flag-gated off `kernels/ops.py:39-49,163-213`) | `Liger-Kernel/.../ops/{rms_norm,rope,swiglu}.py` | triton | yes | S each | N | | |
| | Generalised equivalence gate (parameterised by kernel name) | partial (`kernels/gate.py:62-208`, resolver is FA2-specific) | n/a | yes | yes | S | R O L | | |
| | Doc-masked / varlen flash attention | missing | `attention-gym`; torch `varlen_attn` | triton | degraded | L | O L | | |
| | FP8 GEMM, MLA decode, wgmma/TMA kernels | n-a | `DeepGEMM`, `FlashMLA`, `TileKernels` (SM90/SM100; TileLang) | dep | **no** | XL | none | | |
| | MoE permute/gather/scatter Triton kernels | missing (torch index ops are the oracle) | `OLMo-core/.../kernels/moe.py:31-192`; `Liger-Kernel/.../fused_moe_kernels.py` | triton | yes | M | O (only if profiling demands) | | |
| ### 2.6 Inference and rollout | |
| | Capability | align status (path) | Best reference | Torch-only? | A10G | Effort | For | | |
| |---|---|---|---|---|---|---| | |
| | Continuous batching, contiguous per-slot KV | have (`inference/engine.py:11-17,588-645`) | `nano-vllm/nanovllm/engine/scheduler.py` | yes | yes | n/a | R | | |
| | Paged KV cache | missing (by design `engine.py:11-17`) | `vllm-upstream/vllm/v1/attention/ops/triton_unified_attention.py` (no flash-attn dep; nano-vllm needs flash_attn) | triton | yes | L | R L | | |
| | Prefix sharing across the G samples of a prompt | missing (`rollout/native.py` prefills each prompt G times) | `nano-vllm/.../block_manager.py:36-120` (use blake2b, not xxhash) | yes | yes | S (copy KV rows) to M (block hash) | R L | | |
| | Chunked prefill, token budget, preemption | missing | `vllm-upstream/vllm/v1/core/sched/scheduler.py:562-790` | yes | yes | M | R | | |
| | CUDA-graph decode, fused sampler, top-k/min-p/penalties | missing | `nano-vllm/.../model_runner.py:196-257` | yes | yes | M | N | | |
| | Speculative decoding (n-gram proposer + exact rejection sampler) | missing (`engine.py:48-51`) | `vllm-upstream/.../rejection_sampler.py`; `DeepSpec/deepspec/utils/sampling.py:30-45` | yes | degraded | L | N | | |
| | MoE inference path (router + expert loop/grouped) | missing | `vllm-upstream/.../models/olmoe.py:63-118` | triton | degraded | XL | O | | |
| | Per-request failure isolation, restartable rollout | partial (spool has heartbeat `rollout/protocol.py:167-227`; native raises) | `prime-rl/src/prime_rl/orchestrator/dispatcher.py:1-22` | yes | yes | S-M | R L | | |
| | Multi-engine / time-sliced rollout | partial (one engine GPU, rank 0 only) | `open-instruct/open_instruct/data_loader.py:395`; `miles/miles/rollout/sleep_rollout.py` | yes | degraded | M | R L | | |
| ### 2.7 RL post-training | |
| | Capability | align status (path) | Best reference | Torch-only? | A10G | Effort | For | | |
| |---|---|---|---|---|---|---| | |
| | Train/infer logprob mismatch correction (rho) | have (`rl/grpo_loss.py:107-164`) | `open-instruct/open_instruct/grpo_utils.py:410`; `miles/.../corrections.py` | yes | yes | n/a | R O | | |
| | bf16 log-softmax gap under FSDP2 (README:200) | partial | n/a | yes | yes | S | R O | | |
| | Sampling-support replay (top-p/top-k) | missing (minimum: refuse top_p<1 in RL config; `rollout/protocol.py:44`) | `prime-rl/src/prime_rl/trainer/rl/loss.py:74-91` | yes | yes | S (refusal) / M | R | | |
| | Async / bounded-staleness pipelined RL | partial (submit/collect split exists `rollout/protocol.py:99-108` but called back to back `rl/batch_source.py:246-247`) | `prime-rl/.../orchestrator/dispatcher.py:400-441`; `open-instruct/.../data_loader.py:413,994-1003` | yes | degraded | M | R O L | | |
| | In-memory trainer-to-engine weight sync | partial (checkpoint is the sync, ~13.5 GB write per sync) | `open-instruct/open_instruct/vllm_utils.py:1356-1457` | yes | degraded (PCIe) | M | R O | | |
| | Multiple minibatches per rollout | missing (`rl/batch_source.py:296-307`; ratio is 1 and clip never binds) | `open-instruct/.../grpo_utils.py:102`; `trl/.../grpo_config.py:183` | yes | yes | M | R O | | |
| | GSPO sequence-level ratio, OPSM | missing / partial (`grpo_loss.py:131-142` TV mask is different) | `trl/trl/trainer/grpo_trainer.py:3007-3033,3146-3157` | yes | yes | S | O R | | |
| | MoE routing replay (R3) | missing (needs MoE model and decode path) | `miles/miles/utils/replay_base.py`; `prime-rl/.../models/layers/moe.py:179-227` | yes | yes | L | O | | |
| | Truncation mask/metric (finish_reason unused) | partial (`rl/rewards.py:22-36` soft only) | `open-instruct/.../data_loader.py:1187-1204` | yes | degraded (KV-bound) | S | R L | | |
| | Dynamic sampling top-up, pass-rate memory | partial (`rl/batch_source.py:270-285` retries, shrinking batch) | `open-instruct/.../data_loader.py:508-516,1006-1030` | yes | yes | M | R L | | |
| | Eval during RL: pass@k, stop rate, multiple sets | partial (`rl/canary.py:26-92` greedy pass@1 only) | `open-instruct/.../grpo_utils.py:34-67,785-870` | yes | degraded | S | R L | | |
| | Multi-turn rollout with observation-token loss mask | missing (`rl/assembly.py:126-150`) | `open-instruct/.../vllm_utils.py:949-1166`; `miles/.../multi_turn.py:25-70` | yes | yes | L | L N | | |
| | Environment abstraction (reset/step/state, pool) | missing | `open-instruct/open_instruct/environments/base.py:43-135` (imports ray/pydantic: re-implement) | yes | yes | M | L N | | |
| | Sandboxed code-execution verifier | missing | `open-instruct/open_instruct/code_utils/code_utils.py:96-340` (reliability_guard is not a security boundary) | yes | yes | M | N L | | |
| | **Lean 4 verifier environment** | **missing** | `miles/examples/experimental/formal_math/single_round/{reward_fn,kimina_wrapper}.py` (single round, traps in 1.3) | yes (stdlib subprocess/HTTP) | yes | L | L | | |
| | Rejection sampling / expert iteration pipeline | missing (parts exist: Engine, OutcomeVerifier, SFT) | `open-instruct/open_instruct/rejection_sampling/rejection_sampling.py:231-301` (RM-argmax, not verifier-gated) | yes | yes | S | L R | | |
| | Reward model (Bradley-Terry) training | missing (`ppo/value_head.py:149` head only; README:194) | `trl/trl/trainer/reward_trainer.py:743-760` | yes | yes | S | N | | |
| | LoRA in GRPO | partial (`ppo/lora.py` PPO only) | `prime-rl` docs LoRA | yes | yes | M | R N | | |
| | PPO stage launchable | partial (README: draft, `[TBD]` fields) | n/a | yes | degraded | L | R | | |
| | Recurrent/ACT reasoning cores (HRM, TRM) | missing; puzzle-scale, no evidence of LLM transfer; repos can not resume exactly | `HRM/models/hrm/hrm_act_v1.py:186-207` | yes | yes | M | N | | |
| --- | |
| ## 3. OLMoE on 4x A10G: sizing and token budget | |
| ### 3.1 Reference configuration (read from code) | |
| OLMoE-1B-7B-0924 (`reference-repos/OLMoE/configs/OLMoE-1B-7B-0924.yml:11-45`; cross-check | |
| `reference-repos/OLMo-core/src/olmo_core/nn/transformer/config.py:1079-1100`): 16 layers, d_model 2048, 16 heads (MHA), | |
| 64 experts, top-8, expert hidden 1024 (SwiGLU), dropless, RMSNorm, QK-norm, RoPE, seq 4096, vocab 50,280 padded to 50,304, | |
| untied embeddings, no biases, init N(0,0.02) cut at 3 sigma, load-balance weight 0.01, router z-loss 0.001. Recipe: AdamW | |
| lr 4e-4, wd 0.1, betas (0.9, 0.95), cosine with warmup (2,500 steps), alpha_f 0.1, global batch 1024 x 4096 = 4.19M tokens, | |
| clip 1.0, bf16 with FSDP full shard. | |
| Re-derived counts: 6.919B total, 1.282B active (matches `OLMoE/README.md:4`). Expert params 402.65M/layer, attention | |
| 16.78M/layer, embeddings 2 x 103.0M. | |
| Note: the published run had `decay_embeddings: true` (`OLMoE-1B-7B-0924.yml:52-53`), so a single param group with wd 0.1 matches | |
| it. The embedding-wd=0 override belongs to the later OLMo-core recipe (`OLMoE-1B-7B.py:33-41`). The "5.1T tokens" figure is | |
| not in these repos; only the scheduler horizon t_max = 5e12 (`yml:64-66`) is. | |
| ### 3.2 Memory (my arithmetic; nothing measured) | |
| Per parameter with align's stack: bf16 weight 2 B + bf16 grad 2 B + 8-bit AdamW moments 2.004 B = 6.004 B, FSDP over 4 ranks. | |
| | Model | Total / active | Static per rank | Verdict | | |
| |---|---|---|---| | |
| | OLMoE-1B-7B (vocab 50,304) | 6.919B / 1.282B | 9.67 GiB | fits micro-batch 1x4096, about 13.5 GiB with one gathered block (0.84 GB, x2 with prefetch), root unit 0.41 GB, AC residents 0.27 GB, ~1 GB block transient, ~0.5 GB context | | |
| | Same with Mistral vocab 32,768 | 6.847B / 1.210B | 9.57 GiB | fits | | |
| | "mid": d1536 L16 E64 k8 h768 | 3.877B / 0.706B | 5.42 GiB | fits easily | | |
| | **mini-A**: d1024 L16 E64 k8 h512 | 1.746B / 0.337B | 2.44 GiB | recommended ablation size | | |
| | **mini-B**: d768 L12 E32 k4 h384 | 0.419B / 0.121B | 0.59 GiB | CI / smoke size | | |
| | Mistral-7B v0.3 sliced upcycle, E=16 x h=896 | 7.250B / depends on k | 10.14 GiB | same footprint as the dense stack align already budgets | | |
| | Mixtral-style 8 x full 14336 FFN | 46.7B | 65 GiB | impossible | | |
| Ceiling: with ~5 GiB reserved, static <= ~17 GiB/rank gives about 12B total; sensible limit is 8-10B. The recipe's fp32 fused | |
| AdamW (16 B/param, ~27.6 GiB/rank) does not fit; host-offload AdamW (12 B/param, ~83 GB host) violates the 45 GB preflight when | |
| anything else runs. So adamw8bit is the only plausible optimizer, and it has never been exercised on MoE shapes or on GPU. | |
| Flat expert layout `(E*h, d)` is preferable to `(E, d, h)` so `Shard(0)` works for any world size (GRPO stage B uses 3 ranks; | |
| 64 experts do not divide by 3). | |
| ### 3.3 Token budget in GPU-days | |
| Assumptions (stated, not measured): sustained 25 TFLOP/s per A10G in bf16 (sensitivity 15-35); FLOPs per token = 6 x active | |
| params; MoE dispatch and PCIe communication overhead ignored, so these are optimistic lower bounds on time. No MFU | |
| measurement exists in the repo (`probes.py` reports tokens/s only). | |
| | Run | FLOPs | GPU-days at 25 TFLOP/s | Wall-clock on 4 GPUs | | |
| |---|---|---|---| | |
| | OLMoE-1B-7B, 5e12 tokens (scheduler horizon) | 6 x 1.282e9 x 5e12 = 3.85e22 | ~17,800 (12,700 at 35; 29,700 at 15) | ~4,450 days, about 12 years (8.7 y at 35 TFLOP/s) | | |
| | OLMoE-1B-7B throughput | 7.7 GFLOP/token | n/a | 100 TFLOP/s / 7.7e9 = ~13k tokens/s = ~1.1B tokens/day | | |
| | OLMoE-1B-7B, 20B tokens | 1.5e20 | ~71 | ~18 days | | |
| | mini-A (0.337B active), throughput | 2.02 GFLOP/token | n/a | ~49k tokens/s = ~4.3B tokens/day | | |
| | mini-A, 20B tokens | 4.0e19 | ~19 | ~4.7 days | | |
| | mini-B (0.121B active), 5B tokens | 3.6e18 | ~1.7 | ~10 hours | | |
| Conclusions. A faithful OLMoE-1B-7B pretraining run is out of reach on this node by a factor of several hundred; the | |
| published 5T-token horizon would take over a decade. The realistic goal is architecture-and-recipe reproduction at mini-A | |
| scale (1-20B tokens, days not years), plus an OLMoE-1B-7B bring-up smoke test (a few hundred steps) to prove it fits and to | |
| measure real MFU. Upcycling a pretrained dense checkpoint, or using pre-tokenised public shards read via memmap, is the only | |
| way to reach useful quality; tokenising web-scale data on this box is not viable (pure-Python BPE ~75-165k tokens/s/core | |
| measured on CPU, ~1 core-hour per 300-500M tokens). | |
| Communication reality check (assumed ~12 GB/s effective PCIe, unmeasured). Per layer per 4096-token micro-batch, EP | |
| all-to-all moves about 403 MB fwd+bwd (~34 ms/layer, ~0.54 s over 16 layers). FSDP-style expert weight gathering moves | |
| about 2.42 GB/layer (~201 ms/layer, ~3.2 s over 16 layers) against ~0.9-2.1 s of compute. So FSDP-only experts are | |
| comm-bound at 4096 tokens per micro-batch and EP is ~6x cheaper in bytes, but dropless EP costs a host sync per layer and | |
| cannot be compiled. The published OLMoE-1B-7B run used no EP (`OLMo-MoE/olmo/config.py:1361-1363`). Benchmark both before | |
| committing; do not assume. | |
| Correctness caveat on upcycling tests. The OLMoE script makes E identical copies plus a fresh router with softmax top-k and no | |
| renormalisation, so it is not function-preserving. For the sliced variant, "k=E reproduces dense logits" holds only if the | |
| combine weights are forced to 1.0 (router bypass), because softmax weights sum to 1 (about 1/E each at init). The slicing | |
| itself is exact for SwiGLU. | |
| --- | |
| ## 4. Excluded repos and paths | |
| Excluded from review and why. | |
| - **Speech/ASR/TTS/duplex/voice** (out of scope for a text LLM stack): Easy-Turn, Emilia-pipe, FD-Bench, Full-Duplex-Bench, | |
| Game-Time-Benchmark, HumDial-FDBench, IndicConformerASR, IndicVoices, MTR-DuplexBench, NeMo (LLM parts not reviewed), | |
| NeMo-text-processing, OIWER-Orthographically-Informed-Benchmarking-for-ASR, SID-bench, URO-Bench, VoiceBench, | |
| superintelligenceco-voicebench, vistaar, delayed-streams-modeling, hibiki, hibiki-zero, icefall, indic-punct, | |
| indicConformer-finetuning, indicfdb, llm_wer, moshi, moshi-finetune, omnilingual-asr, open_asr_leaderboard, personaplex, | |
| pocket-tts, pyannote-audio, sherpa-onnx, silero-vad, tts_longeval, unmute, whisper-timestamped, whisperX, whisper_streaming. | |
| - **Interpretability UI**: neuronpedia. (interp-engine and circuit-tracer are library-level and were not reviewed here.) | |
| - **Unreviewed, unclassified**: Dhruva-Evaluation-Suite (modality unstated), astra-brief, clef-head (no README). | |
| - **Reviewed for patterns only, not adoptable**: 3FS (needs RDMA NICs and FoundationDB; only the "avoid FUSE for small random | |
| reads" lesson applies), nnsight and TransformerLens (analysis tooling, depend on transformers; TransformerLens has an | |
| OLMoE-1B-7B-0924 adapter that could serve as an oracle in the legacy venv), NeMo-Curator (RAPIDS and Ray; datatrove is the | |
| right template), AgileRL (evolutionary HPO irrelevant; GSPO/packing covered elsewhere), HRM and TinyRecursiveModels | |
| (small puzzle models, model-only checkpoints that cannot resume; negative pattern), DeepSpeed (banned dependency; Triton | |
| grouped GEMM and router math are pattern sources only). | |
| - **Hopper/Blackwell-only, not A10G-feasible**: DeepGEMM sm90/sm100 kernels and Mega MoE, FlashMLA, TileKernels (TileLang, SM90/SM100), | |
| FP8/MXFP, prime-rl DeepGEMM/DeepEP/FA3/FA4, Liger Blackwell tiling, torch `_scaled_grouped_mm`, Inductor grouped_mm template. | |
| - **Infrastructure with no single-node value**: Beaker launch/callbacks, remote-store I/O, Ray placement, SLURM/k8s, prefill-decode | |
| disaggregation, wandb/comet/slack reporting, HF-hub conversion callbacks (need transformers). | |
| - **Not read or not found**: the megablocks fork behind the 2024 OLMoE run (source absent); prime-rl `verifiers`, `prime-envs`, | |
| `renderers` submodules (empty directories); Lean environments anywhere other than miles `formal_math/single_round`; | |
| `nmo-research/docs/0[234]_*.md` (not opened by the capability maps; claims rest on code); the Leanstral 1.5 report. | |
| - **Not verified by execution anywhere**: SM86 behaviour of `flex_attention`, `varlen_attn`, Triton grouped GEMM autotune; | |
| all throughput and PCIe figures; the all-ranks-write-`history.jsonl` observation; adamw8bit on GPU. | |
| - **Documentation errors noticed in align itself**: `docs/ARCHITECTURE.md:156-166,195-212` misdescribes the GRPO loss/rho (code | |
| is DAPO clip with rho as a multiplicative weight and constant Dr.GRPO denominator, `rl/grpo_loss.py:182-199`); | |
| `README.md:198` says GRPO resume is unwired while `rl/batch_source.py` has state_dict/load_state_dict; comment at | |
| `train/offload_adamw.py:632` ("Not a field of OptimizerConfig today") is stale since `config.py:136` exists. | |