Model card: recalibrate val bpb under upstream packing; document the token_bytes regeneration
Browse files
README.md
CHANGED
|
@@ -35,7 +35,7 @@ minimum validation bpb: 0.719042
|
|
| 35 |
| | value |
|
| 36 |
|---|---|
|
| 37 |
| parameters | 1,384,122,122 |
|
| 38 |
-
| min val bpb | 0.719042 |
|
| 39 |
| CORE | 0.2517 |
|
| 40 |
| train time | 110.74 min on 8xH100 80GB |
|
| 41 |
| throughput | 1,212 ms/step, 864,856 tok/sec (steps 20β99) |
|
|
@@ -49,19 +49,47 @@ DecoderStack tracks 0.2β1.4% behind through step 1000 (where the upstream base
|
|
| 49 |
stopped) while running ~6% faster per step (1,212 vs 1,291 ms/step). Full head-to-head in
|
| 50 |
[`logs/baseline_report.md`](logs/baseline_report.md).
|
| 51 |
|
| 52 |
-
β οΈ **but
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
in validation as in training. The direction of that bias has not been measured. Treat the
|
| 59 |
-
throughput numbers as the solid comparison and the bpb deltas as indicative.
|
| 60 |
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
Both numbers also deserve error bars: Karpathy's re-runs of an identical d24 config span
|
| 67 |
**0.0153 in CORE** (5 runs, mean 0.261), so our 0.2517 and that 0.2614 are inside each
|
|
@@ -77,6 +105,23 @@ one in `ChrisMcCormick/nanochat-varlen-d24-2026-03-22` β 31,474 of 32,759 merg
|
|
| 77 |
differ. Both are 32,768 tokens and both load without complaint, so nothing will warn you.
|
| 78 |
Pairing these weights with the wrong tokenizer produces garbage, not slightly-worse text.
|
| 79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
## Contents
|
| 81 |
|
| 82 |
```
|
|
|
|
| 35 |
| | value |
|
| 36 |
|---|---|
|
| 37 |
| parameters | 1,384,122,122 |
|
| 38 |
+
| min val bpb | 0.719042 (varlen packing, 10.5M val tokens β see the caveat below) |
|
| 39 |
| CORE | 0.2517 |
|
| 40 |
| train time | 110.74 min on 8xH100 80GB |
|
| 41 |
| throughput | 1,212 ms/step, 864,856 tok/sec (steps 20β99) |
|
|
|
|
| 49 |
stopped) while running ~6% faster per step (1,212 vs 1,291 ms/step). Full head-to-head in
|
| 50 |
[`logs/baseline_report.md`](logs/baseline_report.md).
|
| 51 |
|
| 52 |
+
β οΈ **but 0.719042 is not comparable to an upstream nanochat val bpb.** Upstream batches with
|
| 53 |
+
best-fit cropping β it fills each row with largest-doc-that-fits and crops a document to
|
| 54 |
+
finish the row, then attends causally across the whole row with no document isolation
|
| 55 |
+
(`cu_seqlens` appears nowhere in upstream `nanochat/gpt.py`). DecoderStack packs varlen and
|
| 56 |
+
isolates documents in validation as in training. Different truncation points, different
|
| 57 |
+
conditioning context: the two are not scoring the same predictions.
|
|
|
|
|
|
|
| 58 |
|
| 59 |
+
### Measured 2026-08-01: the packing gap is larger than the model gap
|
| 60 |
+
|
| 61 |
+
Re-measured this checkpoint under **upstream's own row packer**, driven with this repo's
|
| 62 |
+
tokenizer over the same pinned val shard and unwound into varlen batches whose `cu_seqlens`
|
| 63 |
+
sit on the row boundaries β so the model predicts exactly the tokens upstream would ask
|
| 64 |
+
for, with exactly the same context.
|
| 65 |
+
|
| 66 |
+
| packing | val tokens | bpb |
|
| 67 |
+
|---|---|---|
|
| 68 |
+
| upstream best-fit rows | 41.9M | **0.737183** |
|
| 69 |
+
| upstream best-fit rows | 10.5M | 0.735274 |
|
| 70 |
+
| varlen, document-isolated | 41.9M | 0.724316 |
|
| 71 |
+
| varlen, document-isolated | 10.5M | 0.720717 |
|
| 72 |
+
|
| 73 |
+
(all on the legacy `token_bytes` basis, for continuity with the numbers above; the
|
| 74 |
+
regenerated basis reads ~0.05% higher β see [β οΈ Tokenizer](#οΈ-tokenizer))
|
| 75 |
+
|
| 76 |
+
Three things follow, and they revise the comparison:
|
| 77 |
+
|
| 78 |
+
1. **Packing alone is worth ~0.0129 bpb** β same model, same shard, same budget. That is
|
| 79 |
+
*larger* than the gap between this model and its sibling release, so bpb must never be
|
| 80 |
+
cross-compared between the two packings.
|
| 81 |
+
2. **`ChrisMcCormick/nanochat-varlen-d24-2026-03-22` is ahead, not behind.** Its 0.724772
|
| 82 |
+
was measured under best-fit rows; the like-for-like number here is **0.737183**, so it
|
| 83 |
+
leads by ~0.0124 bpb. The raw headline figures (0.719042 vs 0.724772) pointed the other
|
| 84 |
+
way purely because of packing. It also trained with FP8 and a different 32k tokenizer,
|
| 85 |
+
so this is still not a controlled comparison β but it is now an honest one.
|
| 86 |
+
3. **The 10.5M val budget reads low.** Upstream's default is `--eval-tokens 80*524288` =
|
| 87 |
+
41.9M; this run used 10.5M, which comes in ~0.002β0.004 bpb optimistic rather than
|
| 88 |
+
merely noisier.
|
| 89 |
+
|
| 90 |
+
Reproduce: `agent-ops/stacks/2026-08-01_1241pm_d24-val-bpb-recalibration/`.
|
| 91 |
+
|
| 92 |
+
Throughput remains the clean comparison: 1,212 vs 1,291 ms/step, ~6% faster per step.
|
| 93 |
|
| 94 |
Both numbers also deserve error bars: Karpathy's re-runs of an identical d24 config span
|
| 95 |
**0.0153 in CORE** (5 runs, mean 0.261), so our 0.2517 and that 0.2614 are inside each
|
|
|
|
| 105 |
differ. Both are 32,768 tokens and both load without complaint, so nothing will warn you.
|
| 106 |
Pairing these weights with the wrong tokenizer produces garbage, not slightly-worse text.
|
| 107 |
|
| 108 |
+
### `token_bytes.pt` was regenerated 2026-08-01
|
| 109 |
+
|
| 110 |
+
bpb divides summed nats by summed BYTES, and the bytes-per-token table was built by
|
| 111 |
+
decoding each id to a Python `str` and measuring `.encode("utf-8")` β which corrupts every
|
| 112 |
+
token that is not valid standalone UTF-8 (a lone continuation byte round-trips through
|
| 113 |
+
U+FFFD and measures 3 bytes instead of 1). **191 of 32,768 ids** were affected here.
|
| 114 |
+
Upstream fixed the calculation in
|
| 115 |
+
[`2ce972a`](https://github.com/karpathy/nanochat/commit/2ce972a), but the fix lives in
|
| 116 |
+
`tok_train.py` and so only lands when a tokenizer is retrained β a released `token_bytes.pt`
|
| 117 |
+
keeps the stale values forever.
|
| 118 |
+
|
| 119 |
+
`tokenizer/token_bytes.pt` here is now the corrected table; `tokenizer/token_bytes_legacy.pt`
|
| 120 |
+
is the pre-fix one, kept so previously published numbers stay reproducible. Measured on this
|
| 121 |
+
model, the correction moves bpb by **+0.05%** (0.724316 β 0.724741 varlen at 41.9M), matching
|
| 122 |
+
upstream's estimate. `tokenizer.pkl` is untouched β encode/decode are unchanged, this is
|
| 123 |
+
purely the byte-accounting used by the metric.
|
| 124 |
+
|
| 125 |
## Contents
|
| 126 |
|
| 127 |
```
|