Chapter 05All of it fades, at one rate

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.

The constraint

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

\[ h \;=\; \frac{\ln 2}{-\ln \alpha} \;\approx\; \frac{0.693}{1-\alpha}\quad\text{for }\alpha\text{ near }1 \]
αhalf-lifewhat that memory is good for
0.96.6 tokensthe immediately preceding phrase; local syntax
0.9969 tokensthe current sentence or paragraph
0.999693 tokensthe current section, a function body, a speaker turn
0.99996,931 tokensthe document; effectively permanent within one context
0instantcontext switch — wipe the board and start over
HOW MUCH OF A FACT SURVIVES, t TOKENS AFTER IT WAS WRITTEN 1 ½ 0 α = 0.9 α = 0.99 α = 0.999 1864512 tokens since the write (log scale) → One scalar per token sets the whole state's memory horizon. It is data-dependent, so the model can hold α near 1 through a passage it wants to remember and drop it at a boundary. But it is one scalar, applied to everything in the state at once. That is chapter 6's problem.
Decay sets a memory horizon. Each curve is αt, the surviving fraction of a fact written t tokens ago. Because α is predicted from the current token rather than fixed, the model can steer between these curves as it reads — but at any instant every association in the state is riding the same one.

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 α onlyDeltaNet β only
Replace one specific factOnly 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 stateOne step, \(\alpha \to 0\).Needs \(d\) separate writes at \(d\) orthogonal keys. In practice, impossible.
Bound the state normYes, geometrically: \(\|S\| \le 1/(1-\alpha)\).Contractive along written directions only; drift elsewhere.
Handle key collisionsNo — 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:

\[ S_t \;=\; \underbrace{\alpha_t}_{\text{forget everything, a little}}\big(\underbrace{I - \beta_t k_t^{\top}k_t}_{\text{forget this one thing, precisely}}\big)\,S_{t-1} \;+\; \underbrace{\beta_t\,k_t^{\top}v_t}_{\text{write}} \] 5.1

α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:

αβBehaviourEquivalent to
10\(S_t = S_{t-1}\), nothing happensa no-op layer
11precise overwrite, no decayDeltaNet · chapter 3
<10uniform decay, additive writeMamba-2 / gated linear attention
1→0additive write, no decaylinear attention · chapter 2
01discard everything, keep only this tokena context reset
α ONLY · MAMBA-2 Everything dims equally. Cannot target one fact. β ONLY · DELTANET One row erased, exactly. Cannot clear the board. α AND β · GATED DELTANET Both, every step, with two independent dials. Two orthogonal questions, asked once per token: β — where do I write, and how hard? α — how fast does everything else fade?
Two dials, two jobs. Neither operation is a special case of the other: β acts on a single rank-one direction, α acts on all d of them. Composing them gives targeted replacement and bulk release in the same step, at the cost of one extra scalar projection per token.

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,

\[ \gamma_i \;=\; \prod_{j \le i} \alpha_j \qquad\Longrightarrow\qquad \text{decay from position } j \text{ to } i \;=\; \prod_{j < m \le i}\alpha_m \;=\; \frac{\gamma_i}{\gamma_j} \] 5.2

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:

  1. The key–key products inside \(T\) pick up \(\gamma_i/\gamma_j\), because \(u_j\) has decayed on its way to position \(i\).
  2. The query reading the incoming state is scaled by \(\gamma_i\), the decay accumulated from the chunk boundary to this position.
  3. 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.

Why this is the right decomposition

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.

What is still wrong

\(\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.