Chapter 11 measured that a memory vector persists, but dilutes: the whole past is worth less than each half. LeCun asks for something else — a memory that is consulted, and survives the window and the session. Here it becomes a bank of abstract states read by attention, with a quantized vector index (turbovec) keeping the bank on disk.
The memory of chapter 11 is one vector
LeCun describes another piece. The talk: "you may have to combine this with the content of a memory to get a complete idea of the state of the world". The interview: systems with "persistent memory, of the type that we have". And the architecture slide has the memory as a module consulted by the world model, not as a running sum. Chapter 11 left this written as an open question: "the consulted memory, not just summed, requires attention over a bank of abstract states, and is another piece". This is the piece.
Every block of 8 tokens that leaves the window is abstracted by the same level-2 encoder (abstrair()) and stored, not summed. The bank is the set
Three decisions, all inherited from what was already measured. The encoder receives no gradient through the bank (only
The measure is chapter 11's, transposed: bank_gain = MSE(bank of another text) − MSE(right bank), with the MSE of the empty bank alongside. Zero means the attention finds nothing useful in the past.
In training the bank fits in one matrix multiplication. On the bench it does not: the bank grows with every block generated or read, session after session, and the interview's promise is that it is not erased. One million blocks (eight million tokens read) are 256 million floats — a gigabyte in fp32, and an exact attention over a million states at every token. What the attention actually needs are the
turbovec is a Rust index with Python bindings implementing TurboQuant (Google Research, 2025): each vector is normalized, goes through a fixed random rotation (which makes every coordinate approximately Beta-distributed, with the same distribution in all dimensions), is quantized per coordinate with a 4-bit Lloyd-Max codebook (16 levels) and bit-packed — 256 dimensions become 128 bytes, eight times less than fp32 — and one scalar per vector corrects the bias of the estimated inner product. Search runs in SIMD over the codes, with no training step and no parameter tuning: the bank ingests online, one block at a time, which is the bench's regime. Saving is incremental (sync writes only what changed since the last time), which makes persistence cost milliseconds per generation. What it does not return are the vectors — only ids and scores — so the fp32 states live in a file alongside, and the attention is done over the
| exact search (numpy) | turbovec, 4 bits | |
|---|---|---|
| bytes per state in the index | 1,024 | 128 |
| one million blocks | 1.0 GB | 128 MB (+ 1.0 GB of states on disk, only the |
| cost per query | product with the whole bank | SIMD search over codes; top- |
| index training step | — | none (fixed rotation + precomputed codebook) |
| persistence | rewrite everything | incremental, durable at any byte |
| the attention uses | all states | the |
The simplest alternative would be to keep everything in RAM and search exactly; it stays available as a fallback (same API, without turbovec installed) and is the reference for measuring what quantization costs in recall — the question section 5 leaves open.
Round wm1n2bco-sz1, on the same budget as the others: hierarchy with the raw mean (the honest abstraction of chapter 11), SigReg-z, bank with dropout 0.5, without the summed memory (to measure the piece alone). Three questions: does the bank carry the past (gain > 0)? is the whole past worth more than each half (what the vector could not do)? and does the rudder govern on this map, with the bank empty — which is the condition of chapter 12?
| Source of the past | summed memory (mem) | consulted bank (bco) | gain vs other (bco) |
|---|---|---|---|
| zero / empty | 0.220 | 0.1748 | +0.0023 |
| other (A+B from another text) | 0.193 | 0.1771 | 0 |
| recent (B only) | 0.173 | 0.1736 | +0.0035 |
| long (A+B) | 0.181 | 0.1736 | +0.0036 |
| old only (A only) | 0.174 | 0.1738 | +0.0033 |
| Round | validation | cost | map gain | memory / bank gain | free | head + real state | governs? |
|---|---|---|---|---|---|---|---|
wm1n2mem-sz1 (summed) | 5.6801 | +7.77% | +0.93 | +0.014 | 0.343 | 0.258 | no |
wm1n2mem-sz1-md0.5 (summed + dropout) | 5.6109 | +6.46% | +0.92 | +0.002 | 0.224 | 0.301 | yes |
wm1n2bco-sz1 (consulted) | 5.7695 | +9.73% | +0.87 | +0.0036 | 0.360 | 0.272 | no |
The bank solves the dilution that was the summed memory's defect. In chapter 11, "long" (A+B) erred 0.181, worse than "recent" (B only, 0.173): the more past, the less of each piece, because a fixed-capacity vector overwrites itself. In the consulted bank, "long" errs 0.1736 — exactly equal to "recent", and slightly better than "old only" (0.1738). Storing instead of summing removes dilution by construction: the old block is still there, intact, and attention picks. It is what the slide's architecture predicted and the summation did not deliver.
And the bank carries little. Its gain over another text's memory is +0.0036, against chapter 11's +0.014 for the summed memory and +0.002 for the summed one with dropout. The cause is the same as in both earlier cases, and it is in the recipe: bank-dropout of 0.5 teaches the predictor to work without a bank, and it learns not to depend on one. The difference is that here the dropout was mandatory — every short prompt starts with an empty bank — so the trade-off is not a calibration error but the shape of the problem. The round with lower dropout is the missing test.
The rudder does not govern on this map (0.272 with head and real state against 0.360 free), and the cost to the generator is the family's highest, +9.73%. Summing up: consulted memory delivers what it promised on persistence — it does not dilute — and delivers nothing else. Under chapter 13 §12.3's noise ruler, +9.73% is indistinguishable from the same map's +9.55% without a bank: the bank is free and carries almost nothing. It stays on the bench as infrastructure, with the quantised on-disk index ready for a large bank, and the dropout question open.
The bank passes if "long" beats "recent" and "old only" — the attention chooses within the whole past instead of diluting it — and if "empty" stays neutral (the dropout did its job). If the bank's gain is zero, the attention found no structure in the past 256 tokens away; the next ruler is the same experiment with a longer past (the bench already builds one). If the cost to the generator is higher than the summed memory's, the attention is charging; what is compared then is gain per point of cost.
--world-bank gets a bank in runs/<round>/banco/ (banco.tvim + states in .npy), loaded when the model is loaded and saved at the end of every generation. Every block that leaves the window — from the prompt or from what was generated — enters the bank.compass parameters: banco (true, false, or "limpar" to clear), banco_gravar (false = consult only) and banco_k (top-banco_estados.model/memory.py) prints the bank's table next to the summed memory's, when the model has both.remove(id) is what makes it cheap.allowlist allows consulting only a subset of ids at no recall cost: that is what a per-conversation or per-source memory would use.