vanilla-small-20B β€” dense baselines (12L / d=1024, 202.53M)

Dense (sparsity_mode=none) counterparts to the cayley-small-*-mlp_in-20B ParityTransformer siblings. One 20B-token run, five checkpoints: three val-matched early stops plus the token-matched end of the run.

These are the dense comparators for the interpretability claim: if a ParityTransformer is more interpretable than a dense model that is at least as good on val, the comparison cannot be dismissed as a handicapped baseline.

Checkpoints

Files are named by iter. They were previously named by the --save-at-val threshold that fired; those names misstated the actual loss, so they were renamed (ckpt_val_3.1584.pt β†’ ckpt_val_1900.pt, 3.1484 β†’ 2100, 3.1330 β†’ 2300).

file iter tokens measured val_loss in-run trigger
ckpt_val_1900.pt 1900 2.99B 3.1477 3.1536
ckpt_val_2100.pt 2100 3.30B 3.1285 3.1354
ckpt_val_2300.pt 2300 3.62B 3.1116 3.1162
ckpt_best.pt 12200 19.19B 2.8559 2.8586
ckpt_final_20B.pt 12716 20.001B 2.8530 2.8664

Siblings, measured in the same pass on the same batches:

reference measured val_loss published (in-run)
cayley-small-2L-mlp_in-20B 3.1671 3.1584
cayley-small-3L-mlp_in-20B 3.1425 3.1330

Paired differences vs the siblings

Negative = dense is better. Every model saw byte-identical batches, so these are exact paired comparisons, not error bars added in quadrature (paired SEM Β±0.0004).

dense ckpt vs cayley-small-2L (3.1671) vs cayley-small-3L (3.1425)
ckpt_val_1900 βˆ’0.0195 (45Οƒ better) +0.0052 (13Οƒ worse)
ckpt_val_2100 βˆ’0.0387 (86Οƒ better) βˆ’0.0140 (33Οƒ better)
ckpt_val_2300 βˆ’0.0556 (111Οƒ better) βˆ’0.0309 (65Οƒ better)
ckpt_final_20B βˆ’0.3141 (245Οƒ better) βˆ’0.2894 (231Οƒ better)

Note ckpt_val_1900 clears 2L but does not clear 3L. Pick the checkpoint your comparison requires from this table.

ckpt_final_20B.pt is also better than ckpt_best.pt by 0.0029 (110Οƒ) despite the name: ckpt_best was selected by a noisy 4.9M-token in-run eval that happened to dip at iter 12200. Prefer ckpt_final_20B.pt for everything; ckpt_best.pt is kept only for provenance.

How these numbers were measured

evals/language_modeling/eval_val_loss.py over the entire FineWeb-Edu val split β€” contiguous non-overlapping windows, bf16 autocast, batch 16 Γ— 1024, fineweb-edu-25B, seed 0.

quantity value
tokens per model 25,161,728 (whole val split)
batches per model 1,536, byte-identical across all models
absolute SEM (single model) Β±0.0045
paired SEM (difference of two models) Β±0.0004

The paired SEM is ~13Γ— tighter because shared passage difficulty cancels. Quote the paired differences.

Two reasons the run log disagrees with this table:

source of disagreement effect
In-run evals are master-rank only, eval_iters Γ— bs Γ— seq_len = 4.9M tokens regardless of world size; adjacent evals wobble ~0.005 nats. --save-at-val triggers inherit that noise.
best_val_loss inside a checkpoint is the run's best, not that checkpoint's val. Meaningless to difference against a reference ckpt.pt saved at a different iter.

Measured on this protocol, dense sits ~0.0025 nats below its in-run trigger, while the cayley siblings sit ~0.011 above their published numbers. The cayley siblings' published numbers are in-run values too, so use the measured column for any cross-model claim and do not mix the two β€” a ~0.01 nat protocol artifact otherwise lands inside the very gap being resolved.

One caveat we cannot yet separate: the cayley path must run bf16 through this loader (it builds the backbone fp32 but forces the SAE to bf16 + triton), so its offset could be protocol or genuine bf16 sensitivity in top-k selection. Dense is bf16-insensitive here β€” its fp32 and autocast runs agree to 0.0002.

Alignment tax

Equal budget (20B tokens both sides):

pair dense cayley gap
vs 2L 2.8530 3.1671 0.314 nats
vs 3L 2.8530 3.1425 0.289 nats

Token efficiency β€” where dense first reaches each sibling's measured val, interpolated on the in-run eval curve shifted by the measured βˆ’0.0025 protocol offset:

sibling its measured val dense crossing tokens tax
2L 3.1671 iter ~1683 2.65B ~7.6Γ—
3L 3.1425 iter ~2021 3.18B ~6.3Γ—

Both inside the <15Γ— target. Eval spacing (100 iters = 157M tokens) caps resolution, so treat as two significant figures. Note the large chassis gives ~3.5Γ— on the same construction (markhenry/vanilla-large-20B) β€” the ratio is not a constant across scale.

Corrections to earlier versions of this card / report.md

claim (earlier) corrected
iter 1900 beats 2L by 0.0048 β€” "a statistical tie" beats by 0.0195 at 45Οƒ β€” not a tie
iter 2300 beats 2L by 0.042, 3L by 0.017 0.0556 and 0.0309
iter 2300 is the 3L match iter 2100 is the first to clear 3L
tax 6.9Γ— (2L) / 5.7Γ— (3L) 7.6Γ— / 6.3Γ—
ckpt_best is the run's best model ckpt_final_20B is better by 0.0029 (108Οƒ)

All five corrections move the same way: measured consistently, the dense baselines are stronger than the in-run numbers implied, so the alignment tax is larger. That is the conservative direction for the interpretability claim.

Architecture and training

12 layers, 8 heads, d=1024, block_size 1024, learned positional encoding, RMSNorm (affine), no bias, vocab 50304, 202.53M params β€” identical to the cayley-small siblings, which add buffers but no nn.Parameters.

Muon + AdamW lockstep 1.2e-2 (min 1.5e-4), linear_warmdown wf=0.9, warmup 200, tokens/iter = 32 Γ— 1024 Γ— 48 = 1,572,864 β†’ 12,716 iters. FineWeb-Edu sample-100BT, GPT-2 tokenizer. 2Γ— H200, 8h32m, ~695k tok/s. Wandb 9iezcto0.

--n-head 8 must be passed explicitly: train.py arch defaults are mode-dependent, so sparsity_mode=none at d=1024 otherwise resolves n_head=12 and 1024 % 12 != 0 asserts. The cayley siblings hit the cayley default of 8.

Also in this repo: report.md, eval_curve.csv (full in-run eval trajectory), train.log, and the training script.

Loading

import torch
ck = torch.load("ckpt_val_2100.pt", map_location="cpu", weights_only=False)
ck["iter_num"]                              # 2100
cfg, sd = ck["model_config"], ck["model"]   # GPTConfig fields, state dict

Checkpoints carry optimizer_states, so they are resumable, not inference-only.

Siblings


Re-evaluation and card by Claude Code. Training run and report.md predate it; where they disagree, the corrections table above states why.

Downloads last month
97
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Dataset used to train markhenry/vanilla-small-20B