Upload docs/ClaudeReport_session_2026-09-15_680m_tied_head_fix_and_phase1_extension.md with huggingface_hub
Browse files
docs/ClaudeReport_session_2026-09-15_680m_tied_head_fix_and_phase1_extension.md
CHANGED
|
@@ -1,82 +1,169 @@
|
|
| 1 |
-
# 2026-09-15 - 680M tied-head bf16 fix,
|
| 2 |
|
| 3 |
-
Workspace:
|
| 4 |
-
Files: Scripts/Blutrain/bluscriptCP.cpp, p1_680m.sh,
|
|
|
|
|
|
|
| 5 |
|
| 6 |
-
## Why this session
|
| 7 |
|
| 8 |
-
Two long-context extension runs on the 1.06B
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
processing itself stayed intact.
|
| 14 |
-
|
| 15 |
-
Working hypothesis: the 1.06B is undertrained at 0.99 tok/param (Chinchilla is 20),
|
| 16 |
-
so copying is the cheaper solution than retrieval and the model falls into it. That
|
| 17 |
-
predicts a better-trained base has a higher ceiling. varybatch is a 680M at
|
| 18 |
-
10.5 tok/param -- the test.
|
| 19 |
|
| 20 |
## The bug that had to be fixed first
|
| 21 |
|
| 22 |
-
varybatch scored NLL 12.
|
| 23 |
-
a PyTorch reference
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
before: transpose -> to_compute(bf16) [strided cast, silently wrong]
|
| 28 |
-
after: to_compute(bf16) -> transpose -> contiguous()
|
| 29 |
-
|
| 30 |
-
Never surfaced before because every model trained in this repo uses weight_tying=0,
|
| 31 |
-
which takes the separate contiguous lm_head path. bluscript_zero_ckpt.cpp -- the
|
| 32 |
-
trainer that actually produced varybatch -- documents the same hazard in a comment
|
| 33 |
-
about contiguous() and trans_b.
|
| 34 |
-
|
| 35 |
-
Confirmed by bf16 mask bisection: mask=15 gave 12.1295, mask=7 (head in fp32) gave
|
| 36 |
-
3.0496. After the fix the 680M scores 3.0497 (PyTorch reference: 3.0793) and the
|
| 37 |
-
1.06B is unchanged at 3.1719 (was 3.1717), so no regression.
|
| 38 |
-
|
| 39 |
-
Result: the 680M beats the 1.06B on identical data, 3.05 vs 3.17.
|
| 40 |
-
|
| 41 |
-
## Phase-1 run (launched, in progress)
|
| 42 |
-
|
| 43 |
-
2x H100 80GB, cp=2. Parent varybatch step 3400.
|
| 44 |
-
|
| 45 |
-
window 16,384 via YaRN SCALE=4 x ORIG_MAXPOS=4096 (must equal CP_T exactly)
|
| 46 |
-
data Data_Loader/Data/p1mix, 640,009,970 tokens, b3 50 / b2 30 / b1 20
|
| 47 |
-
steps 1,200 of 1,220 usable at global_batch 524,288 (grad_accum 32)
|
| 48 |
-
WSD warmup 100 / stable 1,098 / tail 2
|
| 49 |
-
measured 50,117 MB of 81,559 MB per card, 7.83 s/step, ETA 2h34m
|
| 50 |
-
|
| 51 |
-
Both YaRN inputs were verified against the trainer that produced the checkpoint
|
| 52 |
-
rather than assumed: rope_theta 500000 (bluscript_zero_ckpt.cpp:121 and config.md)
|
| 53 |
-
and context_length 4096. The trainer prints a "provenance UNVERIFIED" warning only
|
| 54 |
-
because no sidecar file exists to compare against; the values are correct.
|
| 55 |
|
| 56 |
-
|
| 57 |
-
|
| 58 |
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
|
|
|
|
|
|
| 62 |
|
| 63 |
-
##
|
|
|
|
|
|
|
| 64 |
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 76 |
|
| 77 |
## Open
|
| 78 |
|
| 79 |
-
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
-
|
|
|
|
|
|
|
|
|
| 1 |
+
# 2026-09-15 / 2026-09-16 - 680M tied-head bf16 fix, phase-1 context extension (4k -> 16k), and the baseline correction
|
| 2 |
|
| 3 |
+
Workspace: Context_Parallelism (GPU box, now torn down) / CP (laptop)
|
| 4 |
+
Files: Scripts/Blutrain/bluscriptCP.cpp, p1_680m.sh, p2_680m.sh, p1_shipper.sh,
|
| 5 |
+
p1_finish.sh, p1_eval2.sh, p1_plots.sh, mk_p1_plots.py, dl_p23.sh, mix_buckets.py,
|
| 6 |
+
run_longeval.sh, HANDOFF_H200_32K.md
|
| 7 |
|
| 8 |
+
## Why this session existed
|
| 9 |
|
| 10 |
+
Two long-context extension runs on the 1.06B collapsed, both at roughly 80 percent
|
| 11 |
+
of a cumulative b5 epoch, tracking cumulative long-document exposure rather than
|
| 12 |
+
data composition. Working hypothesis: the 1.06B is undertrained at 0.99 tok/param,
|
| 13 |
+
so copying is a cheaper solution than retrieval. That predicts a better-pretrained
|
| 14 |
+
base has a higher ceiling. varybatch is a 680M at 10.5 tok/param - the test.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
## The bug that had to be fixed first
|
| 17 |
|
| 18 |
+
varybatch scored NLL 12.1295, worse than uniform. Bisected with CP_DUMP_ACTS
|
| 19 |
+
against a PyTorch reference. GPT::forward's weight_tying path cast the TRANSPOSED
|
| 20 |
+
embedding matrix to bf16; the cast ignores strides, so the tied head multiplied a
|
| 21 |
+
garbled weight.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
+
before: transpose -> to_compute(bf16) [strided cast, silently wrong]
|
| 24 |
+
after: to_compute(bf16) -> transpose -> contiguous()
|
| 25 |
|
| 26 |
+
Confirmed by mask bisection: mask=15 gave 12.1295, mask=7 (head in fp32) gave
|
| 27 |
+
3.0496. After the fix the 680M scores 3.0497 (PyTorch reference 3.0793) and the
|
| 28 |
+
1.06B is unchanged at 3.1719 (was 3.1717). Never surfaced before because every
|
| 29 |
+
model trained in this repo uses weight_tying=0 and takes the separate contiguous
|
| 30 |
+
lm_head path. bluscript_zero_ckpt.cpp documents the same hazard in a comment.
|
| 31 |
|
| 32 |
+
## Phase 1: 4k -> 16k
|
| 33 |
+
|
| 34 |
+
2x H100, cp=2, parent varybatch step 3400.
|
| 35 |
|
| 36 |
+
window 16,384 via YaRN SCALE=4 x ORIG_MAXPOS=4096
|
| 37 |
+
data p1mix, 640,009,970 tokens, b3 50 / b2 30 / b1 20
|
| 38 |
+
steps 1,200 of 1,220 usable at global_batch 524,288 (grad_accum 32)
|
| 39 |
+
measured 50,117 MB of 81,559 per card, 7.83 s/step, clean finish
|
| 40 |
+
loss 2.5969 @step 99 -> 2.6006 @step 1199 (i.e. flat)
|
| 41 |
+
val 2.8726 -> 2.8560 over the whole run
|
| 42 |
+
|
| 43 |
+
rope_theta 500000 and context_length 4096 were verified against
|
| 44 |
+
bluscript_zero_ckpt.cpp:121 and .mdfiles/config.md - the trainer's
|
| 45 |
+
"provenance UNVERIFIED" warning only means no sidecar exists to compare against.
|
| 46 |
+
|
| 47 |
+
## Result: a null
|
| 48 |
+
|
| 49 |
+
niah_single, N=100, greedy, haystack b2_8192_16384/val_shard_00000.bin.
|
| 50 |
+
|
| 51 |
+
prompt len base680 (untrained, zero-shot YaRN) p1final (1200 steps)
|
| 52 |
+
8,192 84 77
|
| 53 |
+
16,360 40 42
|
| 54 |
+
|
| 55 |
+
Both deltas sit inside the +-9-13pp Wilson band at N=100. 1,200 steps and 2.6 GPU
|
| 56 |
+
hours changed nothing measurable. The flat loss predicted this.
|
| 57 |
+
|
| 58 |
+
Depth breakdown at 16,360 (both models): 0 percent when the needle is at the start,
|
| 59 |
+
100 percent when it is at the end, monotonic in between. That is recency, not
|
| 60 |
+
retrieval, and training did not move it.
|
| 61 |
+
|
| 62 |
+
## Four explanations I gave, three of them wrong
|
| 63 |
+
|
| 64 |
+
1. LEARNING RATE - WRONG. I claimed phase 1 ran at 1.8e-4 against the 1.06B's
|
| 65 |
+
3e-4. CP_MAX_LR and CP_MIN_LR appear ZERO times in bluscriptCP.cpp; max_lr is
|
| 66 |
+
hardcoded 6e-4 at line 151. Every run in this project, both models, every
|
| 67 |
+
context stage, trained at 6e-4 x REWARMUP_PEAK 0.3 = 1.8e-4. The scripts that
|
| 68 |
+
set CP_MAX_LR=1e-3 were setting a variable the trainer never reads, and
|
| 69 |
+
ext64k_b5.sh:23 already said so. THIS IS THE SAME ERROR I MADE AND LOGGED ON
|
| 70 |
+
2026-09-09 ("my 3.0e-4 came from assuming max_lr=1e-3").
|
| 71 |
+
|
| 72 |
+
2. TOO FEW LONG TOKENS - WRONG. At the same 524,288 global batch, phase 1 saw
|
| 73 |
+
314,572,800 b3 tokens; mix64k saw 188,743,680. Phase 1 had 1.67x MORE.
|
| 74 |
+
|
| 75 |
+
3. TRUNCATION - BACKWARDS. b3 documents are 16,384-32,768 tokens, at or above the
|
| 76 |
+
16,384 window, so every phase-1 window is contiguous single-document text. That
|
| 77 |
+
is the good case and the reason b3 was chosen. The 65,536-window runs are the
|
| 78 |
+
ones that packed several b3 docs plus boundaries per window.
|
| 79 |
+
|
| 80 |
+
4. BASELINE - WRONG, AND MY CORRECTION WAS ALSO PARTLY WRONG. I reported 42 as
|
| 81 |
+
"far below the 1.06B's 65-70", but ext64k had been through three extension
|
| 82 |
+
stages. The stage analogue is the 1.06B's own 16k ladder: l1/l2/l3 tied at 35.0
|
| 83 |
+
at 16,360, best l3long2k (run17 step 2000) 43.0. So 42 is at the 16k-stage best.
|
| 84 |
+
But then the comparison table I built to show that was itself invalid, because
|
| 85 |
+
eval directories used DIFFERENT haystacks.
|
| 86 |
+
|
| 87 |
+
## Haystack tiering (the reason cross-run eval comparison is unsafe here)
|
| 88 |
+
|
| 89 |
+
val_shard_00000.bin mix64k_1200, mixcont/cliff1400 <- same as phase 1
|
| 90 |
+
b2val_haystack.bin decide, ext32k, ext64k <- probably same, UNVERIFIED
|
| 91 |
+
b3val_haystack.bin lenb
|
| 92 |
+
flux_val_000000.bin newck, longeval_yarnfix (N=50)
|
| 93 |
+
|
| 94 |
+
Proof this matters: checkpoint blumodelcp_run2_step_400 scores 78 under lenb and
|
| 95 |
+
62 under decide - same weights, 16pp apart, different haystack. The haystack files
|
| 96 |
+
are not on HF, so b2val_haystack.bin cannot be byte-checked against
|
| 97 |
+
val_shard_00000.bin despite the suggestive name.
|
| 98 |
+
|
| 99 |
+
Only mix64k (83 @8192 / 70 @16360) and mixcont (80 / 54) are certainly comparable
|
| 100 |
+
to phase 1.
|
| 101 |
+
|
| 102 |
+
## What actually stands
|
| 103 |
+
|
| 104 |
+
- The 680M base reaches 84 @8192 zero-shot, equal to the fully-laddered mix64k's
|
| 105 |
+
83 on the SAME haystack. That is the one real signal for the higher-ceiling
|
| 106 |
+
hypothesis.
|
| 107 |
+
- At 16,360 the 680M sits at 40-42, at the level of the 1.06B's 16k-stage ladder
|
| 108 |
+
and well below its fully-laddered 65-70.
|
| 109 |
+
- 1,200 steps of training added nothing at either length.
|
| 110 |
+
- Therefore: the hypothesis is neither confirmed nor refuted. Phase 1 did not fail
|
| 111 |
+
to reach a ceiling; it failed to move at all.
|
| 112 |
+
|
| 113 |
+
## YaRN rule correction (HANDOFF_H200_32K.md)
|
| 114 |
+
|
| 115 |
+
The doc said ORIG_MAXPOS must be "the length the weights were ACTUALLY trained at".
|
| 116 |
+
Right for a single extension, wrong for a ladder. build_rope_cache takes rope_theta
|
| 117 |
+
and is rebuilt from base theta every run, so SCALE never composes with the previous
|
| 118 |
+
stage. Re-basing freezes interpolation at theta/2 while the window doubles:
|
| 119 |
+
|
| 120 |
+
stage as-run (re-based) interp last tok -> virtual ramp
|
| 121 |
+
16k 4 x 4096 theta/4 4,096 [14,32]
|
| 122 |
+
32k 2 x 16384 theta/2 16,384 [21,39]
|
| 123 |
+
64k 2 x 32768 theta/2 32,768 [24,42]
|
| 124 |
+
|
| 125 |
+
stage corrected interp last tok -> virtual ramp
|
| 126 |
+
16k 4 x 4096 theta/4 4,096 [14,32]
|
| 127 |
+
32k 8 x 4096 theta/8 4,096 [14,32]
|
| 128 |
+
64k 16 x 4096 theta/16 4,096 [14,32]
|
| 129 |
+
|
| 130 |
+
find_dim(num_rot, L, head_dim, base) does not take scale, so the ramp moves only
|
| 131 |
+
when ORIG_MAXPOS moves. The 1.06B ladder followed the old rule from its 32k stage
|
| 132 |
+
on. This is NOT thought to be the collapse cause - a wrong cache is a static defect
|
| 133 |
+
while the collapse was progressive - but it plausibly lowered the ceiling.
|
| 134 |
+
|
| 135 |
+
## Operational errors this session
|
| 136 |
+
|
| 137 |
+
- The eval aborted in 49 s: run_longeval.sh defaults CP_DATA_ROOT to
|
| 138 |
+
Data_Loader/Data, which on that box held only subdirectories, and the trainer
|
| 139 |
+
builds a data loader even for pure generation ("no .bin shards found for split
|
| 140 |
+
train"). Fixed with GEN_DATA_ROOT.
|
| 141 |
+
- up() verified logs/upload.log against a file it was itself appending to, so it
|
| 142 |
+
always reported a mismatch. Now uploads a snapshot copy.
|
| 143 |
+
- A sed heredoc produced an EMPTY p2_680m.sh that still passed bash -n. test -s is
|
| 144 |
+
now checked alongside it.
|
| 145 |
+
- run_longeval.sh prefixes OUT with $PWD, so an absolute OUT becomes
|
| 146 |
+
".../Context_Parallelism//tmp/...". Caught by an N=2 smoke test before it cost a
|
| 147 |
+
second full cycle.
|
| 148 |
+
- I called the NLL position analysis a "copying fingerprint that explained why"
|
| 149 |
+
retrieval dropped. It does not explain it: NLL shape and retrieval ANTI-correlate
|
| 150 |
+
in that very data (the degraded model has the steeper context gain). The evidence
|
| 151 |
+
for degradation is NIAH alone; the NLL work ruled out broken long-range
|
| 152 |
+
processing and showed where the loss gain sat, nothing more.
|
| 153 |
+
|
| 154 |
+
## State
|
| 155 |
+
|
| 156 |
+
Everything byte-verified on HF unparallelled/BluScriptCP: full resumable phase-1
|
| 157 |
+
checkpoint both ranks (11.2 GB), both plots, all eval CSVs and generations, every
|
| 158 |
+
script, corrected handoff doc. p2mix and p3mix built and verified to read shards
|
| 159 |
+
disjoint from phase 1 and from each other. p2_680m.sh written and refuses to run
|
| 160 |
+
without a completed phase 1. Phase 3 needs >= 4 GPUs (~115 GB at cp=2).
|
| 161 |
|
| 162 |
## Open
|
| 163 |
|
| 164 |
+
- Why training moved nothing. Remaining candidate: next-token loss on natural text
|
| 165 |
+
may not reward reaching backwards, so there is no gradient toward retrieval.
|
| 166 |
+
Untested.
|
| 167 |
+
- Whether b2val_haystack.bin == val_shard_00000.bin, which would widen the
|
| 168 |
+
comparable set to ext64k/ext32k/decide.
|
| 169 |
+
- CP_EVAL_PPL broken for weight_tying=1, deferred by decision.
|