Retrieval simulated as computation
Language modelling runs two workloads through one mechanism. Compositional reasoning — multi-step inference, arithmetic, code — genuinely needs deep, input-dependent computation. Static recall — named entities, idioms, formulaic collocations — does not. It needs a table.
Transformers only have the first mechanism, so they emulate the second. The canonical demonstration comes from PatchScope: decode the residual stream at the token Wales layer by layer and watch six blocks of attention and FFN assemble a single entity that a lookup would have returned in one step.
| Layer | Latent state translation (PatchScope) | Resolved entity |
|---|---|---|
| 1–2 | Country in the United Kingdom | Wales |
| 3 | Country in Europe | Wales |
| 4 | Title held by female sovereigns in their own right or by queens consort | Princess of Wales (unspecific) |
| 5 | Title given to the wife of the Prince of Wales (and later King) | Princess of Wales (unspecific) |
| 6 | Diana, Princess of Wales (1961–1997), the first wife of Prince Charles, Prince of Wales, famous for her beauty and humanitarian work | Diana, Princess of Wales |
The wasted depth is the target. Engram's thesis is that if the model can address that entity directly, the freed layers become available for work that actually requires them — which is why the paper's largest gains land on BBH (+5.0) and ARC-Challenge (+3.7), not on the trivia benchmarks you would expect a memory module to move.
Conditional computation, conditional memory
MoE is conditional computation: a router reads the hidden state and activates a sparse subset of experts. Engram is conditional memory: a hash of the input tokens addresses a sparse subset of embedding rows. Both raise total parameters without raising per-token FLOPs. They differ in the one property that determines where the parameters are allowed to live.
| Property | MoE — conditional computation | Engram — conditional memory |
|---|---|---|
| Selected unit | Expert FFN (top-k of N) | Embedding row (1 per hash head) |
| Address derived from | Hidden state h_t — a runtime value | Input token IDs — known in advance |
| Address known at | Layer execution time | Before the forward pass begins |
| Work per activation | Two matmuls per expert | One gather. O(1), no arithmetic |
| Parameters may live | HBM only — needed mid-flight | Host DRAM, NVMe — prefetchable |
| Access distribution | Balanced by construction (aux-loss / bias) | Zipfian — cacheable by frequency |
| Fails at | Cheap static recall | Anything context-dependent |
The third row is the load-bearing one. Because an Engram address is a pure function of input_ids, the table can sit off-accelerator and still arrive on time — the property Section 11 turns into a 100B-parameter layer in host memory at a 2.8% throughput cost.
Where the parameters go
Fix total parameters P_tot and activated parameters P_act. The inactive remainder P_sparse = P_tot − P_act is free capacity — it scales the model without scaling the compute. The allocation ratio ρ splits it:
Section 06 shows this has an interior optimum. That is the paper's central empirical claim: pure MoE is not the right allocation.
From token IDs to 16 table addresses
Everything upstream of the embedding lookup is integer arithmetic on input_ids — no weights, no gradients, no data dependence on the hidden state. Four stages: canonicalise, window, mix, reduce.
03.1 — Tokenizer compression
Collapsing a lossless vocabulary into a semantic one
A BPE vocabulary is built for lossless reconstruction, so it splits one concept across many IDs: Apple, ␣apple, APPLE. For a hash key that is pure waste — each variant addresses a different, separately-trained row. Engram first applies a precomputed surjective map P : V → V′ built from textual normalisation.
normalizers.Sequence([ NFKC(), # compatibility composition NFD(), StripAccents(), # decompose, drop diacritics Lowercase(), Replace(Regex(r"[ \t\r\n]+"), " "), # collapse whitespace runs Replace(Regex(r"^ $"), SENTINEL), # protect a lone space … Strip(), Replace(SENTINEL, " "), # … from Strip() ]) # byte-fallback tokens (decode to U+FFFD) bypass this and key on # their raw token string, so they stay distinct.
Note the sentinel dance: Strip() would erase a token that is exactly one space — a very high-frequency token — so it is swapped for a private-use character and swapped back.
| Rank | Merged | Canonical | Raw surface forms |
|---|---|---|---|
| 1 | 163 | '␣' | \t \n \r ␣ ␣␣ \n\n ␣␣␣ … |
| 2 | 54 | 'a' | A a ␣a ␣A á ä ã ą ␣à â … |
| 3 | 40 | 'o' | O o ␣o ␣O ó ö ô õ ő ò … |
| 4 | 35 | 'e' | E e ␣e ␣E é è ␣é ę ě ê … |
| 5 | 30 | 'i' | I i ␣I ␣i í ì î ī ï ␣î … |
The effect is not merely compression. Inside the sentence By the way, I am a fan of the Milky Way. the tokenizer emits ␣way (1722) and ␣Way (13823) as unrelated IDs; P sends both to canonical 1461. The 2-gram key for “the way” and the key for “…y Way” now share statistics that the raw vocabulary kept apart. Removing this step is one of the three ablations that hurt most (§09).
03.2 — Multi-head hashing
Why eight heads and why prime moduli
The space of 3-grams over a 98k vocabulary is ~9.6 × 1014 keys. No table enumerates that, so Engram hashes into a fixed number of slots and accepts collisions — then makes them survivable. Each order n gets K = 8 heads, each with its own prime modulus, none reused across heads, orders, or layers.
e_t = ∥_{n=2..N} ∥_{k=1..K} e_{t,n,k} ∈ ℝ^d_mem (2)
Two keys that collide in head k almost certainly do not collide in the other seven, because the moduli are coprime and the multipliers are independent. The concatenation in (2) means the fusion layer sees eight near-independent readings of the same key; a single corrupted one is recoverable. Prime — rather than power-of-two — moduli avoid the classic failure where mod 2^b keeps only the low bits and discards the avalanche the XOR just produced.
Table packing
All 16 head-tables are one nn.Embedding. Each head's index is shifted by the cumulative size of its predecessors, so the 16 addresses become one contiguous gather — a single kernel, one memory transaction pattern, no per-head dispatch.
offsets = cumsum([0, M₂,₁, M₂,₂, …, M₃,₇]) rows = embedding[ z + offsets ] # [B,L,16,d_head] e_t = rows.flatten(-2) # [B,L,d_mem]
Layer decorrelation
Multipliers are drawn per layer from seed + 10007·ℓ, forced odd (2r+1) so multiplication stays a bijection mod 264, and bounded so x′·m cannot overflow int64. The Engram at layer 2 and the Engram at layer 15 therefore see the same n-gram at completely different addresses — they are independent memories, not two reads of one.
| Layer / order | k=1 | k=2 | k=3 | k=4 | k=5 | k=6 | k=7 | k=8 |
|---|---|---|---|---|---|---|---|---|
| ℓ = 2, n = 2 | 646403 | 646411 | 646421 | 646423 | 646433 | 646453 | 646519 | 646523 |
| ℓ = 2, n = 3 | 646537 | 646543 | 646549 | 646571 | 646573 | 646577 | 646609 | 646619 |
| ℓ = 15, n = 2 | 646631 | 646637 | 646643 | 646669 | 646687 | 646721 | 646757 | 646771 |
| ℓ = 15, n = 3 | 646781 | 646823 | 646831 | 646837 | 646843 | 646859 | 646873 | 646879 |
32 distinct primes, searched upward from engram_vocab_size − 1 = 646,399 with a shared seen-set across layers. Reproduced by running the repository's find_next_prime loop. These are the demo configuration's table sizes; Engram-27B uses 2,262,400 slots per head.
Gating a static prior against live context
The retrieved vector e_t is context-free by construction. It is the same 1280 numbers whenever those three canonical tokens co-occur — correct for “Alexander the Great”, wrong when the n-gram is a hash collision or a polysemous fragment. Engram therefore never adds e_t to the residual stream directly. It scores it first.
α_t = σ( RMSNorm(h_t)⊤ RMSNorm(k_t) / √d ) (4)
Y = SiLU( Conv1D( RMSNorm(Ṽ) ) ) + Ṽ , Ṽ = α_t · v_t (5)
The gate is one number
Not a vector, not a per-dimension mask — a single scalar per token per branch. That is a strong constraint: the module may decide how much of a memory to admit, never which parts. It buys interpretability (§10 reads α directly as “a static pattern completed here”) and it keeps the fusion cheap.
RMSNorm on both sides before the dot product makes α a scaled cosine similarity rather than a magnitude comparison, which is what keeps gradients stable when the query and the memory live at very different scales early in training.
Four branches, one table
The backbone is Manifold-Constrained Hyper-Connections with M = 4 parallel residual streams. Engram shares the embedding table and W_V across all four, but gives each branch its own W_K^(m). So one retrieval is admitted at four different strengths — each branch decides independently whether it wants that memory.
The five projections (W_V + four W_K) fuse into a single FP8 GEMM. Removing branch-specific gating is the single most damaging ablation in §09.
Where to inject it
Placement is a genuine trade-off, and the paper resolves it empirically rather than by argument.
- Earlier is better for offloading work. The point is to spare the backbone from reconstructing local patterns; do it after the backbone already has, and there is nothing left to spare.
- Later is better for gating. α needs a query that has seen global context. At layer 1 the hidden state has been through no attention at all, and the four mHC branches have not yet diverged enough to gate differently.
- Layer 2 wins the single-injection sweep (val loss 1.770). One round of attention is enough context; layer 1 is worse, and everything deeper degrades monotonically.
- Two smaller modules beat one large one. Splitting the same 1.6B budget across layers 2 and 6 reaches 1.768 — early intervention plus late-stage contextual gating. Engram-27B uses layers 2 and 15.
- And it happens to serve the hardware. A deeper second placement gives the prefetcher more compute to hide PCIe latency behind (§11).
The addressing, running
Below is the real arithmetic — the DeepSeek-V3 tokenizer's IDs, the canonical map P, the seed-0 multipliers, and the prime moduli computed by the repository's own prime search. Pick a token to see the 16 addresses its suffix n-grams resolve to.
Key construction
Edit any canonical ID by one digit and watch every one of the 16 addresses move. Changed rows mark in red.
Resolved addresses
| Head | Order | Modulus M | Address z | Position in table |
|---|
Verified against the reference implementation. Multipliers come from np.random.default_rng(0 + 10007·ℓ); the mix is computed in signed 64-bit (BigInt here, int64 there) and never overflows because each m_k is bounded by (2⁶³−1)/|V′|/2. The paper places Engram at layers 2 and 15; the shipped demo file uses layer_ids = [1, 15], and the moduli shown here follow the paper.
16 heads × 2 layers
2,262,400 × 16 × 2
touched per token
per token, all layers
Derived from Table 5 and Eq. 2: d_mem = 1280 is the concatenation of 2 orders × 8 heads × 80 dims, so 2,262,400 × 80 × 16 × 2 = 5.79B parameters — the paper's 5.7B Engram module. Engram-40B triples the slot count to 7,239,680 per head for 18.5B.
The U-curve: pure MoE is the wrong allocation
Hold P_tot and P_act fixed — same parameter count, same FLOPs per token — and sweep ρ, moving capacity from routed experts to embedding slots. If memory were merely a cheaper substitute for compute, loss would rise monotonically as ρ falls. It does not.
| Allocation ρ | Val loss | Reading |
|---|---|---|
| 100% — pure MoE | 1.7248 | 99 routed experts, no memory |
| ≈ 80% — optimum | 1.7109 | Δ = −0.0139 |
| ≈ 40% | ≈ parity | 43 experts still matches pure MoE |
Measured at C = 6×10²⁰, P_tot ≈ 9.9B, P_act = 993M. The optimum sits at ρ ≈ 75–80% in both compute regimes — stable enough to use as a design rule.
Why both ends lose
ρ → 100%. No dedicated store for static patterns, so the model rebuilds them through depth — the waste from §01, now priced.
ρ → 0%. No conditional computation left. A table cannot compose, cannot condition on context, cannot do arithmetic. Memory does not substitute for compute; it complements it.
The interior minimum is the whole argument. It says the two axes are structurally different rather than two ways of buying the same thing — and that frontier MoE models are sitting at a corner of the design space rather than inside it.
Released from the budget, memory keeps paying
Relax the parameter cap and the second scaling question appears: with a fixed 3B MoE backbone (568M activated, 100B tokens), how far does adding slots go? Sweeping M from 2.58×10⁵ to 1.0×10⁷ — up to ~13B added parameters — validation loss falls log-linearly across the entire range, with no sign of saturation.
The comparison that matters is OverEncoding, which also uses hashed n-gram embeddings but averages them into the input embedding at layer 0. Same memory budget, distinctly worse slope. How the memory is fused matters as much as how much of it there is.
Iso-parameter, iso-FLOPs, 262B tokens
Engram-27B is MoE-27B with 17 routed experts removed and the freed parameters spent on a 5.7B embedding module — ρ = 74.3%. Identical backbone, identical data in identical order, identical activated parameters. The only difference is where the sparse capacity sits.
| Benchmark | Shots | Dense-4B | MoE-27B | Engram-27B | Δ vs MoE | Engram-40B |
|---|---|---|---|---|---|---|
| Configuration | ||||||
| Total parameters | — | 4.1B | 26.7B | 26.7B | 39.5B | |
| Activated (excl. token embed) | — | 3.8B | 3.8B | 3.8B | 3.8B | |
| Experts — shared + routed (top-k) | — | — | 2+72 (6) | 2+55 (6) | 2+55 (6) | |
| Engram parameters | — | — | — | 5.7B | 18.5B | |
| Language modelling — loss, lower is better | ||||||
| Pile (test) | — | 2.091 | 1.960 | 1.950 | −0.010 | 1.942 |
| Validation set | — | 1.768 | 1.634 | 1.622 | −0.012 | 1.610 |
| Knowledge & reasoning | ||||||
| MMLU | 5 | 48.6 | 57.4 | 60.4 | +3.0 | 60.6 |
| MMLU-Redux | 5 | 50.7 | 60.6 | 64.0 | +3.4 | 64.5 |
| MMLU-Pro | 5 | 21.1 | 28.3 | 30.1 | +1.8 | 31.3 |
| CMMLU | 5 | 47.9 | 57.9 | 61.9 | +4.0 | 63.4 |
| C-Eval | 5 | 46.9 | 58.0 | 62.7 | +4.7 | 63.3 |
| AGIEval | 0 | 29.1 | 38.6 | 41.8 | +3.2 | 45.9 |
| ARC-Easy | 25 | 76.8 | 86.5 | 89.0 | +2.5 | 90.1 |
| ARC-Challenge | 25 | 59.3 | 70.1 | 73.8 | +3.7 | 76.4 |
| TriviaQA | 5 | 33.0 | 48.8 | 50.7 | +1.9 | 51.8 |
| TriviaQA-ZH | 5 | 62.8 | 74.8 | 76.3 | +1.5 | 77.9 |
| PopQA | 15 | 15.1 | 19.2 | 19.4 | +0.2 | 21.2 |
| CCPM | 0 | 72.2 | 79.6 | 87.1 | +7.5 | 87.7 |
| BBH | 3 | 42.8 | 50.9 | 55.9 | +5.0 | 57.5 |
| HellaSwag | 0 | 64.3 | 71.8 | 72.7 | +0.9 | 73.1 |
| PIQA | 0 | 63.8 | 71.9 | 73.5 | +1.6 | 76.5 |
| WinoGrande | 5 | 64.0 | 67.6 | 67.8 | +0.2 | 68.1 |
| Reading comprehension | ||||||
| DROP (F1) | 1 | 41.6 | 55.7 | 59.0 | +3.3 | 60.7 |
| RACE-Middle | 5 | 72.4 | 80.9 | 82.8 | +1.9 | 83.3 |
| RACE-High | 5 | 66.0 | 75.4 | 78.2 | +2.8 | 79.2 |
| C3 | 0 | 57.7 | 60.1 | 63.6 | +3.5 | 61.8 |
| Code & mathematics | ||||||
| HumanEval (pass@1) | 0 | 26.8 | 37.8 | 40.8 | +3.0 | 38.4 |
| MBPP (pass@1) | 3 | 35.4 | 46.6 | 48.2 | +1.6 | 46.2 |
| CruxEval-i | 0 | 27.6 | 30.7 | 32.2 | +1.5 | 36.2 |
| CruxEval-o | 0 | 28.7 | 34.1 | 35.0 | +0.9 | 35.3 |
| GSM8K | 8 | 35.5 | 58.4 | 60.6 | +2.2 | 62.6 |
| MGSM | 8 | 27.0 | 46.8 | 49.4 | +2.6 | 52.4 |
| MATH | 4 | 15.2 | 28.3 | 30.7 | +2.4 | 30.6 |
Table 1. All four models trained on the same 262B tokens. The Δ column compares the two iso-parameter, iso-FLOPs 26.7B models. Engram-40B keeps the activated budget fixed and only grows the table; it does not dominate on every task, which the authors attribute to under-training — the loss gap was still widening at the end of the run.
The surprising column
A memory module should move TriviaQA and PopQA. It moves them least (+1.9, +0.2). The largest gains are on CCPM +7.5, BBH +5.0, C-Eval +4.7, ARC-Challenge +3.7 — composition-heavy tasks with no obvious lookup component. Under the paper's account this is exactly right: the benefit is not the facts stored, it is the depth returned to the backbone. §09 tests that claim directly.
Attention, relieved of local work
Attention heads that spend themselves binding adjacent subwords into entities are not available for retrieval across 32k tokens. If Engram absorbs the local dependencies, the prediction is that long-range behaviour improves — even though Engram itself has a receptive field of three tokens.
The evaluation is unusually careful about a confound the authors flag themselves: long-context ability tracks general model quality, so comparing at equal steps conflates architecture with base capability. They therefore include an iso-loss checkpoint — Engram at 46k steps has the same pre-training loss as MoE at 50k — and give all variants the identical YaRN extension run (32,768 tokens, 5,000 steps, 30B tokens).
| Model (steps, pre-train loss) | LongPPL (32k) ↓ | RULER (32k) ↑ | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Book | Paper | Code | L-CoT | S | MK | MV | MQ | VT | CWE | FWE | QA | |
| MoE-27B (50k, 1.63) | 4.38 | 2.91 | 2.49 | 14.16 | 100.0 | 88.0 | 92.7 | 84.2 | 77.0 | 4.5 | 73.0 | 34.5 |
| Engram-27B (41k, 1.66) — 82% FLOPs | 4.37 | 2.92 | 2.50 | 14.26 | 99.6 | 88.3 | 93.0 | 89.5 | 83.2 | 3.8 | 99.6 | 44.0 |
| Engram-27B (46k, 1.63) — iso-loss | 4.19 | 2.84 | 2.45 | 13.59 | 97.6 | 89.0 | 95.5 | 97.0 | 87.2 | 4.3 | 98.6 | 37.5 |
| Engram-27B (50k, 1.62) — iso-FLOPs | 4.14 | 2.82 | 2.44 | 13.41 | 99.3 | 89.3 | 96.5 | 97.0 | 89.0 | 5.9 | 99.3 | 40.5 |
Table 2. S / MK / MV / MQ — single, multi-key, multi-value and multi-query needle-in-a-haystack. VT — multi-hop variable tracking. CWE / FWE — common and frequent word extraction. QA — long-document question answering.
at iso-loss
at iso-loss
at iso-loss
The 82%-compute row is the sharper result: an Engram checkpoint stopped 9,000 steps early, at visibly worse pre-training loss, already matches the fully-trained MoE on LongPPL and beats it on RULER. Two honest caveats: single-needle accuracy is marginally lower (99.3 vs 100.0 — a saturated metric), and CWE stays broken for both models at 4.5 vs 5.9. Whatever common-word extraction needs, neither architecture has it.
Evidence that Engram buys depth
The claim from §01 — that lookups return sequential depth to the backbone — is testable with interpretability tools rather than benchmarks. Three independent probes agree.
1 — Predictions converge earlier
LogitLens projects every intermediate hidden state through the final LM head and measures KL divergence against the model's own final distribution: how prediction-ready is layer ℓ? Both Engram variants sit systematically below the MoE baseline, with the widest gap in the early blocks — precisely where the entity-composition work of Table 3 would otherwise happen.
2 — Shallow layers behave like deep ones
Centered Kernel Alignment compares representations across models. Build the pairwise CKA matrix over Few-NERD entity-final tokens, then take the similarity-weighted centroid of the top-5 matching MoE layers for each Engram layer. The alignment curve lifts clearly off the diagonal: Engram layer 5 ≈ MoE layer 12.
Same conclusion from a different instrument — the network is not merely more accurate, it is further along at the same depth.
3 — Turn it off and see what breaks
Suppress the Engram output entirely at inference, leaving the backbone untouched, and measure what survives. This deliberately induces a train/inference mismatch, so the authors read only the two extremes of the spectrum — but the dichotomy is stark.
TriviaQA retains 29%, PopQA 44%, MGSM 44% — against C3 at 93% and RACE-Middle at 89%. Note that MATH (36%) and MGSM (44%) fall on the knowledge side, suggesting the memory is also carrying formulaic mathematical surface patterns, not only entities.
Component ablations
All at a fixed 1.6B Engram budget on a 12-layer 3B MoE backbone (0.56B activated, 100B tokens). Reference configuration: {2,3}-grams at layers 2 and 6, 1.768 against a bare MoE baseline of 1.808.
| Variant | Val loss | Effect |
|---|---|---|
| 3B MoE baseline | 1.808 | no memory |
| Reference — layers 2 + 6 | 1.768 | Δ = −0.040 |
| Single injection, layer 2 | 1.770 | best single placement |
| w/o multi-branch gating | ≈1.783 | largest regression |
| w/o context-aware gating | ≈1.780 | static memory admitted unfiltered |
| w/o tokenizer compression | ≈1.778 | keys fragment across case/space |
| + 4-grams | ≈1.773 | dilutes the 2/3-gram budget |
| w/o short conv | ≈1.771 | marginal |
Three components carry the design: branch-specific fusion, context-aware gating, and tokenizer compression. Remove any one and most of the 0.040 advantage goes with it. The depthwise convolution is nearly free to drop.
Adding 4-grams hurts at this budget — longer keys are rarer, so slots spent on them see fewer updates than slots spent on 2- and 3-grams. The authors explicitly leave open that this reverses at larger table sizes.
Values marked ≈ are read from the Figure 5 markers rather than a table; the paper reports them graphically. The ordering and the three-way conclusion are stated in the text.
What the gate actually fires on
Because α_t is a single scalar, it can be read straight off the model. Engram operates on suffix n-grams, so a high value at token t means the phrase ending at t was recognised — the gate marks pattern completion, not pattern onset.
Figure 7 — schematic reproduction. The sentences are the paper's; the highlighted spans are the ones it reports the gate activating on. Per-token α values are published only as a heatmap image, so the intensities here are illustrative of the described pattern rather than measured. Engram-27B computes eight gates per token (4 mHC branches × 2 layers); the paper visualises the branch most correlated with semantic matching.
The categories it selects
- Multi-token named entities — Alexander the Great, the Milky Way, Princess of Wales.
- Formulaic collocations — By the way. Zero factual content, perfectly predictable, ideal table material.
- Cross-lingual, with no special handling — Chinese idioms and historical figures fire the same way. The mechanism is a hash over token IDs; it has no notion of language.
Note the useful negative: the gate is quiet over function words and compositional spans. It is not a general-purpose “add memory” signal — it is a static-pattern detector, which is what Eq. 4 was designed to produce.
Why suffix framing matters
A 3-gram key at position t is (x′_{t−2}, x′_{t−1}, x′_t). Nothing to the right is visible, so the module stays strictly causal and is usable in autoregressive decoding without modification.
It also means the memory cannot help until the pattern has been observed — Engram assists the token after “Bucephalus” is complete, not the one that predicts it. What it contributes is a clean, already-composed representation of the phrase for everything downstream, which is exactly the representation the backbone was spending six layers to build.
Storage decoupled from compute
This is the property that makes the architecture interesting to build on rather than merely to benchmark. An MoE router cannot tell you which expert a token needs until the hidden state reaches that layer, so expert weights must already be in HBM. An Engram address is a function of input_ids alone — it is computable before the first block runs.
Training
Sharded tables, All-to-All
Embedding tables are sharded across accelerators. The forward pass gathers active rows with an All-to-All; the backward pass dispatches gradients back the same way. Total memory capacity scales linearly with device count, so the table size is bounded by the cluster rather than by any single GPU.
The embeddings get their own optimiser: Adam at 5× the base learning rate with no weight decay, while the backbone runs Muon. Sparse rows are visited rarely, so they need a larger step when they are; decay would erode the long tail between visits. The convolution is zero-initialised so the module is an exact identity at step 0.
Inference
Prefetch, and hide it behind the first blocks
Tables move to host DRAM. The moment a sequence is known, all addresses are known, so the host can start the PCIe transfer while the GPU is still executing block 0 — communication overlapped with computation rather than serialised behind it. This is why Engram sits at layer 2 and not layer 0: layer 0 leaves nothing to hide the latency behind, which is precisely the flaw the paper identifies in OverEncoding and SCONE.
Volume per step scales with activated slots (32 rows/token), not with table size. A 100B-parameter table and a 1B-parameter table move the same bytes per token.
| Configuration | Tok/s | Penalty |
|---|---|---|
| 4B dense — baseline | 9,031.62 | — |
| + 100B Engram, CPU offload | 8,858.28 | −1.9% |
| 8B dense — baseline | 6,315.52 | — |
| + 100B Engram, CPU offload | 6,140.02 | −2.8% |
Dense backbones were used deliberately, to keep MoE expert-parallel traffic out of the measurement.
This is a pessimistic number. Every single retrieval was forced across PCIe with no caching at all. Natural-language n-grams are Zipfian, so a real deployment would keep the hot head of the distribution in HBM and let only the long tail reach DRAM or NVMe — a three-tier hierarchy the paper describes but does not implement here.
Configuration reference — Engram-27B / 40B
| Backbone | Value |
|---|---|
| Layers / dimension | 30 / 2560 |
| Attention | MLA, 32 heads, RoPE θ=10000 |
| Residual topology | mHC, expansion 4 |
| Leading dense layers | 1 |
| Load balancing | loss-free (bias) |
| Sequence length | 4096 |
| Batch / steps | 1280 / 50,000 |
| Optimiser / LR | Muon / 4e-4, step decay |
| Weight decay | 0.1 |
| Engram | 27B | 40B |
|---|---|---|
| d_mem | 1280 | 1280 |
| Slots per head | 2,262,400 | 7,239,680 |
| Heads per order | 8 | 8 |
| N-gram orders | {2, 3} | {2, 3} |
| Layers | [2, 15] | [2, 15] |
| Parameters | 5.7B | 18.5B |
| Optimiser | Adam | Adam |
| LR multiplier | ×5 | ×5 |
| Weight decay | 0.0 | 0.0 |
| Conv init | zero | zero |
Table 5. Slots-per-head is listed in the paper as “Engram vocab size”; the reading above is the one consistent with the reported 5.7B / 18.5B parameter counts at d_mem = 1280.
What it is not, and what is unresolved
Engram is frequently described as giving a model “a second brain” or fixing “LLM amnesia.” It does neither. Being precise about the boundaries is the fastest way to understand the mechanism.
Not retrieval-augmentation
There is no document store, no query encoder, no nearest-neighbour search. The table holds learned parameters addressed by a hash of literal token IDs. Nothing is retrieved about the content; a row is fetched because of the arithmetic on three integers.
Not editable memory
Rows are trained by gradient descent like any other weight. You cannot write a new fact into slot z and expect coherent behaviour — the row means whatever training made it mean, entangled with every colliding key. This is parametric memory that happens to be sparse, not a knowledge base.
Not long-range
The receptive field is three tokens. The long-context gains in §08 are entirely indirect: attention is freed, not extended.
Open questions the paper leaves
- Collision behaviour at scale is uncharacterised. Eight heads make collisions survivable, but there is no measurement of how often two semantically unrelated n-grams share a slot, or what that costs.
- 4-grams are unresolved, not refuted. They lose at a 1.6B budget. The authors explicitly decline to rule out that they win at 18.5B.
- Two layers, chosen by a 12-layer sweep. The [2, 15] placement for a 30-layer model is extrapolated from ablations on a smaller backbone plus a latency-hiding constraint. Three modules? Four?
- 262B tokens is short. Engram-40B was still improving relative to baselines at the end of training — the reported numbers are a lower bound, and the shape of the allocation law at trillion-token scale is unknown.
- The Zipfian cache hierarchy is described, not built. The 2.8% figure comes from forcing every access over PCIe; the tiered design that would improve it remains future work.
- Nothing here is post-trained. All results are base-model evaluations. How a heavily-parametric-memory model behaves under RLHF or reasoning-style RL is untested.
The claim worth keeping
Strip away the benchmark table and one structural result remains: under a fixed parameter and FLOP budget, moving roughly a fifth to a quarter of your sparse capacity out of routed experts and into a hash-addressed table makes the model better — and it makes it better most on the tasks that look least like lookup. If that holds at frontier scale, then every pure-MoE model currently in production is sitting at the boundary of the design space rather than inside it, and “where should the parameters live” becomes a question with a non-degenerate answer.