Part XII — Modern Sequence Architectures: RoPE, FlashAttention & State-Space Models · Chapter 6

Linear attention & kernelized approximations

Hook

Last chapter's n2n^2 came from one specific design choice: softmax normalizes each query's row of scores independently, so nothing in that row can be known until every score in it exists. What if attention didn't need a full row before it could answer?

Intuition

Switch queries. Both numbers move together, every time, because they're computing the same thing two different ways — one rescans all four keys from scratch, the other looks up a state that was built before any query even ran.

Formalize

Drop softmax and score a query against a key with a plain dot product instead — no per-row normalization needed. The double sum every query requires then factors, by ordinary associativity:

j(qikj)vj  =  qi(jkjvj),j(qikj)  =  qi(jkj)\sum_j (q_i \cdot k_j)\, v_j \;=\; q_i \cdot \Big(\sum_j k_j v_j\Big), \qquad \sum_j (q_i \cdot k_j) \;=\; q_i \cdot \Big(\sum_j k_j\Big)
  • qiq_i — the query vector for position ii, the one being scored against every key.
  • kjk_j — the key vector for position jj, one of the keys a query is compared against.
  • vjv_j — the value vector for position jj, the payload retrieved when key jj matches.
  • ii — the index of the query currently being scored.
  • jj — the index ranging over every key (and its paired value) in the sequence.
  1. The sums don't depend on the query

    The parenthesized sums on the right don't mention ii at all — they're the same for every query, so computing them once (a single pass over the keys, O(n)O(n)) and reusing them turns each query into one O(1)O(1) dot product instead of an O(n)O(n) rescan.

  2. Real layers add a feature map for non-negativity

    Real linear-attention layers apply a positive feature map ϕ\phi (commonly elu(x)+1\text{elu}(x)+1, where ELU is short for Exponential Linear Unit) to qq and kk before the dot product, so the "attention weights" stay non-negative the way softmax's do — this chapter uses the identity map to keep every number exact and checkable by hand, but the factoring trick itself doesn't depend on that choice at all.

Play
at n = 64: naive = 4096 ops, factored = 128 ops

The bold curve is the same quadratic from last chapter. The dashed one — 2n2n, not n2n^2 — is what scoring every query the factored way actually costs: one pass to build the running state, one more to evaluate every query against it.

Worked example

Four keys kjk_j and values vjv_j, scored against query q0=(1,0)q_0=(1,0):

  1. The naive way: rescan every key

    Scores, one per key:

    • q0k1=(1,0)(2,1)=2q_0\cdot k_1 = (1,0)\cdot(2,1) = 2
    • q0k2=(1,0)(1,2)=1q_0\cdot k_2 = (1,0)\cdot(-1,2) = -1
    • q0k3=(1,0)(1,1)=1q_0\cdot k_3 = (1,0)\cdot(1,-1) = 1
    • q0k4=(1,0)(0,3)=0q_0\cdot k_4 = (1,0)\cdot(0,3) = 0

    Weighted sum =2(3)+(1)(2)+1(1)+0(4)=6+2+1+0=9= 2(3)+(-1)(-2)+1(1)+0(4) = 6+2+1+0 = 9. Normalizer =21+1+0=2= 2-1+1+0 = 2. Output =9/2=4.5= 9/2 = 4.5.

  2. Build the state once, before any query

    Building s=jkjvjs=\sum_j k_jv_j, one key at a time:

    • k1v1=(2,1)(3)=(6,3)k_1v_1 = (2,1)(3) = (6,3)
    • k2v2=(1,2)(2)=(2,4)k_2v_2 = (-1,2)(-2) = (2,-4)
    • k3v3=(1,1)(1)=(1,1)k_3v_3 = (1,-1)(1) = (1,-1)
    • k4v4=(0,3)(4)=(0,12)k_4v_4 = (0,3)(4) = (0,12)

    Summing: s=(6+2+1+0, 341+12)=(9,10)s = (6+2+1+0,\ 3-4-1+12) = (9,\,10).

    Building z=jkjz=\sum_j k_j: (2,1)+(1,2)+(1,1)+(0,3)=(2+(1)+1+0, 1+2+(1)+3)=(2,5)(2,1)+(-1,2)+(1,-1)+(0,3) = (2+(-1)+1+0,\ 1+2+(-1)+3) = (2,\,5). Neither ss nor zz mentions q0q_0.

  3. Every query is now one dot product
    • q0s=(1,0)(9,10)=9q_0 \cdot s = (1,0)\cdot(9,10) = 9.
    • q0z=(1,0)(2,5)=2q_0 \cdot z = (1,0)\cdot(2,5) = 2.

    Output =9/2=4.5= 9/2 = 4.5 — exactly the naive answer, with the four keys never rescanned.

Checkpoint

Find the query, among the three candidates, whose linear-attention output is the largest.

Pick a query to try it
Summary
j(qikj)vj=qi(jkjvj)\sum_j (q_i\cdot k_j)v_j = q_i \cdot \Big(\sum_j k_jv_j\Big)

This isn't an approximation of attention — for a linear kernel, it's the exact same number, just computed in a different order. The catch real linear-attention layers have to work around is that a plain dot product isn't guaranteed non-negative the way softmax's weights are, which is why ϕ\phi exists in the real formula. The catch this chapter doesn't fix at all: that single running state ss has to summarize the entire key-value history in a fixed-size vector — it can't grow with nn the way softmax's full matrix implicitly can. The next chapter turns that constraint into the entire design of a new architecture: a state-space model that carries exactly one hidden state forward, one token at a time, on purpose.