File size: 20,583 Bytes
5c6c847 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | ---
license: apache-2.0
language:
- en
tags:
- zeropoint
- zerocg
- numpy
- from-scratch
- sequence-modeling
- memory-slots
- linear-attention
- research
pretty_name: ZeroPoint
---
# ZeroPoint — a new, from-scratch framework for sequence modeling
**Status: v0 research prototype (November 2026). This is a brand-new framework: it is not a
fine-tune, not a wrapper around PyTorch / `transformers`, and not a derivative of an existing
released model. Both the framework and the architecture are implemented here from scratch,
in pure Python + NumPy.**
ZeroPoint is two things:
1. **ZeroCG** — a small deep-learning framework written from scratch: `Tensor` with
reverse-mode automatic differentiation, `nn` layers, AdamW (checkpointable), and
matrix-multiply FLOP counting. Dependencies: Python 3 + NumPy. Nothing else.
2. **ZeroPoint** — a sequence architecture that replaces self-attention with a set of
**memory slots that forget at different, learnable speeds**. Training uses a
**chunked-parallel** form (chunk = 32); inference uses a **per-character recurrence**
whose state size is fixed and independent of text length, and it needs **no positional
encoding**.
**This repository contains no pretrained weights.** It is an architecture + framework
release, together with the full experiment suite that compares ZeroPoint against a
GPT-style Transformer baseline at ~115k parameters and a character level. A separate
1.4M-parameter model trained on a private corpus (internal name *ZeroX*) is **not** part
of this release, and neither are its weights, corpus, or training runs.
---
## TL;DR — the measured comparison
On the only head-to-head experiment (same data, same parameter budget, same training
recipe, same evaluation), **ZeroPoint and the Transformer are statistically tied** under
the project's own "difference > 2× seed std" rule. We do **not** claim ZeroPoint is better.
| model | params | val loss (nats/char, 3 seeds) | matmul FLOPs/char @T=64 | inference state @64 / @1024 / @4096 (floats) |
|---|---|---|---|---|
| Transformer (learned PE) | 116,576 | 1.5452 ± 0.0100 | 241,664 | 16,384 / 262,144 / 1,048,576 |
| Transformer (sinusoidal PE) | 112,480 | 1.5271 ± 0.0083 | 241,664 | 16,384 / 262,144 / 1,048,576 |
| **ZeroPoint** | **115,240** | **1.5214 ± 0.0134** | **232,448** | **2,048 / 2,048 / 2,048** |
- ZeroPoint − Transformer = 0.0238; 2 × max seed std = 0.0268 → **ratio 0.89, not
significant**. ZeroPoint − Transformer(sin) = 0.0057 → ratio 0.21, not significant.
- The transformer's KV cache is **8×** ZeroPoint's state at 64 characters, **128×** at
1,024 characters and **512×** at 4,096 characters. ZeroPoint's state is 2,048 floats
(8 KiB in fp32) at any length.
- The Transformer's per-character matmul cost grows with context (2,306,048 FLOPs/char at
4,096) while ZeroPoint's stays ~constant (234,464). **Wall-clock speed was not measured**
— this release ships FLOP counts, not throughput numbers.
Read [**Comparison conditions**](#comparison-conditions-read-before-quoting-any-number)
before quoting any number, and [**Limitations**](#limitations) before drawing conclusions.
---
## What is actually new (and what is not)
**New code.** `zerocg/` is a self-contained NumPy implementation: reverse-mode autograd,
layers, AdamW, checkpointing, FLOP counting. `models/zeropoint.py` is the architecture
implementation. Neither depends on PyTorch; the early PyTorch reference scripts of the
project are not part of this release and were never used for the results.
**New combination.** The specific design — **per-slot learnable decay λ with a geometric
half-life initialisation (1.5 → 64 characters) + softmax competition when writing +
a write-strength gate + chunked-parallel / recurrent dual form + no positional encoding +
learnable initial slot state** — is, to our knowledge, a new combination. It is the object
of study here.
**Not new.** Every individual ingredient has prior art, and the design document says so:
memory networks / Neural Turing Machines (soft read-write memory), linear attention
(Katharopoulos et al., 2020 — parallel/recurrent dual form), RetNet (Sun et al., 2023 —
decayed recurrence without positional encoding), and Mamba / state-space models (fixed-size
recurrent state). This work makes **no priority claim** and is not "the first" anything.
It is also not a claim that memory slots are generally better than attention: at this scale
they tie.
---
## Comparison conditions (read before quoting any number)
Everything below is what the two sides of the comparison actually shared, measured on
**2026-10-11** (head-to-head and ablation) and **2026-10-18** (length re-evaluation).
| item | setting |
|---|---|
| Corpus | ASCII-only Python standard-library `.py` source, **1,558,395** characters, vocabulary **96** |
| Split | contiguous 90 % train / 10 % validation |
| Task | character-level next-character prediction |
| Models | width 64, 2 layers, 4 heads (D = 16), MLP hidden 256 (4×), Pre-LN, GELU, no dropout, no weight tying |
| ZeroPoint specifics | 16 slots/head, initial half-lives geometric 1.5→64 chars, learnable λ and s0, chunk 32, no positional encoding |
| Context length | 64 characters (training and short-context eval) |
| Batch | 32 sequences × 64 characters = 2,048 chars/step |
| Steps | 2,000 (about 2 minutes per model on one CPU core) |
| Optimizer | AdamW β = (0.9, 0.999), weight decay 0.01, gradient clip 1.0 |
| LR schedule | 100-step warmup, cosine decay to 10 % |
| LR selection | per model: sweep {1e-3, 3e-3, 6e-3} on seed 0, take the best for seeds 1–2; all three models selected 6e-3 |
| Seeds | 0, 1, 2 (seed controls initialisation and data order) |
| Evaluation | mean cross-entropy over 40 fixed validation batches × 32 sequences × 64 chars (seed 999); mean ± sample std over 3 seeds |
| Hardware | one Apple Silicon Mac, CPU only, NumPy float32 — no GPU |
| Data used | only the reports in `experiments/`; the numbers below were independently re-derived from saved checkpoints where possible |
**Not controlled / things this comparison does not tell you:**
- **One corpus, one domain, one split.** Source code is not natural language. No downstream
tasks, no instruction following, no reasoning evals — only validation loss.
- **Tiny scale.** 115k parameters, 2 layers, 64-char context, 2,000 steps. Nothing here
extrapolates to large models or long training.
- **The baseline is a minimal GPT-style decoder** with learned or sinusoidal positional
encoding, Pre-LN and GELU. It is not tuned beyond a 3-value LR sweep; no RoPE/ALiBi, no
dropout, no weight decay tuning.
- **3 seeds only**, and the LR is selected on seed 0, which is also included in the 3-seed
mean (a winner's-curse of ≤ ~0.01 nats/char; the same protocol was used for all models).
- **Transformer checkpoints were not saved**, so the Transformer rows cannot be re-derived
from artifacts — they rest on the original report. The ZeroPoint side *was* re-derived
bit-for-bit (see [Data verification](#data-verification)).
- **No wall-clock or memory benchmark.** FLOPs count matrix multiplications only; CPU
wall-clock is dominated by Python overhead and would not be a meaningful comparison.
- **Length extrapolation is evaluated at two different sample sizes** (32 sequences for
ZeroPoint, 8 for the sinusoidal Transformer — the baseline checkpoints are gone).
- **Ablation numbers use a different fixed LR** (3e-3) than the head-to-head (6e-3), so the
two tables are only internally comparable. Do not rank across them.
- **Exact recall is not measured** by this release: the recall experiment is inconclusive
because of its learning-rate configuration (see below), and must not be cited as an
architecture comparison.
---
## Head-to-head results
Protocol: identical width/layer/head/MLP configuration; parameter counts within ~4 %
(115,240 / 116,576 / 112,480); identical data, batches, seeds, optimiser, schedule and
evaluation; the only difference is the token-mixing layer (memory slots vs self-attention)
and the positional encoding.
```
validation loss (nats/char, lower is better; 3 seeds, 2000 steps, lr 6e-3)
ZeroPoint 1.5214 ± 0.0134
Transformer (sin) 1.5271 ± 0.0083
Transformer (learned) 1.5452 ± 0.0100
```
Per-seed ZeroPoint values: 1.5311 / 1.5307 / 1.5024. The largest gap (vs learned-PE
Transformer) is 0.0238 nats/char, **below the project's 2 × seed-std decision line of
0.0268**. Under a stricter standard-error criterion the gap would be ~2.5σ in ZeroPoint's
favour, but that is not the rule this project pre-registered, and 3 seeds is thin. **The
honest reading is: indistinguishable at this scale.**
### Inference state and compute
| | @64 chars | @1,024 chars | @4,096 chars |
|---|---|---|---|
| Transformer KV cache (floats) | 16,384 | 262,144 (128×) | 1,048,576 (512×) |
| ZeroPoint state (floats) | 2,048 | 2,048 | 2,048 |
| Transformer matmul FLOPs/char | 241,664 | 733,184 | 2,306,048 |
| ZeroPoint matmul FLOPs/char | 232,448 | 234,368 | 234,464 |
ZeroPoint's state is per-layer slots (2 layers × 4 heads × 16 slots × 16 dims) and is
independent of sequence length. This is the property the architecture was designed for: a
fixed-size recurrent state with no KV cache. It is **not** a claim that this is faster in
wall-clock time — see the limitations.
---
## Length behaviour (corrected 32-sequence evaluation)
Trained on 64 characters, then evaluated on 4,096-character sequences, in segments. 3
seeds, 32 validation sequences, same chunked-parallel algorithm for every model:
| positions | ZeroPoint (trained at 64) | ZeroPoint (trained at 256) |
|---|---|---|
| 0–63 | 1.4372 ± 0.0187 | 1.4741 ± 0.0117 |
| 64–255 (4× training length) | 1.4742 ± 0.0341 | 1.4486 ± 0.0098 |
| 256–1023 | 1.6617 ± 0.0234 | 1.5098 ± 0.0022 |
| 1024–4095 (64× training length) | 1.6932 ± 0.0305 | 1.5155 ± 0.0048 |
| far − near gap | **+0.2190 ± 0.0630** | **+0.0669 ± 0.0051** |
- At 4× the training length the loss rises by **0.037** nats/char; at 64× by **0.219**.
Extrapolation degrades gracefully, but it **does** degrade — do not quote "handles 4×
training length" without the +0.037.
- Training at 256 characters reduces the far−near gap 3.3× (to +0.067) but costs +0.036 at
64 characters. That run also changed batch size 32 → 8 (to keep 2,048 chars/step), so the
short-range cost is confounded with batch size; treat it as a hypothesis, not isolated.
- **Sinusoidal-PE Transformer collapses outside the training window:** 1.4512 within
0–63, then **4.6359** at 64–255 and **4.6057** at 256–1023, versus ln 96 = 4.5642, i.e.
chance level. This is an 8-sequence × 3-seed measurement, and the baseline checkpoints
were not retained, so it cannot be re-run with 32 sequences. It is a real, large effect,
but it is also a known weakness of plain sinusoidal absolute PE — **it is not evidence
that attention in general cannot extrapolate** (relative-position and NoPE models are
outside this comparison).
The earlier 8-sequence values (1.5550 / 1.6164 / 1.6410 / 1.7040) are kept only in the
archived report and are **superseded** by the table above; the 8-sequence sample was
noise-dominated (the same model scores 1.5550 vs 1.4372 on 0–63 depending on sample size).
---
## Ablations (fixed LR 3e-3; internally comparable only)
Each row changes one thing; parameter counts are matched within 1 % by adjusting the MLP
width; 2,000 steps, 3 seeds, same corpus. Base: **1.5500 ± 0.0073**. Decision line per
row: 2 × max(base std, row std). Δ is row − base (positive = worse).
| variant | Δ (nats/char) | Δ / threshold | verdict |
|---|---|---|---|
| uniform half-life init (no hierarchy) | **+0.0510** | 3.23× | clear: hierarchy matters |
| + sinusoidal positional encoding | **+0.0606** | 3.88× | clear: no PE is better here |
| λ frozen at initial values | **+0.0284** | 1.46× | clear: learnable decay matters |
| 1 head (64 dims, MLP widened to match) | **+0.0276** | 1.89× | clear: multiple heads matter |
| 8 heads (8 dims each, MLP narrowed) | +0.0173 | 1.19× | marginal / weak |
| 4 slots/head | −0.0034 | 0.20× | no significant difference |
| 32 slots/head | +0.0124 | 0.85× | no significant difference |
| no write-strength gate | +0.0022 | 0.15× | no significant difference |
| sigmoid write instead of softmax competition | −0.0013 | 0.09× | no significant difference |
At this scale, the things that **do** matter are the hierarchical half-life initialisation,
learnable λ, multiple heads and the absence of positional encoding. Slot count (4–32),
the write-strength gate, and write competition do **not** show a significant effect here.
Note the base loss differs from the head-to-head table because the ablation fixes
lr = 3e-3 (base 1.5500) while the head-to-head uses the selected lr = 6e-3 (1.5214).
---
## Exact recall: inconclusive — do not cite as an architecture comparison
The long-distance associative-recall experiment (`k1 v1 … kN vN [query kq] → vq`) was meant
to test the expected weakness of a fixed slot state. It produced **no usable conclusion**:
- With the original constant lr = 3e-3, both architectures plateau near 50 % on N=2
(chance is 6 % for 16 values) and near 16–23 % for larger N, after 20,000 steps. The
plateau is a **training-configuration** artefact, not an architecture property: with a
1e-3 cosine schedule, a Transformer trained on N=2 alone reaches **100 %** in 8,000
steps, and the diagnostic shows the loss ≈ ln 2 (50/50 hedge) trap.
- The mixed-N setup also dilutes the easy examples (N=2 is ~1/15 of the data), so the
experiment needs a curriculum and/or per-N weighting before it can compare architectures.
The 20,000-step table (Transformer 50/30/23/20/18 %; ZeroPoint-16 51/32/23/20/16 %;
ZeroPoint-32 49/31/24/20/17 %) is therefore **not** evidence that ZeroPoint is worse at
recall. It is a negative result about the experimental setup. A corrected re-run is future
work.
---
## Repository layout
```
zerocg/ from-scratch NumPy framework (autograd, nn, AdamW, FLOP counter)
models/zeropoint.py ZeroPoint architecture + the small char-LM harness used in the experiments
models/transformer.py GPT-style Transformer baseline (learned or sinusoidal PE)
experiments/ compare / ablation / recall (+ recall_diag), length/ema/slot diagnostics
experiments/results/ dated archives of the reports (kept, annotated as historical)
tests/ numerical gradient checks, parallel=recurrent equivalence, golden reference
docs/ZeroPoint.md design document (Chinese; structured after "Attention Is All You Need")
docs/ZeroPoint_EN.md English translation of the design document
docs/AUDIT.md independent verification notes for the numbers in this card
```
## Reproducing
```bash
pip install numpy
python tests/test_zerocg.py # framework self-checks
python tests/test_zeropoint.py # architecture + parallel/recurrent equivalence (~20 s)
cd experiments
python compare.py # ~35 min on one CPU core
python ablation.py # ~70 min
python recall.py # ~15 min; known inconclusive (see above)
```
Experiments are pure NumPy on CPU. `compare.py` / `ablation.py` write a dated archive to
`experiments/results/` and update the latest report in `experiments/`.
---
## Data verification
The numbers in this card were independently audited, not merely copied from the project's
own reports:
- The **ZeroPoint side was re-derived bit-for-bit** from the saved diagnostic checkpoints
(`val64 = 1.5214 ± 0.0134`, per-seed 1.5311 / 1.5307 / 1.5024; the 32-sequence segment
values above; the ablation parameter counts). The Transformer checkpoints were never
saved, so those rows could not be re-derived (stated as a limitation above).
- Corrections applied after the audit: the 8-sequence length-extrapolation table was
superseded by the 32-sequence re-evaluation; the "effective write slots 3.2 / 5.0"
number was a metric bug (entropy over a non-normalised, gate-scaled write distribution —
the normalised values are ~6–10 write slots and ~10 read slots out of 16) and is not
used; "precise recall is a known weakness" was downgraded to "inconclusive"; "one matrix
multiply, as fast as attention" was corrected to "chunked parallel, one matmul per chunk";
"~110k parameters" was corrected to the exact 115,240.
- See [`docs/AUDIT.md`](docs/AUDIT.md) for the claim-by-claim audit table.
---
## Limitations (summary)
- Small scale: 115k params, 2 layers, 64-char context, 2,000 steps, one source-code corpus.
- Only validation loss was measured; no downstream tasks, no generation-quality evaluation,
no scaling study.
- The baseline is a minimal GPT-style decoder, not a tuned Transformer; the comparison is
fair in configuration but does not represent "Transformers" in general.
- 3 seeds; the LR was selected on seed 0 (small selection bias).
- No wall-clock or memory measurements; FLOP counts only.
- Length extrapolation: ZeroPoint degrades +0.037 nats/char at 4× training length; the
sinusoidal Transformer's collapse is a known property of absolute PE, measured with only
8 sequences.
- Exact recall: inconclusive; needs a corrected training configuration.
- The framework is a research prototype, not a production framework: no GPU kernels, no
distributed training, no mixed precision.
---
## Citation
```bibtex
@misc{zeropoint2026,
title = {ZeroPoint: a from-scratch NumPy framework and a hierarchical memory-slot
sequence architecture},
author = {Holmes2011},
year = {2026},
howpublished = {\url{https://huggingface.co/Holmes2011/ZeroPoint}},
note = {v0 research prototype; architecture and framework release, no pretrained weights}
}
```
## License
Apache-2.0 (code and documentation). This repository contains **no model weights, no
training corpus, and no training runs** of the project's separate 1.4M-parameter model.
---
## 中文摘要
**ZeroPoint 是一个全新的框架,不是已有模型的封装、微调或衍生品。** 本仓库从零实现了两部分:
1. **ZeroCG**:纯 Python + NumPy 的深度学习框架 —— 反向自动求导、`nn` 层、AdamW、矩阵乘
FLOP 统计,不依赖 PyTorch。
2. **ZeroPoint**:用一组**遗忘速度可学习、按存储层级初始化**的记忆槽取代自注意力。训练用
**分块并行**(块长 32,块间串行传状态),推理用**逐字递推**,状态固定、与文本长度无关,
**不需要位置编码**。
**对比条件(引用任何数字前请先看)**:Python 标准库源码 1,558,395 字符、字符级、词表 96;
三个模型同宽 64 / 2 层 / 4 头 / MLP 256 / Pre-LN / GELU;上下文 64、batch 32、2000 步、
AdamW、100 步预热 + 余弦、学习率在 {1e-3, 3e-3, 6e-3} 里按种子 0 选(三者都选 6e-3)、
种子 0/1/2;验证 loss = 40 个固定 batch × 32 序列 × 64 字的平均交叉熵;单机 CPU、NumPy。
**主要结果**:
- 头对头验证 loss:ZeroPoint **1.5214 ± 0.0134**,Transformer **1.5452 ± 0.0100**,
正弦位置编码 Transformer **1.5271 ± 0.0083**。最大差 0.0238 < 2× 种子标准差 0.0268
→ **统计上没有差别,不声称 ZeroPoint 更好**。
- 推理状态:ZeroPoint 固定 2,048 个浮点数(8 KiB fp32);Transformer KV 缓存在第 64 字时
16,384(8×)、第 1024 字时 262,144(**128×**)、第 4096 字时 1,048,576(**512×**)。
- 长度外推:训练 64 字,4 倍长度 loss 升高 **0.037**,64 倍长度升高 **0.219 ± 0.063**;
正弦位置编码的 Transformer 出训练长度后崩到约 4.64(≈随机水平;只有 8 条序列的测量)。
- 消融:分层半衰期初始化(+0.051)、可学习 λ(+0.028)、多头(1 头 +0.028)、去掉位置编码
(+0.061)有明确作用;槽数 4~32、写强度门、写入竞争在该规模下**无显著差异**。
- 精确回忆:**无结论**(学习率配置问题),不能用来比较架构。
**本仓库不含训练权重**:项目里另一个 1.4M 参数的模型(内部名 ZeroX)及其语料、训练运行
都不在本次发布范围内。
许可证:Apache-2.0。设计文档中文原文见 [`docs/ZeroPoint.md`](docs/ZeroPoint.md),
英文版见 [`docs/ZeroPoint_EN.md`](docs/ZeroPoint_EN.md)。
|