Learning to forget on purpose
The delta rule deletes an association only as a side effect of writing a replacement. But a model that finishes a document and starts a new one does not have replacements for the thousand facts it no longer needs — it needs a way to say "release that capacity" with no new content at all.
Erasure is not an operation. It only happens when some future key points in the same direction as an old one, which is not something the model controls. Stale associations from tens of thousands of tokens ago sit in the state consuming its \(d\) slots until chance evicts them.
And the geometry says this cannot be patched with the delta rule alone. \(I - \beta k^{\top}k\) contracts along one direction and leaves the other \(d-1\) untouched. Clearing a \(d\)-dimensional state would take \(d\) separate delta writes — 128 tokens spent doing nothing but erasing. That is not an eviction policy, that is a garbage-collection pause.
The other primitive
There is a much blunter operation available, and it is the entire contribution of gated linear attention and Mamba-2. If we were still doing chapter 2's purely additive write, adding forgetting would take one character:
S_old = cache S_new = k @ v # cache = S_old + S_new ← chapter 2 cache = alpha * S_old + S_new ← decay the past, add the new at full strength
With \(\alpha_t \in (0,1)\) predicted from the token, the state becomes a leaky accumulator. Two consequences fall straight out.
The state is now provably bounded. Under a constant \(\alpha\) with unit-norm writes, \(\|S_t\| \le \sum_{j\ge 0}\alpha^{j} = 1/(1-\alpha)\). Without decay, an additive state's norm drifts upward roughly as \(\sqrt N\) and there is nothing to stop it. This is the framing Mamba-2 used: decay first, then add at full strength, so the state cannot grow without bound.
Every association acquires a memory horizon. A fact written \(t\) steps ago survives with weight \(\alpha^{t}\), so its half-life in tokens is
| α | half-life | what that memory is good for |
|---|---|---|
| 0.9 | 6.6 tokens | the immediately preceding phrase; local syntax |
| 0.99 | 69 tokens | the current sentence or paragraph |
| 0.999 | 693 tokens | the current section, a function body, a speaker turn |
| 0.9999 | 6,931 tokens | the document; effectively permanent within one context |
| 0 | instant | context switch — wipe the board and start over |
Neither primitive can do the other's job
The two mechanisms fail in exactly complementary ways, and stating why is the argument for combining them.
| Gated linear attention / Mamba-2 α only | DeltaNet β only | |
|---|---|---|
| Replace one specific fact | Only by shrinking \(\alpha\) — which damages every other fact by the same factor. There is no targeted operation. | Exactly. One direction, one step, nothing else touched. |
| Clear the whole state | One step, \(\alpha \to 0\). | Needs \(d\) separate writes at \(d\) orthogonal keys. In practice, impossible. |
| Bound the state norm | Yes, geometrically: \(\|S\| \le 1/(1-\alpha)\). | Contractive along written directions only; drift elsewhere. |
| Handle key collisions | No — collisions still superimpose. | Yes, that was chapter 3. |
The gated delta rule
Put both transforms on the state. The decay scales everything; the Householder term removes the one direction being rewritten:
αt ∈ (0,1) and βt ∈ (0,1) are both data-dependent scalars projected from the token. The mathematics is otherwise identical to chapter 3.
The corners of the \((\alpha,\beta)\) square recover every model in the series so far:
| α | β | Behaviour | Equivalent to |
|---|---|---|---|
| 1 | 0 | \(S_t = S_{t-1}\), nothing happens | a no-op layer |
| 1 | 1 | precise overwrite, no decay | DeltaNet · chapter 3 |
| <1 | 0 | uniform decay, additive write | Mamba-2 / gated linear attention |
| 1 | →0 | additive write, no decay | linear attention · chapter 2 |
| 0 | 1 | discard everything, keep only this token | a context reset |
Making decay survive chunking
Everything in chapter 4 assumed that moving a value from position \(j\) to position \(i\) inside a chunk left it unchanged. With decay it does not: it gets multiplied by every \(\alpha\) in between. Define the running product from the chunk's start,
A cumulative product is the multiplicative analogue of a prefix sum — and in practice it is computed as one, in log space, because \(\gamma\) underflows fp16 quickly: \(\log\gamma_i = \sum_{j\le i}\log\alpha_j\), so the ratio \(\gamma_i/\gamma_j\) is a difference of two prefix sums, exponentiated at the last moment.
Then decay enters chapter 4's algorithm in exactly three places, and nowhere else:
- The key–key products inside \(T\) pick up \(\gamma_i/\gamma_j\), because \(u_j\) has decayed on its way to position \(i\).
- The query reading the incoming state is scaled by \(\gamma_i\), the decay accumulated from the chunk boundary to this position.
- The state handed to the next chunk is scaled by \(\gamma_C\), the chunk's total decay, and each key's contribution by \(\gamma_C/\gamma_i\).
# the diff against chapter 4, schematically g = alpha.cumprod(-1) # γ_i : decay from chunk start (done in log space) Gm = g[:, :, None] / g[:, None, :] # γ_i / γ_j : pairwise decay, a C×C matrix K_beta = K * beta[..., None] V_beta = V * beta[..., None] T = -((K_beta @ K.transpose(-1,-2)) * Gm).tril(-1) ← 1. pairwise decay for i in range(1, C): T[i,:i] += (T[i,:,None] * T[:,:i]).sum(-2) T += torch.eye(C) W = T @ (K_beta * g[..., None]) U = T @ V_beta for i in range(L // C): u_i = U[i] - W[i] @ S o_inter = (q_i * g_i) @ S ← 2. query decays from chunk start A_i = ((q_i @ k_i.t()) * Gm).tril() o_intra = A_i @ u_i S = g_C * S + (k_i * (g_C / g_i)).t() @ u_i ← 3. state carries chunk decay O[i] = o_intra + o_inter
The asymptotic cost is unchanged. One extra \(C\times C\) elementwise multiply, one prefix sum of length \(C\), and one extra scalar projection per token. Gated DeltaNet is not a more expensive model than DeltaNet in any way that shows up in a profile.
A fixed-capacity memory needs two verbs, not one. Replace is rank-one and content-addressed: it needs a key and a new value. Release is full-rank and content-free: it needs neither. Chapter 3 built the first. Mamba-2 built the second. Neither is expressible in the other, and this chapter is the observation that you can simply have both — the transition matrix \(\alpha_t(I-\beta_t k_t^{\top}k_t)\) is still rank-one-plus-diagonal, so every parallelisation trick from chapter 4 survives untouched.
\(\alpha_t\) is one number. Every channel of the state decays at the same rate, which means the model must choose a single memory horizon for all of it, every step. But the state is not homogeneous: some of its directions hold things that should persist for the whole document — who is speaking, what language this is, which file we are editing — and others hold things that are stale within a clause, like the last number mentioned. Forcing them onto one timescale means the persistent facts decay too fast or the volatile ones linger too long. There is no setting of a scalar that is right for both. Chapter 6 replaces the scalar with a diagonal.