← BACK TO THE NOTEBOOK
DEEP LEARNING / FIELD NOTE 004

Linear attention: change the order.

A different kernel, a useful matrix identity, and a path around the quadratic attention matrix.

On this page Explore the sections +

Standard attention constructs pairwise interactions between tokens. As the sequence grows, that matrix grows quadratically. Kernel-based linear attention asks whether we can aggregate the keys and values first, then query the aggregate.

The answer involves changing the attention kernel. You cannot simply move parentheses through the softmax operation.

The associative trick

Replace softmax attention with a positive feature-map kernel \(\phi(q)^\top\phi(k)\). For one query, the normalized output is:

$$ y_i = \frac{\phi(q_i)^\top\left(\sum_j\phi(k_j)v_j^\top\right)} {\phi(q_i)^\top\left(\sum_j\phi(k_j)\right)}. $$
READ THE EQUATION

Accumulate transformed-key/value products and transformed keys, then let the query read and normalize those accumulated states.

TermWhat it is and doesWhat it controls
\(y_i,q_i,k_j,v_j\)Output and query at receiver i; key and value at source j.Who reads, how sources match, and what content they contribute.
\(\phi\)A chosen feature map into a kernel feature space.Defines the attention kernel; this choice changes the model from ordinary softmax attention.
\(\top\)Transpose. Transformed vectors are treated as columns in this formula.Makes the indicated inner and outer products compatible.
\(\phi(k_j)v_j^\top\), \(\sum_j\)An outer-product matrix per source, accumulated across sources.Stores feature-weighted value content without a pairwise query–key matrix.
NumeratorA transformed query row reads the accumulated matrix.Produces an unnormalized value-feature vector.
DenominatorThe same query reads the summed transformed keys, producing a scalar.Normalizes by total kernel weight; it must be positive for this expression to be defined.

Check: With one kernel feature, transformed query 2, keys [1, 3], and scalar values [4, 6], the numerator is 2×(1×4+3×6)=44 and denominator 2×(1+3)=8. Output is 5.5. The later code adds epsilon for numerical protection.

Define a matrix state S and a normalization state z:

$$ S = \sum_j \phi(k_j)v_j^\top, \qquad z = \sum_j \phi(k_j). $$
READ THE EQUATION

Give names to the two reusable sums: a key–value matrix and a key-normalization vector.

TermWhat it is and doesWhat it controls
\(S\)Accumulated matrix of shape dφ×dᵥ. Here S names a state, not sequence length.Content available to every query after accumulation.
\(z\)Accumulated vector of length dφ.The denominator’s reusable key statistics; this z is not a vocabulary-logit vector.
\(j,\sum_j\)Source index and accumulation over included sources.Which positions enter the state.
\(\phi(k_j)\), \(v_j^\top\)Mapped key column and value row. Their outer product has dφ×dᵥ entries.Associates every mapped-key feature with every value feature.

Check: For mapped scalar keys [1, 3] and values [4, 6], S=22 and z=4. Any transformed scalar query can reuse these two sums.

For fixed feature and value dimensions, accumulating those states scales linearly with sequence length. The cost still depends on the dimensions: building S requires work proportional to \(n d_\phi d_v\).

N × N ATTENTIONFIXED-SIZE STATEO(N²)O(N)
FIG. 004 — A kernel formulation lets us accumulate a fixed-size matrix state instead of materializing all token pairs. O(N) assumes fixed feature dimensions.

An implementation you can check

Here, \(\phi(x)=\operatorname{ELU}(x)+1\). The direct implementation builds every pairwise kernel score; the associative implementation never builds that matrix. They should agree up to floating-point error.

python
import numpy as np
from numpy.typing import NDArray


def phi(x: NDArray[np.float64]) -> NDArray[np.float64]:
    # exp(min(x, 0)) avoids overflowing the unused branch.
    return np.where(x >= 0, x + 1, np.exp(np.minimum(x, 0)))


def linear_attention(q: NDArray[np.float64], k: NDArray[np.float64], v: NDArray[np.float64]) -> NDArray[np.float64]:
    qf, kf = phi(q), phi(k)
    state = kf.T @ v               # (features, value_dim)
    normalizer = kf.sum(axis=0)    # (features,)
    denominator = qf @ normalizer
    return (qf @ state) / denominator[:, None].clip(1e-8)


rng = np.random.default_rng(7)
q, k = rng.normal(size=(2, 12, 8))
v = rng.normal(size=(12, 6))

pairwise = phi(q) @ phi(k).T
reference = (pairwise @ v) / pairwise.sum(-1, keepdims=True)
output = linear_attention(q, k, v)

np.testing.assert_allclose(output, reference, atol=1e-10)
print(output.shape)  # (12, 6)

This example is non-causal: every query can access all keys. It is a different attention rule from softmax attention, even though both return normalized weighted mixtures.

The causal recurrence

For autoregressive use, maintain prefix states. Add the current key/value pair before answering the current query:

$$ S_t = S_{t-1} + \phi(k_t)v_t^\top, \qquad z_t = z_{t-1} + \phi(k_t). $$
READ THE EQUATION

Update the recurrent states with only the new key and value, retaining the previous prefix’s sums.

TermWhat it is and doesWhat it controls
\(t,t-1\)Current and previous sequence positions.The boundary of the included prefix.
\(S_t,S_{t-1}\)Current and prior key–value accumulated matrices.The content memory after adding one source.
\(z_t,z_{t-1}\)Current and prior normalization vectors.The accumulated kernel weight information.
\(\phi(k_t)v_t^\top\)The new source’s outer-product contribution.Adds its contents to S without recomputing previous contributions.
\(\phi(k_t)\), \(+\)The new mapped key and elementwise additions.Adds the source to normalization; causal queries read only the state up to their position.

Check: Starting S=0 and z=0, a mapped key 1 with value 4 gives S=4,z=1. A later mapped key 3 with value 6 gives S=22,z=4. The earlier query must not read the later state.

Then evaluate the same normalized expression with \(S_t\) and \(z_t\). The state size does not grow with the number of tokens. This connection between linear attention and recurrent computation is developed in Transformers are RNNs .

The trade-off

The aggregate compresses previous keys and values into a fixed-size state. That changes what interactions the model can express. Lower asymptotic cost does not guarantee better speed at every sequence length, or the same model quality as softmax attention.

Further reading

See Transformers are RNNs: Fast Autoregressive Transformers with Linear Attention . Compare this recurrence with a conventional KV cache , which retains individual keys and values.

END OF NOTE
← Explore all notes