Lucas Sun

An Associative Introduction to Deep Learning

Biology
Graph
Nonlinear Rank One
Python
dendrites · soma · terminal
=
=
=
if match(x, key):
    out += value
ϕ ⁣(xu)v  =  ϕ ⁣(ux)v\textcolor{#f59e0b}{\phi}\!\left(x\,\textcolor{#10b981}{u}^{\top}\right)\textcolor{#b07cff}{v}\;=\;\textcolor{#f59e0b}{\phi}\!\left(\langle \textcolor{#10b981}{u}|x\rangle\right)\textcolor{#b07cff}{|v\rangle}
=
=
=
memory = {
    key1: value1,
    key2: value2,
    key3: value3,
    key4: value4,
}
for key, value in memory:
    if match(x, key):
        out += value
ϕ ⁣(xU)V  =  iϕ ⁣(uix)vi\textcolor{#f59e0b}{\phi}\!\left(x\,\textcolor{#10b981}{U}^{\top}\right)\textcolor{#b07cff}{V}\;=\;\sum_i \textcolor{#f59e0b}{\phi}\!\left(\langle \textcolor{#10b981}{u_i}|x\rangle\right)\textcolor{#b07cff}{|v_i\rangle}

Neural networks are fundamentally associative. You might be tempted to view them as functions wiggling in space, but thinking of them as computing associations leads far more directly to the architectural, mechanistic, and theoretical developments of the past decade. This post won't follow the conventional ordering for learning the subject. It is meant to sit beside the standard guides and expose the structure they leave implicit. I assume some linear algebra and multivariable calculus, though the parts that carry weight get rebuilt as they arrive: if you know those tools already, the aim is to hand you another lens on them, and if you don't, most of what follows survives the translation. By the end the same structure should be visible in networks of every kind, which is what makes the more advanced material approachable.

Directions, not coordinates#

Send xAxx \mapsto Ax for any invertible AA, every read uuA1u \mapsto uA^{-1}, every write vAvv \mapsto Av. The two cancel wherever they meet, so the network computes what it computed before. This is all of GL(d)GL(d) and not just the rotations: an MLP and an attention score never measure a length or an angle. Rotations are what is left once RMSNorm and weight decay insist on a norm.

xx, and the level sets of uu
AxAx, and the level sets of uA1uA^{-1}
the arrow crosses 2.62.6 lines either way: ux\langle u|x\rangle needs no metric

A read and a write are therefore different kinds of object. A write is a vector, an arrow you add to the stream. A read is a covector: not an arrow but a stack of level sets, and applying it to a vector counts crossings. Counting survives AA; lengths and angles do not.

That is the case for bras and kets here, and it is not the case physics makes. The syntax closes a bra against a ket and nothing else, so ux\langle u|x\rangle is a number and vu|v\rangle\langle u| is an operator, while nothing contracts two bras into a number. In quantum mechanics that restriction is cosmetic, since the inner product turns any ket into a bra. A residual stream ships without that converter, so the restriction has content: the notation is a type system that refuses exactly the expressions a metric would be needed to define.

  • ux\langle u|x\rangle, a read applied to the stream: fine.
  • vu|v\rangle\langle u|, read then write: fine, and it is one neuron.
  • u2v1\langle u_2|v_1\rangle, a later read against an earlier write: fine, and it is the virtual weight between two layers.
  • u1u2\langle u_1|u_2\rangle, or a cosine between two reads, or between a read and a write: needs a metric nobody supplied.

ϕ\phi is the exception. It acts on Rh\mathbb{R}^h, which is not the stream but the space indexed by the neurons themselves, so it has a basis already; elementwise means something there and nothing on the stream. (RMSNorm is the other exception, and LayerNorm's mean subtraction additionally singles out the all-ones direction.)

One sum covers the rest of the post:

r(q)  =  i=1nϕi ⁣(k1q, , knq)vi(Associative Memory)r(q)\;=\;\sum_{i=1}^{n}\phi_i\!\left(\langle k_1|q\rangle,\ \ldots,\ \langle k_n|q\rangle\right)|v_i\rangle \tag{Associative Memory}

A query is bracketed against every key, the numbers that come back become coefficients, and the coefficients mix the values. Three choices generate almost everything below: where the keys and values come from, how much of the bracket vector each coefficient is allowed to see, and whether the memory is rebuilt from scratch at every step or carried forward and edited.

An MLP reads its keys and values out of its weights, and each ϕi\phi_i sees only its own bracket. Softmax attention computes them from the sequence, and every ϕi\phi_i sees all the brackets at once. Everything outside this form is the normalization gains and biases: 0.031% of GPT-2 small, 0.005% of a five-billion-parameter model, and foldable into the neighbouring matrices in any case.

1. A dictionary made of weights#

The simplest case is the one where the memory is the weights. Let an MLP with activation function ϕ\phi have a hidden dimension hh. Then:

MLP(x)=Woutϕ ⁣(Winx+bin)+bout=[w1outwhout]ϕ ⁣([w1inw2inw3inwhin]x+[b1inb2inb3inbhin])+bout=[w1outwhout]ϕ ⁣([w1inx+b1inw2inx+b2inw3inx+b3inwhinx+bhin])+bout=i=1hϕ ⁣(wiinx+biin)wiout+bout.\begin{aligned} \mathrm{MLP}(|x\rangle) &= W^{\mathrm{out}}\,\phi\!\left(W^{\mathrm{in}}|x\rangle + b^{\mathrm{in}}\right) + |b^{\mathrm{out}}\rangle \\[0.45em] &= \left[ \begin{array}{ccc} \rule{0.4pt}{1.15em} & & \rule{0.4pt}{1.15em} \\[0.1em] |w_1^{\mathrm{out}}\rangle & \cdots & |w_h^{\mathrm{out}}\rangle \\[0.1em] \rule{0.4pt}{1.15em} & & \rule{0.4pt}{1.15em} \end{array} \right] \phi\!\left( \left[ \begin{array}{c} \rule{1.5em}{0.4pt}\,\langle w_1^{\mathrm{in}}|\,\rule{1.5em}{0.4pt}\\[0.75em] \rule{1.5em}{0.4pt}\,\langle w_2^{\mathrm{in}}|\,\rule{1.5em}{0.4pt}\\[0.75em] \rule{1.5em}{0.4pt}\,\langle w_3^{\mathrm{in}}|\,\rule{1.5em}{0.4pt}\\[0.25em] \hspace{2.1em}\vdots\hspace{2.1em}\\[0.25em] \rule{1.5em}{0.4pt}\,\langle w_h^{\mathrm{in}}|\,\rule{1.5em}{0.4pt} \end{array} \right] |x\rangle + \left[ \begin{array}{c} b_1^{\mathrm{in}}\\[0.75em] b_2^{\mathrm{in}}\\[0.75em] b_3^{\mathrm{in}}\\[0.25em] \vdots\\[0.25em] b_h^{\mathrm{in}} \end{array} \right] \right) + |b^{\mathrm{out}}\rangle \\[0.45em] &= \left[ \begin{array}{ccc} \rule{0.4pt}{1.15em} & & \rule{0.4pt}{1.15em} \\[0.1em] |w_1^{\mathrm{out}}\rangle & \cdots & |w_h^{\mathrm{out}}\rangle \\[0.1em] \rule{0.4pt}{1.15em} & & \rule{0.4pt}{1.15em} \end{array} \right] \phi\!\left( \left[ \begin{array}{c} \langle w_1^{\mathrm{in}}|x\rangle + b_1^{\mathrm{in}}\\[0.75em] \langle w_2^{\mathrm{in}}|x\rangle + b_2^{\mathrm{in}}\\[0.75em] \langle w_3^{\mathrm{in}}|x\rangle + b_3^{\mathrm{in}}\\[0.25em] \vdots\\[0.25em] \langle w_h^{\mathrm{in}}|x\rangle + b_h^{\mathrm{in}} \end{array} \right] \right) + |b^{\mathrm{out}}\rangle \\[0.45em] &= \sum_{i=1}^{h} \phi\!\left(\langle w_i^{\mathrm{in}}|x\rangle + b_i^{\mathrm{in}}\right)\, |w_i^{\mathrm{out}}\rangle + |b^{\mathrm{out}}\rangle. \end{aligned}

This form reveals a simple structure: WinW^\mathrm{in} acts as a list of keys (the lookup), ϕ\phi acts as a threshold (if-else statement), and WoutW^\mathrm{out} acts as a list of values (the table). Neither list depends on the input. The layer answers every query out of the same hh pairs, fixed at training time, and all the input decides is which coefficients come back. How many distinct associations those hh pairs can hold is the next section.

A weight matrix reads two ways: its rows are bras, each producing one coefficient; its columns are kets, each scaled and summed. This distinction becomes critical when x|x\rangle has a representational preference. In residual architectures: If x|x\rangle immediately followed an activation function like ReLU or softmax, it prefers the column form (since non-linear activations make dot products meaningless). If an activation is to be applied to the result, it prefers the row form. Otherwise, it prefers the SVD form. When researchers apply linear projections, they usually have one of these forms in mind, and design architectures to apply these forms in specific, meaningful orders.

Connection to optimizer design (NorMuon) NorMuon, the current SOTA optimizer, requires setting the "normalization dimension" which depends on whether the matrix is row-form or column-form. The distinction between row-form and column-form matrices therefore has practical consequences for training.

As a corollary, consider the squeeze-and-excitation layer (SE) introduced by Hu et al.. We see the same structure as the MLP, where we first apply global pooling to obtain a single vector, then split the vector into multiple distinct "heads" or convolution groups. This is actually kind of similar to mixture-of-experts without sparsity.

2. More keys than dimensions#

An informal bra-ket definition of effective rank is

Mi=1reffviki,M \approx \sum_{i=1}^{r_{\mathrm{eff}}} |v_i\rangle\langle k_i|,

so reffr_{\mathrm{eff}} is roughly the number of key-value pairs needed for a good approximation. This makes the structural comparison clear:

  • linear map: fixed coefficients, fixed key-value pairs,
  • MLP: nonlinear coefficients, fixed key-value pairs,
  • attention: nonlinear coefficients, token-dependent key-value pairs.

The effective rank is bounded by the number of pairs on offer. For an MLP that is at most the hidden dimension hh; for a single attention head at one token it is at most the number of tokens attended to. In both cases the operator is a bounded sum of ket-bras in a finite-dimensional space, and the nonlinearity comes entirely from the input-dependent coefficients:

ϕ ⁣(wiinx+biin),ϕi ⁣(k1qt,,ktqt).\phi\!\left(\langle w_i^{\mathrm{in}}|x\rangle + b_i^{\mathrm{in}}\right), \qquad \phi_i\!\left( \langle k_1|q_t\rangle,\dots,\langle k_t|q_t\rangle \right).

That bound is on the number of pairs. The number of features a layer can traffic in is a different question, and a much less restrictive one, because a feature is a direction rather than a coordinate. Draw NN unit vectors at random in dd dimensions and their pairwise brackets concentrate near 1/d1/\sqrt{d}: at d=768d=768, a thousand random directions overlap by at most 0.1830.183 and ten thousand by at most 0.2030.203. Exact orthogonality caps you at dd; near-orthogonality does not.

Retrieval is where the limit appears. Reading a linear memory S=jvjujS=\sum_j |v_j\rangle\langle u_j| with a stored key returns

Sui  =  vi  +  jiujuivj,S|u_i\rangle \;=\; |v_i\rangle \;+\; \sum_{j\neq i}\langle u_j|u_i\rangle\,|v_j\rangle,

one wanted value plus a little of every other. The crosstalk grows like m/d\sqrt{m/d} while the signal stays at 11, so the two are comparable around m=dm=d; picking the nearest value is forgiving enough to survive a few multiples past that, and no further.

ϕ\phi holds it off by discarding small brackets before they can mix values in. How many pairs survive depends on how sharply it does that:

0%25%50%75%100%1281k8k64k256kone pair per dimensionpairs stored in one memorysoftmaxReLU2linear, ReLU
d=128d=128, random unit keys and values; readouts ϕ(z)=z\phi(z)=z, max(z,0)\max(z,0), max(z,0)2\max(z,0)^2 and softmax(30z)\operatorname{softmax}(30z); accuracy of recovering vi|v_i\rangle from ui\langle u_i|

A linear readout is down to half accuracy at 12d12d pairs and a ReLU at 24d24d. Squaring the ReLU carries it to 768d768d, and a softmax readout has not begun to fail at 2048d2048d, where it is holding two thousand pairs for every dimension it has. Capacity is set by the sharpness of ϕ\phi, not by the dimension, and the sharpest choice in common use is the exponential one, which is what softmax attention applies.

3. Everything writes to the same place#

A block does not replace the representation, it adds to it. Every dictionary in the network therefore reads from and writes into one shared space, and what travels between layers is a running sum.

Composition across layers is then immediate. A key in a later layer meets a value written by an earlier one, and all that passes between them is the number uv\langle u_\ell|v_{\ell'}\rangle: how much the later read cares about the earlier write. It is a covector against a vector, so it is a legal contraction, computable from the two weight matrices without running the model and without choosing coordinates. This is the quantity usually called a virtual weight.

It also explains why the packing above matters. Every layer writes into the same stream, so features have no choice but to coexist there as directions.

4. A dictionary the sequence writes for itself#

attentionMLP123456token position
one block at six positions, residual stream drawn 88 lanes wide: each sublayer reads the stream, and its output is added back. The MLP keeps its hh entries everywhere; attention holds one vjkj|v_j\rangle\langle k_j| per token it can see

The MLP's entries are fixed once training ends. Attention builds its entries out of the sequence: at position tt the pairs viki|v_i\rangle\langle k_i| are computed from the tokens already seen, so every position reads from a different dictionary, and that dictionary gains one entry per token. The diagram above draws exactly that: the MLP row holds the same hh entries everywhere while the attention row grows.

The read has the same shape as an MLP's, with one change. An MLP coefficient depends only on its own bracket. An attention coefficient is normalised against all the others:

Attn(qt)=i=1tϕi ⁣(k1qt,,ktqt)vi,ϕi=softmaxi.\mathrm{Attn}(|q_t\rangle) = \sum_{i=1}^{t} \phi_i\!\left(\langle k_1|q_t\rangle,\dots,\langle k_t|q_t\rangle\right)|v_i\rangle, \qquad \phi_i = \operatorname{softmax}_i .

Set beside the MLP:

MLP(x)=i=1mϕ ⁣(wiinx+biin)wiout+bout,Attn(qt)=i=1tsoftmaxi ⁣(k1qt,,ktqt)vi.\begin{aligned} \mathrm{MLP}(|x\rangle) &= \sum_{i=1}^{m} \phi\!\left(\langle w_i^{\mathrm{in}}|x\rangle+b_i^{\mathrm{in}}\right) |w_i^{\mathrm{out}}\rangle+|b^{\mathrm{out}}\rangle,\\[8pt] \mathrm{Attn}(|q_t\rangle) &= \sum_{i=1}^{t} \operatorname{softmax}_i\!\left(\langle k_1|q_t\rangle,\dots,\langle k_t|q_t\rangle\right) |v_i\rangle. \end{aligned}

Two differences: where the entries come from, and whether the coefficients are allowed to see each other. The next section removes the second.

Where did the output projection go?

A head contributes iaiWOWVxi\sum_i a_i\,W^OW^Vx_i to the stream, and those two matrices never appear apart, so vi|v_i\rangle above already stands for the composite. Splitting them is a statement about rank rather than about the map: with head dimension dhd_h below the model dimension, WOWVW^OW^V is a rank-dhd_h operator from the stream back into the stream, and the factorisation is how that rank gets imposed. The same holds on the read side, where the bracket only ever depends on the combination WKWQW^{K\top}W^Q.

5. When the cache collapses into one matrix#

Softmax couples the coefficients, and the coupling forces a cache. Evaluating softmaxi\operatorname{softmax}_i at position tt needs every bracket at position tt, so every ki\langle k_i| and every vi|v_i\rangle has to still be there: O(T)O(T) memory per token, O(T2)O(T^2) across the sequence.

Remove the coupling. Let each coefficient see its own bracket alone, and take the simplest such function, the identity:

ot=i=1tkiqtvi.|o_t\rangle = \sum_{i=1}^{t} \langle k_i|q_t\rangle\, |v_i\rangle.

A bracket is a number, so it can be written on either side of the ket. Move it across, then move the brackets:

ot=i=1tvikiqt=(i=1tviki)qt.\begin{aligned} |o_t\rangle &= \sum_{i=1}^{t} |v_i\rangle \langle k_i|q_t\rangle \\ &= \left(\sum_{i=1}^{t} |v_i\rangle\langle k_i|\right)|q_t\rangle. \end{aligned}

The two lines are one string of symbols regrouped, and the step is associativity of composition. The parenthesis now depends on tt only through the range of the sum, so it can be carried forward instead of rebuilt:

St:=i=1tviki,ot=Stqt,St=St1+vtkt.S_t := \sum_{i=1}^{t} |v_i\rangle\langle k_i|, \qquad |o_t\rangle = S_t|q_t\rangle, \qquad S_t = S_{t-1} + |v_t\rangle\langle k_t|.

The cache is gone. What crosses from one token to the next is a single dv×dkd_v\times d_k matrix with every pair ever written superposed inside it: the memory of section 1, with its entries supplied by the sequence rather than by training.

6. Forget to remember#

Superposing every pair into one matrix brings back the problem from section 2: keys that resemble each other cannot be read apart. Three characters in a sloppy piece of LLM-generated fiction, Elias (magical and brave), Elara (brave, not magical) and Silas (magical, cautious). Ask for the one who is both. Elias scores highest, but Elara and Silas score high too, so the read returns a blend. Raise the sharpness and see which readout can separate them:

Linear attention tops out near 79%79\% of the readout coming from the right entry, however hard the query pushes. Softmax keeps sharpening, because its coefficients are computed against each other and can starve the runners-up. A linear readout has to return everything it holds, in proportion.

Why no recurrence of this kind recalls perfectly. For a fixed state, ot=Stqt|o_t\rangle=S_t|q_t\rangle is a linear function of the query, and the state does not depend on the query at all. Softmax at low temperature is not linear: place NN keys evenly around a circle in a two-dimensional query space with vi=ei|v_i\rangle=|e_i\rangle, and it sends the query to whichever ei|e_i\rangle it sits nearest, a piecewise-constant map onto NN independent directions. No linear map does that, at any state size. The gap can only be narrowed. Two angles of attack follow.

A. Letting old entries fade#

Transformers get temporal structure from Rotary Positional Encodings, which rotate every query and key by an angle proportional to position. The bracket then depends on the gap tit-i rather than on tt and ii separately, and it decays as the gap grows. A head that needs to reach far back can learn to undo the rotation, which is how induction heads survive it.

How RoPE works Attention is permutation-invariant by default: "the dog ate the man" and "the man ate the dog" produce the same attention scores without positional information. Early transformers used learnable positional embeddings, but these required many parameters and limited the model to its training context length. RoPE instead applies a fixed rotation to each pair of dimensions in the query and key vectors, with the rotation angle proportional to the token position. This means the dot product kiqt\langle k_i | q_t \rangle depends on the relative distance tit - i, not on absolute positions, naturally encouraging nearer tokens to attend to each other more strongly.

Each pair of dimensions turns at its own frequency. Drag the position and watch the bracket fall off with distance:

A recurrence can do something stronger, because it can pick how fast to forget and re-pick at every token. Give each channel of the key its own decay factor:

St=St1diag(γt)+vtkt,γt[0,1]dhS_t = S_{t-1}\operatorname{diag}\left(\gamma_t\right) + |v_t\rangle\langle k_t|, \quad \gamma_t \in {\left[0,1\right]}^{d_h}

RoPE rotates at a rate fixed per dimension pair; this shrinks at a rate learned per channel and recomputed per token. Without it, NN entries sharing a key drown out the (N+1)(N+1)-th, which can contribute at most 1/N1/N of the readout however important it is. With it, the old entries can be pushed down before the new one is written.

Decaying per channel looks like it fixes a preferred basis, which should be suspicious after the opening section. The restriction is only apparent: decay along any fixed set of linearly independent directions is the same model as decay along the channels, up to an invertible change of coordinates that folds into the key and query weights and leaves every bracket unchanged.

Exact proof

Let the fixed decay features be the bras

f1,,fdhHk,\langle f_1|,\dots,\langle f_{d_h}| \in H_k^*,

where we assume they are linearly independent. If we only wish to decay along some smaller collection of features, we extend that collection to a basis of HkH_k^* and set the unused decay coefficients to 11.

Because {fj}j=1dh\{\langle f_j|\}_{j=1}^{d_h} is a basis of HkH_k^*, there exists a unique dual basis of kets

g1,,gdhHk|g_1\rangle,\dots,|g_{d_h}\rangle \in H_k

such that

figj=δij.\langle f_i|g_j\rangle=\delta_{ij}.

Now suppose we want to decay the coordinates of a key-space vector along these fixed feature bras by factors

γt=(γt,1,,γt,dh)[0,1]dh.\gamma_t=(\gamma_{t,1},\dots,\gamma_{t,d_h})\in[0,1]^{d_h}.

The corresponding linear operator on key space is

Dt:=j=1dhγt,jgjfj.D_t:=\sum_{j=1}^{d_h}\gamma_{t,j}\,|g_j\rangle\langle f_j|.

Indeed, every xHk|x\rangle\in H_k has the decomposition

x=j=1dhgjfjx,|x\rangle=\sum_{j=1}^{d_h}|g_j\rangle\langle f_j|x\rangle,

so

Dtx=j=1dhγt,jgjfjx,D_t|x\rangle =\sum_{j=1}^{d_h}\gamma_{t,j}\,|g_j\rangle\langle f_j|x\rangle,

which shows that DtD_t scales the jj-th feature coordinate fjx\langle f_j|x\rangle by exactly γt,j\gamma_{t,j}.

Thus the most general linear-attention state update with fixed per-feature decay is

St=St1Dt+vtkt.S_t=S_{t-1}D_t+|v_t\rangle\langle k_t|.

Now define the coordinate map

F:HkRdh,Fx=[f1xfdhx].F:H_k\to\mathbb{R}^{d_h}, \qquad F|x\rangle= \begin{bmatrix} \langle f_1|x\rangle\\ \vdots\\ \langle f_{d_h}|x\rangle \end{bmatrix}.

Since the feature bras form a basis of HkH_k^*, FF is invertible. Moreover, by construction,

Fgj=ej,F|g_j\rangle=e_j,

so

gj=F1ej.|g_j\rangle=F^{-1}e_j.

Hence

Dt=j=1dhγt,jgjfj=j=1dhγt,jF1ejejF=F1diag(γt)F.D_t =\sum_{j=1}^{d_h}\gamma_{t,j}\,|g_j\rangle\langle f_j| =\sum_{j=1}^{d_h}\gamma_{t,j}\,F^{-1}e_j e_j^\top F =F^{-1}\operatorname{diag}(\gamma_t)F.

We now pass to these feature coordinates. Define

q~t:=Fqt,k~t:=ktF1,S~t:=StF1.|\tilde q_t\rangle:=F|q_t\rangle, \qquad \langle \tilde k_t|:=\langle k_t|F^{-1}, \qquad \tilde S_t:=S_tF^{-1}.

Then

S~t=StF1=(St1Dt+vtkt)F1=St1F1diag(γt)+vtktF1=S~t1diag(γt)+vtk~t.\begin{aligned} \tilde S_t &=S_tF^{-1}\\ &=\left(S_{t-1}D_t+|v_t\rangle\langle k_t|\right)F^{-1}\\ &=S_{t-1}F^{-1}\operatorname{diag}(\gamma_t)+|v_t\rangle\langle k_t|F^{-1}\\ &=\tilde S_{t-1}\operatorname{diag}(\gamma_t)+|v_t\rangle\langle \tilde k_t|. \end{aligned}

This is exactly channel-wise decay.

It remains to check that this change of coordinates does not alter the actual computation. First,

S~tq~t=StF1Fqt=Stqt,\tilde S_t|\tilde q_t\rangle = S_tF^{-1}F|q_t\rangle = S_t|q_t\rangle,

so the readout is unchanged.

Second, all key-query dot products are preserved:

k~iq~t=kiF1Fqt=kiqt.\langle \tilde k_i|\tilde q_t\rangle = \langle k_i|F^{-1}F|q_t\rangle = \langle k_i|q_t\rangle.

So the transformed model computes exactly the same similarities and exactly the same output as the original one.

Therefore any linear attention mechanism with decay along arbitrary fixed linearly independent feature bras is exactly equivalent to one with channel-wise decay after an invertible change of coordinates on key/query space. In this sense, channel-wise decay loses no expressive power relative to fixed-direction decay; it chooses a particular coordinate system in which those fixed features become the standard channels. \square

B. Erasing before writing#

Decay forgets indiscriminately. Often the model needs the opposite: a large memory it must edit at one address. Alice \rightarrow sweater, Bob \rightarrow hoodie, Charlie \rightarrow leather jacket, and Alice changes into a coat. Everyone else's entry should survive untouched.

The state holds associations as ket-bras, and the key being overwritten is known. So read the old value out of the state with that key, rt:=St1κt|r_t\rangle := S_{t-1}|\kappa_t\rangle, rebuild the pair it came from as rtκt|r_t\rangle\langle \kappa_t|, and subtract it before writing the new one. The vector κt|\kappa_t\rangle acts as a pseudo-query; take κt:=kt/kt\kappa_t := k_t/\lVert k_t\rVert for now; section C returns to what that normalisation assumes.

Explicitly why this operation removes the old information Define vold=St1κt|v_{\text{old}}\rangle=S_{t-1}|\kappa_t\rangle. Now, write St1S_{t-1} as St1=voldκt+iviei.S_{t-1} = |v_{\text{old}}\rangle\langle \kappa_t| + \sum_i |v_i\rangle\langle e_i|.

And by definition, (iviei)κt=0\left(\sum_i |v_i\rangle\langle e_i|\right)|\kappa_t\rangle=0, since otherwise St1κtS_{t-1}|\kappa_t\rangle would not equal vold|v_{\text{old}}\rangle, contradicting its definition.

Thus, when we subtract:

St=St1St1κtκt=(voldκt+iviei)(voldκtκt+(iviei)κt)=(voldκt+iviei)(vold1+0)=iviei\begin{aligned} S_t &= S_{t-1} - S_{t-1}|\kappa_t\rangle\langle \kappa_t|\\ &= \left( |v_{\text{old}}\rangle\langle \kappa_t| + \sum_i |v_i\rangle\langle e_i| \right) - \left( |v_{\text{old}}\rangle\langle \kappa_t|\kappa_t\rangle + \left(\sum_i |v_i\rangle\langle e_i|\right)|\kappa_t\rangle \right)\\ &= \left( |v_{\text{old}}\rangle\langle \kappa_t| + \sum_i |v_i\rangle\langle e_i| \right) - \left( |v_{\text{old}}\rangle\cdot1 + 0\right)\\ &= \sum_i |v_i\rangle\langle e_i| \end{aligned}

Now, when we query St1κtS_{t-1}|\kappa_t\rangle we get (iviei)κt=0\left(\sum_i |v_i\rangle\langle e_i|\right)|\kappa_t\rangle=0.

Hence, when we add the new value vtκt|v_t\rangle\langle \kappa_t| to the state, future queries yield the clean result vt|v_t\rangle.

A full overwrite is too blunt for anything that changes gradually, a character's personality over a chapter for instance, so let the model erase and write only a fraction βt\beta_t. That is the delta rule:

St=St1 ⁣(Iβtκtκt)+βtvtκtS_t = S_{t-1}\!\left(I - \beta_t|\kappa_t\rangle\langle \kappa_t|\right) + \beta_t\,|v_t\rangle\langle \kappa_t|

Three pairs stored in a two-dimensional state. Erase at a chosen key and write a new value:

C. Why the two do not compose#

Put the two together and the recurrence is

St=St1diag(γt) ⁣(Iβtκtκt)+βtvtκt.S_t = S_{t-1} \operatorname{diag}\left(\gamma_t\right) \!\left(I - \beta_t|\kappa_t\rangle\langle \kappa_t|\right) + \beta_t\,|v_t\rangle\langle \kappa_t|.

The halves sit awkwardly. Decay is stated in a fixed basis; erasure happens along a direction that moves with the data. The obvious repair is the one that worked in section A: fold the change of coordinates FF into the keys and queries, and hope the delta term comes through unharmed.

It does not. Conjugation sends the projector κtκt|\kappa_t\rangle\langle\kappa_t| to FκtκtF1F|\kappa_t\rangle\langle\kappa_t|F^{-1}. That is still rank one and still idempotent, and it still contracts to 11 against its own key, but it is no longer symmetric: it erases along FκtF|\kappa_t\rangle the component measured by κtF1\langle\kappa_t|F^{-1}, and those are two different directions. An orthogonal projection has become an oblique one, so the combined recurrence is not a reparameterisation of the fixed-basis one. The models differ.

This is the opening section's warning arriving with consequences. Writing κtκt|\kappa_t\rangle\langle\kappa_t| uses one vector as both a read and a write. Nothing in a vector space lets you do that; it takes a metric to turn a ket into a bra, and dividing ktk_t by kt\lVert k_t\rVert is where the metric quietly enters. Channel-wise decay picks a basis, the delta rule picks an inner product, and there is no reason for the two choices to agree. That mismatch is what sent me down the rabbit hole this post came out of.

D. Every recurrence is attention with moving keys#

Unroll the recurrence, writing Am:=diag(γm)(Iβmκmκm)A_m := \operatorname{diag}(\gamma_m)\bigl(I-\beta_m|\kappa_m\rangle\langle\kappa_m|\bigr) and starting from S0=0S_0=0:

St=i=1tβiviκiAi+1Ai+2At,S_t = \sum_{i=1}^{t}\beta_i\,|v_i\rangle\langle \kappa_i|\,A_{i+1}A_{i+2}\cdots A_{t},

with the factors ordered left to right in increasing mm, since they do not commute. The query then reads

ot=Stqt=i=1tβiκiAi+1Atqtvi.|o_t\rangle = S_t|q_t\rangle = \sum_{i=1}^{t} \beta_i\,\langle \kappa_i|A_{i+1}\cdots A_{t}|q_t\rangle\,|v_i\rangle .

Everything between the two ends of that bracket belongs to the key side, so collect it into an effective key

k~i(t):=βiκim=i+1tdiag(γm)(Iβmκmκm),\langle\tilde{k}_i^{(t)}| := \beta_i \langle \kappa_i| \prod_{m=i+1}^{t} \operatorname{diag}(\gamma_m) \bigl(I - \beta_m|\kappa_m\rangle\langle \kappa_m|\bigr),

and the output is a weighted sum of values, exactly as in attention:

ot=i=1tk~i(t)qtvi.|o_t\rangle = \sum_{i=1}^{t} \langle\tilde{k}_i^{(t)}|q_t\rangle\, |v_i\rangle.

A key is not fixed once written. It is transported forward by every operator that arrives after it, so what a token scores at position tt depends on the whole path from ii to tt. This is the same duality that connects state-space models to attention. Note the superscript: there are O(T2)O(T^2) effective keys, one per pair of positions.

Two things follow. The first is that a recurrence has attention patterns after all, k~i(t)qt\langle\tilde{k}_i^{(t)}|q_t\rangle, which can be plotted and read the way softmax maps are; that is the subject of a later post on interpreting non-softmax attention.

The second is that nothing stops us from putting the coupling back. Run softmax over the effective scores and the result is PaTH attention:

At,j=softmaxj ⁣(k~j(t)qt),A_{t,j} = \operatorname{softmax}_j\!\left(\langle\tilde{k}_j^{(t)}|q_t\rangle\right),

with the values recombined exactly as in ordinary attention:

ot=j=1tAt,jvj.|o_t\rangle = \sum_{j=1}^{t} A_{t,j}\,|v_j\rangle.

7. Where the brain writes and erases#

Nothing above was derived from neuroscience. The cerebellum, whose circuit was mapped in enough detail by the 1960s to be modelled directly, is built from these same parts.

molecularPurkinjegranularwhite matter
mossy and parallel fibres, the keys ki\langle k_i|climbing fibre, the errorPurkinje axon, the value v|v\rangle
the granule layer expands a handful of mossy fibres into a sparse code, one Purkinje cell reads about 150,000150{,}000 parallel fibres at once, and a single climbing fibre is the only line that writes

Read the circuit from the bottom. Mossy fibres bring in the input. The granular layer expands it: about 5050 billion granule cells in a human cerebellum, more than every other neuron in the brain put together, each sampling only a handful of mossy inputs and firing sparsely. That expansion is section 2 built out of cells. A few thousand incoming fibres become an enormous, sparse, nearly decorrelated set of keys, and sparsity is what keeps the brackets between them small.

Each granule cell axon rises into the molecular layer and splits into a parallel fibre running for millimetres across the sheet, passing through the dendritic fans of hundreds of Purkinje cells on the way. One Purkinje cell sits in the path of on the order of 150,000150{,}000 parallel fibres, and its output is the weighted sum of them: a read of the whole key set at once, and the only output the cerebellar cortex has.

Then there is the climbing fibre. Each Purkinje cell receives exactly one, from the inferior olive, and it makes hundreds of contacts on the proximal dendrites, so a single one of its spikes is enough to seize the whole cell. When it fires, it drives long-term depression at precisely the parallel-fibre synapses that were active alongside it. A weight change proportional to presynaptic activity times an error delivered on a separate line is the delta rule, and Albus wrote it down as one in 1971.

It is the delta rule rather than plain Hebbian storage because of what the olive carries. It signals error, not target, and the deep nuclei project back onto it inhibitorily, so as a Purkinje cell learns to predict, its own output silences its teacher. The write shrinks in proportion to what is already stored. That is the term the delta rule subtracts before writing:

ΔS    β(vtSt1κt)κt,\Delta S \;\propto\; \beta\left(|v_t\rangle - S_{t-1}|\kappa_t\rangle\right)\langle \kappa_t| ,

which is the update of section 6B rearranged, with St1κtS_{t-1}|\kappa_t\rangle playing the part the nucleo-olivary pathway plays.

The hippocampus supplies the other half. CA3's recurrent collaterals, where each pyramidal cell contacts thousands of its neighbours, are a recurrent matrix storing patterns as a sum of outer products, and querying it with a fragment of a stored pattern returns the whole one. That is SqS|q\rangle with a corrupted q|q\rangle, and Marr described it as such in 1971, before Hopfield made the same structure famous. Upstream of it, the dentate gyrus takes cortical input and re-codes it sparsely into a far larger population, which is the same defence against collision that section 6 needed: Elias and Elara are pushed apart before anything is written, because once they are superposed no readout can separate them.

Hippocampus and neocortex store the same kind of thing at very different write strengths. The hippocampus writes at high β\beta, changing its readout after one exposure, which is what episodic memory requires and also why its representations must be kept nearly orthogonal: a large β\beta on overlapping keys would overwrite the neighbours. The neocortex writes at low β\beta over interleaved repetitions, which is slow and needs replay to work at all, but tolerates dense overlapping codes and accumulates structure rather than episodes. The difference is β\beta, and it is the standing account of why we have both.

These are claims about what the circuits compute, not that the brain runs gradient descent. Whether parallel-fibre LTD is sufficient for learning has been argued over for decades. The wiring is not in dispute: an expansion into sparse keys, a single reader over all of them, one line for the error.

8. Why a dictionary is enough#

One object keeps reappearing: a set of key-value pairs, a score of the query against every key, and a sum of values weighted by those scores. The MLP fixes its pairs during training, attention builds them from the sequence, and a linear recurrence collapses them into a single matrix. Only two things vary across them: where the pairs come from, and whether the scores may see one another.

Text is power-law distributed, and a memory holding a few common associations and a long tail of rare ones is the right shape for it. That is why something this plain goes so far. Where the data lacks that structure the dictionary matters less: Leela Chess Zero can cut MLP hidden width, and with it the number of stored pairs, with little effect on strength, which suggests its capacity goes into computing over the position rather than into recalling memorised moves.

Cite this post
@online{associative-introduction,
  author    = {Lucas Sun},
  title     = {An Associative Introduction to Deep Learning},
  year      = {2026},
  month     = {04},
  day       = {28},
  url       = {https://xtimecrystal.com/posts/260428-associative-introduction/},
}