--- license: mit library_name: numpy tags: - plasticity - test-time-training - continual-learning - hebbian - tiny-models - numpy - from-scratch pipeline_tag: text-generation --- # gary-neuron-chat 🧠💬 **A tiny chatbot that learns the more you use it — on three timescales, in pure numpy.** Most models are frozen at deploy: every conversation starts from amnesia. gary-neuron-chat doesn't. It has a **plastic hippocampal memory** that learns *within* a conversation (it remembers what you told it earlier), and it **sleeps** between sessions to consolidate what it has seen into its weights — without forgetting how to speak English. The brain is a file (`brain.npz`) that **changes over time**. It is deliberately small and honest: a 1.1M-param, 8-layer dialogue cortex (gary-4-petite fine-tuned on real conversation) plus a **6,147-param** plastic memory. No transformers were retrained at test time on a GPU farm — this runs on a laptop, in numpy. ## The three timescales of "learning from use" | Timescale | Mechanism | Does it change weights? | What it gives you | |---|---|---|---| | **Fast** — within a conversation | Plastic **hippocampal memory**: a softmax-attention read over the whole conversation, scored by key-match + **surprise** + recency, that votes the remembered token into the cortex's logits | No — it's activations (like fast-weights / a KV cache) | Tell it "my dog is Buddy", chat about other things, ask later → it answers **Buddy** | | **Slow** — across sessions | **Sleep consolidation**: replays your buffered conversations mixed with base corpus (experience replay) and fine-tunes the cortex | Yes — the cortex evolves | Topics you discuss a lot get baked into the weights permanently | | **Episodic** (v3) — across sessions, no training | A **persistent episodic store**: declarative facts are encoded the moment you say them (surprise picks the value word), saved in `brain.npz`, retrieved by cue pattern-completion | No — it's a memory, not weights | Tell it your name today, restart tomorrow, ask — it answers. Recall survives the 128-token window AND program restarts | | **Persistent** | `brain.npz` = cortex weights + **episodic store** + replay buffer + age | — | The brain is a file that grows with use | This maps directly onto the research it's built from: **fast-weights / Test-Time Training** (a memory that adapts at inference — and is, in closed form, linear attention), **Titans**' insight that *surprising* tokens should be written more strongly, **Miconi's differentiable plasticity / Backpropamine** (training the rule that does the remembering), and **sleep-replay continual learning** (consolidate without catastrophic forgetting). ## How the plastic memory works The cortex is **frozen**. When you ask a question about yourself, the memory does a gated **pattern completion** (v2): 1. **Candidate memories** = declarative things you said (questions are not facts) whose content words overlap the cue — ask about your *name*, it considers turns about your *name*. 2. The **meta-trained attention** (`key·query + bN·surprise`, the cortex's hidden states as keys/query) selects *which* remembered moment to read. 3. The **value** inside that memory is found by **surprise**: the most unexpected content word is the one worth remembering ("gary" is the surprising part of "my name is gary"). 4. The recalled word is **copy-chained** token-by-token into the reply — multi-token values come out whole — then the reply wraps up. One recall per reply, and only for questions about *you* ("my", "I" — never "your"). If the fact has slid out of the 128-token window (v3): the **episodic store** answers instead. Each declarative turn was encoded at the moment it was said — content-word stems as the retrieval cue, a surprise-ranked candidate list as the values — so retrieval is cue overlap (Jaccard-style, newest wins ties) and the answer is the top-ranked candidate that isn't the cue itself ("where do i work?" → "hospital", not "work"). The store persists in `brain.npz`: **memory survives restarts**. **Arithmetic** is routed to a different brain region entirely: [gary-neuron](https://huggingface.co/gary23w/gary-neuron), the 26K-param async-NCA adder, imported from the sibling repo (`../gary-neuron`). Ask "what is 17 + 25?" and a trained net answers `17 + 25 = 42` — no calculator code. Only ~6K parameters are learned (a 96×64 key projection `Wq` and three scalars). They are **meta-trained** on `teach → distract → probe` episodes where the fact value is **randomized every episode** — so the only way to drive the loss down is to learn *how to store and retrieve through the memory*, not to memorize answers. (A fun emergent detail: the recency weight `rdec` trained **positive** — it discovered the fact is always the *oldest* token in an episode, so it rewards distance.) ## Measured results | Benchmark | Result | |---|---| | **Fact recall** (400 held-out episodes), plastic memory **ON** | **100.0%** | | Fact recall, memory **OFF** (frozen cortex alone) | **0.0%** | | **Live-chat recall** (randomized facts incl. multi-token names, 2 distractor turns) | **14/14 ON vs 0/14 OFF** | | False recalls during distractor turns (incl. question distractors) | **0** | | Small-talk degeneration (14 turns): max consecutive repeated word / distinct-bigram | **1 / 0.97** | | **Long-distance recall** after the fact left the 128-token window (v3 episodic store) | **works** (v2 failed) | | **Cross-session recall** — save brain, restart process, ask | **gary. / Rex. / hospital. / books.** | | Cortex after v3 burst training (step 222 → 515 on 20.5M tokens) | val loss **3.39 → ~2.88** (ppl ~29.7 → ~17.8) | | **v4 cortex**: deepened L=4→6→8 by function-preserving identity surgery (Net2Net-style) + context 128→192, then burst-trained on a 40M-token corpus (SODA valid+test) | val loss **2.42, ppl 11.2** — 1,109,952 params | | Hippo re-meta-trained on the new cortex (held-out episodes) | **100% ON / 0% OFF** | | **Sleep consolidation** — loss on new "session" material | **5.73 → 4.10** (it learns) | | Sleep consolidation — base English perplexity (forgetting anchor) | **29.4 → 30.7** (+4%, intact) | | Cortex params / memory params | 656,448 / **6,147** | The ablation is the whole story: the frozen cortex **cannot** remember a fact across distraction (0%), and the 6K-param plastic layer makes it perfect (100%) — that gap *is* the learning. And sleep teaches new material while base English barely moves, because experience replay holds the stability–plasticity line. > The autograd for the memory is hand-written and **finite-difference gradient-checked to 1e-5**. ## Talk to it ```bash pip install numpy tokenizers python brain.py chat # interactive; tell it facts, ask later, type /sleep to consolidate, /exit to save python brain.py demo # scripted: teach a fact, distract, ask -- memory ON vs OFF ``` ``` you : my dog is named Buddy you : how is the weather today? (distraction -- no false recall) you : what is my dog's name? gary: Buddy! you : my name is gary you : what is my name? gary: gary! (multi-token value, copy-chained) ``` Honest caveats: the cortex is 656K params, so **free-form generation is rough** (petite-grade word salad) — but it no longer loops or collapses (v2 decoder: temperature sampling, repetition & frequency penalties, trigram blocking). The rigorous, measured capabilities are **fact recall in live chat** (tables above) and **non-forgetting consolidation**. This is a mechanism demonstrator, not a polished assistant. ### v3 rebuild notes v2's recall only worked while the fact was still inside the 128-token context window — ask "what is my name?" twice, eight turns apart, and the second ask silently failed. v3 adds the persistent episodic store (encode-at-store-time, retrieve-by-cue), routes arithmetic to gary-neuron, accepts question-word questions without "?", and trains the cortex further (val 3.39 → ~2.88). ### v4.2: it can actually hold a conversation now Beyond fact recall, the deployed model handles real dialogue moves, all in the wrapper around the frozen cortex: - **Yes/no questions** with coverage logic: "am I a nurse?" → *yes*; "am I a doctor?" → *not that i know*; a false premise gets a soft correction ("is my cat named Rex?" → *what i remember is Luna*). - **Corrections that chain**: "no wait it's Garrett" rebinds the last answer; Gary → Garrett → Gareth all stick. - **Introductions & age**: "i'm Aiko" / "i'm 28" parse to name / age attributes. - **Coreference**: "i adopted a puppy" … "her name is Mochi" → "what's my puppy's name?" → *Mochi*. - **Self-knowledge**: "are you a real person?" → an honest canned answer. - **Accented names** (Tomás, José, Zürich) survive the byte-level tokenizer via span-decoding. - **Arithmetic** routes to the bundled [gary-neuron](https://huggingface.co/gary23w/gary-neuron) adder (included in `gary-neuron/` so math works standalone): "what is 123 + 456?" → *579*. Found and fixed by chatting with the model across three invented personas (a nurse, a retired teacher, a software engineer); a 17/18 regression suite holds. ### v4: a deeper brain, same memories The cortex was deepened from 4 to 6 layers by **function-preserving surgery**: two new blocks inserted with zero-initialized output projections, so the network computes the *exact same function* on day one (val loss identical to 6 decimals), then a ~1200-step burst campaign on a doubled 40M-token corpus grew into the new capacity. Perplexity: 29.7 (v2) → 17.8 (v3) → **11.7 (v4)**. The memory gate also generalized: any question may consult the episodic store unless it's about gary himself — so taught world-facts ("today is friday", "the meaning of life is 42") are now recallable, irregular verbs match (drank→drink), and subject-position matches outrank recency ("what is today?" → "friday", not the latest episode mentioning today). ### v3.1 fixes (live-chat shakedown) A long hands-on test session surfaced and fixed: relation **binder rules** (an episode about your *sister* can never answer "what is my *name*?", and "my *cat's* name?" can't be answered by a *dog* memory — both directions enforced); unified window-vs-store match scoring (a weak in-window match no longer shadows a strong stored memory); fact **overwrites** ("actually my dog is named Max now") resolve by overlap → specificity → recency; a tokenizer bug where stripping possessive-'s turned "is" into "i" and leaked user-facts into "what is *your* name?"; values can't be filler/relation words; sums ≥ 10^7 decline honestly. ### v2 rebuild notes v1's interactive chat death-spiraled ("hi hi hi...") for three compounding reasons: greedy decoding, a memory bias applied **every step over every token — including its own outputs** (one emitted "hi" became a key voting for the next), and single-token votes that couldn't emit multi-token facts. v2 keys the memory on **your** words only, fires it **once** per reply through the gate above, copy-chains whole words, and samples with anti-repetition penalties. ## Reproduce the whole thing The full pure-numpy pipeline is in `training/` (the cortex warm-starts from [gary-4-petite](https://huggingface.co/gary23w/gary-4-petite)): ```bash cd training python build_corpus.py # SODA (vocab-filtered) + Persona-Chat -> U:/G: dialogue python retok_warmstart.py # tokenize + warm-start cortex from petite SECONDS=40 E=96 H=4 L=4 BLK=128 python train_burst.py # fine-tune cortex (repeat ~5x) python build_episodes.py train 2000 && python build_episodes.py val 400 python hippo_train.py # meta-train the plastic memory (gradcheck + recall) python benchmark.py # recall ON/OFF + sleep-without-forgetting ``` ## Data - **Cortex dialogue**: [SODA](https://huggingface.co/datasets/allenai/soda) (AllenAI, EMNLP 2023), vocabulary-filtered to an everyday ~4k lexicon ("SODA-lite", the corpus-simplicity lever from TinyStories), seasoned with [Synthetic-Persona-Chat](https://huggingface.co/datasets/google/Synthetic-Persona-Chat) (Google). - **Memory meta-training**: synthetic `teach→distract→probe` episodes generated in that vocabulary, fact values randomized per episode. ## Sibling models - [gary-4-petite](https://huggingface.co/gary23w/gary-4-petite) — the 656K-param cortex this fine-tunes. - [gary-neuron](https://huggingface.co/gary23w/gary-neuron) — an async neural-cellular-automaton + mixture-of-experts that does 7-digit arithmetic. ## Citations - **Test-Time Training / fast-weights = linear attention** — Sun et al., *Learning to (Learn at Test Time)* (2024); *Test-Time Training Done Right* (2025). - **Titans: Learning to Memorize at Test Time** — Behrouz et al., arXiv:2501.00663 (surprise-gated neural memory). - **Differentiable plasticity / Backpropamine** — Miconi et al. (2018); arXiv:2002.10585 (ICLR 2019) — training self-modifying Hebbian networks with gradient descent. - **Sleep-like replay reduces catastrophic forgetting** — Tadros et al., *Nature Communications* (2022). - **SODA** — Kim et al., arXiv:2212.10465 (EMNLP 2023). **TinyStories** (corpus simplicity) — Eldan & Li (2023). *Built with numpy. The brain is a file. It changes.*