Download docs/LAST_ATOM_DROPOUT.md from thefinalboss/atom-ai: direct link, hf CLI and curl.
- Browser
- Download file 7.51 kB
-
https://huggingface.co/thefinalboss/atom-ai/resolve/main/docs/LAST_ATOM_DROPOUT.md
- Command line
-
hf download hf://thefinalboss/atom-ai/docs/LAST_ATOM_DROPOUT.md
-
curl -L -o LAST_ATOM_DROPOUT.md https://huggingface.co/thefinalboss/atom-ai/resolve/main/docs/LAST_ATOM_DROPOUT.md
last_atom dropout — 2026-09-28
English. Numbers. No fluency claim.
Problem
Under field_obligatory_hard + --last-atom-readout the byte-tick hard logits are
logits = obl·α_MLP(a_hat) + 0.3·frozen_JL(a_hat) + payload + S·last_atom(last_byte, prev_byte, φ)
Audit: teacher-forced CE/val is carried by the last_atom term (bigram + phase
shortcut); the field (α) path contributes little. Measured here on the b4828 start tip
(4868k): val CE 0.401 normal vs 6.12 with last_atom zeroed at eval — worse than
uniform (ln 256 = 5.55). The field path alone is not even a unigram model. In free-run
chat the model falls into attractors (Bonne, Oui,,, Peut--).
Already falsified: fixed/adaptive last_atom_scale S (letter soup), field_hard_couple
S=0.25/1.0 (W barely trains), free-run-aux (brief diversity, then collapse).
Lever (opt-in, default OFF)
--last-atom-dropout P # default 0.0 = exact current behavior (no RNG draw)
Training only (module.training and grad enabled). Each surface forward is one
byte-tick position. With probability P that position's la_byte term is set to 0
(per-position Bernoulli; no inverted-dropout rescale). On those positions CE has to be
carried by α-MLP + frozen JL. The flag is ignored in eval, generation, validation, and
no-grad predictions. So efference's own-byte pick still uses the full model, the same way
generation does.
src/atom_native.py:AtomSurfaceHead.last_atom_dropout(saved in checkpoint config, restored on load as provenance). Also adds runtime-onlylast_atom_force_off(not saved), a diagnostic that zeroesla_bytein any mode.tools/run_atom_native.py:--last-atom-dropout. CLI wins after--resume, using the same pattern asfield_loss_weightandlast_atom_scale. It is recorded inatomization_stats/run_metrics.test/test_last_atom_dropout.py:- P=0 gives bit-identical logits and draws no global RNG.
- P=1 in train mode gives exactly the no-last_atom logits.
- Eval and no-grad are unaffected.
- P=0.5 is a per-position Bernoulli (~50%).
force_offworks.- The value survives a checkpoint roundtrip.
- Diagnostics:
tools/eval_last_atom_ablation.pyrebuilds the exact stream-ring val ofrun_atom_nativeand reports CE normal vslast_atom-zeroed.tools/chat_seeds_probe.pyruns the coherence-probe prompts/params with fixed torch seeds.
Probe (+8k, P=0.5)
Resume: atom_native_step_4868000_d32_ms1M_lrd_b4828.pt. This was the newest b4828 tip at probe start,
2026-09-28 13:45 ET. The recipe was the exact live one from scripts/train_until_coherent.sh:
stream-skip 4372000, d32, max-span-bytes 1, field-obligatory-hard, no-enable-merge,
no-payload-copy, last-atom-readout, efference-every 10, atom-flush-every 64,
episode-length 8000 --episode-reset, field-loss-weight 0.05, contrast 0, LR 1.5e-5 /
SLR 3.6e-5, seed 20260913, --allow-parallel-train. The only addition was --last-atom-dropout 0.5.
Output: checkpoints/byte_tick_ladrop/atom_native_step_4876000_d32_ms1M_lrd_b4828_ladrop.pt
(separate dir, so the live run_metrics.json was never touched). Baseline: the live
atom_native_step_4876000_d32_ms1M_lrd_b4828.pt (same start, same data, P=0).
Val (stream ring, 256 transitions — identical window for all three rows)
| ckpt | val loss (normal) | byte CE normal | byte CE last_atom zeroed |
|---|---|---|---|
| start 4868k (b4828) | 0.4010 | 0.3990 | 6.120 |
| live 4876k (P=0) | 0.4024 | 0.4003 | 6.195 |
| ladrop 4876k (P=0.5) | 0.5363 | 0.5309 | 3.399 |
Reference on the same window, from corpus counts: unigram CE ≈ 3.24, bigram CE ≈ 1.77, uniform 5.55
(val_window_baselines.json). The eval script reproduces run_metrics val exactly (0.4010 /
0.4024 / 0.5363).
Read it plainly:
- The field path alone went from worse-than-uniform (6.12) to about unigram level (3.40) in 8k steps. It learned the byte marginal. It did not learn context: 3.40 is still far above the bigram's 1.77.
- Normal val got worse, 0.401 → 0.536 (+0.13), because
last_atomnow only has half the positions to fit. - The live P=0 run moved field-alone CE the other way (6.12 → 6.20). Without pressure, the field path decays.
Chat
The coherence probe CLI takes only the first line of the response (sed … | head -1), with
unseeded sampling, T=0.8, top-k 12, --no-role-prime, 96 packets, max-length 100:
| prompt | live 4876k | ladrop 4876k |
|---|---|---|
| Bonjour, comment ça va ? | Bonne |
Bonne |
| Qui es-tu ? | Oui,, |
Bonne |
| Il était une fois | Oui,, |
Bonne |
Seeded probe (seeds 1,2,3 × T 0.6/0.8/1.0 × 3 prompts = 27 full replies per ckpt,
chat_seeds_*.txt):
| ckpt | unique replies /27 | mean distinct replies across the 3 prompts (same T, seed) | first words |
|---|---|---|---|
| start 4868k | 23 | 2.56 | Oui,, 9 / Je 9 / Peut-- … |
| live 4876k | 21 | 2.56 | Je 16 / Peut-- … |
| ladrop 4876k | 15 | 1.67 | Je 27/27 |
Example, T=0.8 seed=1, same reply for all three prompts on ladrop:
'Je …\nsoirends …\nAsssistant:::::::::::::::::::O \nuurrraais'.
Chat got worse. Replies depend less on the prompt and always open with Je, which fits a field
path that learned only the unconditional marginal and now biases every opening.
Other observations
- Train-log
field=96.0 rms=3.0 scale≈0.999on both runs: α sits pinned at thefield_max_rms=3.0clamp for most of each episode. A saturated field can carry little position-specific information. This is a plausible reason the field path tops out at unigram. - Median train loss: live 0.039, ladrop 2.98 (half the positions have no shortcut).
Verdict
P=0.5 for 8k steps is a technical PASS, not a fluency lever yet. It proves the field path can be pushed to carry probability mass (field-alone CE 6.12 → 3.40), but what it learned is the marginal, not context. Chat is less prompt-conditioned. Normal val is +0.13 worse.
Next (not done here)
- Longer P=0.5 run (≥40k) tracking field-alone CE. If it stays near unigram (~3.2), the α state holds no usable context, and the bottleneck is upstream (saturated field at the RMS clamp, α features), not the readout.
- P=1.0 for 8k steps is a clean "field-only" ceiling test. It matches P=0.5 on field-alone CE if the field
is capacity-limited. Do not chat-evaluate it with
last_atomon (train/eval mismatch). - Only if field-alone CE clearly beats bigram (≲1.8): consider a stacked recipe (P anneal 0.5→0.2).
Artifacts
docs/artifacts/last_atom_dropout/: val_ablation.{json,txt}, val_window_baselines.json,
chat_seeds_{start_4868000,live_4876000,ladrop_4876000}.{json,txt},
gen_coherent_4876000_{b4828,ladrop}.txt, run_metrics_*, train_ladrop.log,
yield_to_live.py + measure.sh (see CPU note).
CPU note (parallel probes)
The live trainer runs torch with 8 OMP threads that busy-wait. Any other busy process on
one core cut live throughput from about 77 to about 2 steps/s (measured with SIGSTOP on and off). The probe
and evals were therefore run single-threaded (OMP_NUM_THREADS=1) under
yield_to_live.py, which SIGSTOPs only the probe's own process group while the live chunk is past its
single-threaded stream-skip phase. The live loop was never signalled.