I strongly recommend reading the original materials if you are good at algorithms and math.
1. Linear Attention
We are all familiar with traditional Softmax Attention, often referred to as Full Attention. It applies Softmax normalization to the attention similarity matrix, giving
ot=j=1∑t∑l=1texp(qtTkl)exp(qtTkj)vj
Here, the q and k vectors are row vectors taken from the original Q and K matrices, while the vectors in the equations are written as column vectors. From a vector perspective, the meaning of Attention becomes very clear: the output of the t-th token is simply a weighted sum. Since qTk is a scalar, we can write
ot=j=1∑twjvj
In other words, Attention computes a weighted sum of the v vectors using a set of weights. Because of causal modeling, the output at position t can only aggregate the first t vectors. Therefore, if we temporarily ignore how wj is computed, Attention itself is linear. The real issue lies in the computation of the weights:
wj=∑l=1texp(qtTkl)exp(qtTkj)
This expression includes the Softmax function. Intuitively, we exponentiate the similarity between the query vector q and each key vector k, then divide by the sum of the exponentiated similarity scores over the first t tokens. This gives us the normalization. Notice that we are still summing over all preceding tokens.
Because of Softmax, we must first compute the query-key similarities, i.e. softmax(QKT), which produces a T×T matrix, where T is the sequence length. The idea behind Linear Attention is very simple: remove the Softmax first, giving
ot=j=1∑t(qtTkj)vjwj=qtTkj
There is now no exponential normalization, which means we can apply a few mathematical tricks:
ot=j=1∑t(qtTkj)vj=j=1∑tvj(kjTqt)=(j=1∑tvjkjT)qtqtTkj is a scalarAssociativity
Define St=∑j=1tvjkjT. Then
ot=Stqt∈Rd
and
S_t=S_{t-1}+v_tk_t^T\in \mathbb{R}^{d\times d}$$.
This immediately turns Attention into an RNN! The hidden state is $S_t$, which is updated by $v_tk_t^T$, while the output is obtained by mapping the query vector through the state. We now only need to store the state matrix $S$; we no longer need to keep every KV pair around in order to compute Attention. The space complexity drops from $O(Ld)$ to $O(d^2)$. In other words, the memory footprint no longer grows with sequence length. At the same time, the computational complexity changes from $O(L^2d)$ to $O(Ld^2)$.
Linear Attention looks great, but simply removing Softmax causes a major performance drop. Although the computation above is equivalent to an RNN with a fixed-size $d\times d$ state, mixing all KV vectors into a single matrix destroys its ability to precisely retrieve a particular historical KV pair. One of the biggest advantages of Softmax Attention is that the entire history of KV pairs is exposed directly to the model, allowing it to freely decide which historical information to use.
We can see this clearly by looking at the retrieval process. Suppose a query $q$ wants to retrieve the value associated with some key $k$. In other words, we want the output to be one exact historical value $v_j$:
$$o_t = v_j$$.
But our computation is
$$o_t=\sum_{j=1}^tv_j(k_j^Tq_t)
To retrieve vj as accurately as possible, the ideal solution would satisfy
{kiTqt=1i=jkiTqt=0i=j
The closest natural choice is qt=kj. Then, without loss of generality, assume all vectors are normalized:
To retrieve vj exactly, we would need kiTkj=0 for every i=j, meaning that all key vectors would have to be mutually orthogonal. But in a d-dimensional space, we can have at most d mutually orthogonal vectors. Once the sequence becomes longer than that, retrieval error becomes unavoidable.
You might ask: doesn’t Softmax Attention face the same problem? This is exactly where Softmax helps. When Softmax Attention wants to retrieve a particular value, it only needs to make qtTkj much larger than the other similarity scores. Softmax will naturally concentrate most of the probability mass on the j-th weight, making the distribution almost one-hot:
So yes, Softmax is actually very useful (confirmed). The idea behind DeltaNet is to address this problem by minimizing retrieval error.
2. The Delta Rule
The idea behind the Delta Rule is simple: it is just gradient descent applied to a linear predictor. Suppose we have a linear predictor
y^=i∑wixi
and use mean squared error as the loss function:
L=21(y−y^)2
Assuming y is the ground-truth target, the gradient with respect to the weights is
∂wi∂L=∂y^∂L∂wi∂y^=−(y−y^)xi
By gradient descent,
Δwi=−η∂wi∂L=η(y−y^)xi
which gives
w′=w−η(y^−y)xi(1)
From this, we can directly write down the core state-matrix update used by DeltaNet:
St=St−1−βt(St−1kt−vt)ktT(2)
Comparing this with Equation (1), the DeltaNet update rule is really performing online gradient descent. The input is kt, the prediction is St−1kt, the target is vt, and the learning rate is βt. In effect, DeltaNet trains its state matrix so that when the input is kt, the corresponding vt can be retrieved from the state matrix as accurately as possible.
There is another way to understand DeltaNet. Suppose we define St−1kt as the previously stored, or “old,” value vtold. Then
Looking at Equation (3), we can see that the new value is simply a mixture of the old value and the current value. The state-matrix update can therefore be interpreted as erasing the old value from the state matrix and then writing back a mixture of the old and current values. When βt=0, the old value is preserved. When βt=1, the old value is completely erased and replaced by the current value.
Finally, Linear Attention itself can also be viewed as online gradient descent. Starting from the Linear Attention state update,
If the vectors are normalized, this loss reaches its minimum value of −1 when the two vectors are maximally aligned. By contrast, the Delta Rule used in DeltaNet comes from an MSE loss:
L(S)=21∥Skt−vt∥2
Comparing these two loss functions, we can also say that one difference between DeltaNet and Linear Attention is the objective used for the online update: DeltaNet uses an MSE loss, while Linear Attention corresponds to a linear loss based on the dot product.
3. Chunkwise Parallelism
One reason Attention became so popular is that training can be highly parallelized: almost all of the computation can be expressed as matrix multiplication, which scales extremely well on GPUs. An RNN, on the other hand, is iterative and usually requires a for-loop, so it cannot be fully parallelized. However, once the recurrence contains no nonlinear operation, certain parallel algorithms become possible.
A classic example is the prefix-sum problem. Suppose we want the sum of the first t elements of a sequence:
St=i=1∑txt=St−1+xt
At first glance, this looks difficult to parallelize because the t-th prefix sum appears to require the (t−1)-th prefix sum first. But addition is associative. Suppose the sequence is [a,b,c,d]. What we want is the prefix sum at every position, together with the total sum. For example, the prefix before a is 0, the prefix before b is a, the prefix before c is a+b, and so on.
Computing the total sum is easy because of associativity:
a+b+c+d=(a+b)+(c+d)
The computation can therefore be arranged hierarchically.
We can compute a+b and c+d independently in parallel, then add the two results. This process is called the up-sweep. However, the up-sweep only gives us the total sum a+b+c+d. What we actually want is the prefix sum associated with every leaf at the bottom of the tree.
Now define the sum range of a node as
Sl:r=i=l∑r−1xi
and define the prefix sum of a node as
Pl=i=0∑l−1xi
which represents the sum of everything before the starting point of that node’s range. Then we can make two observations:
The prefix of a left child is always equal to the prefix of its parent. For example, the node representing a+b+c+d has prefix 0, and the node representing a+b also has prefix 0. The node representing c+d has prefix a+b, and its left child c also has prefix a+b. This is because a left child always starts at the same position as its parent.
The prefix of a right child is the parent’s prefix plus the sum range of the left child. For example, the node c+d has prefix 0+a+b. If the split point is m, the left child covers Sl:m and the right child covers Sm:r, so Pm=Pl+Sl:m.
Therefore, we can propagate the prefix information from the root down the tree. We only need to follow two rules:
The left child receives the parent’s prefix.
The right child receives the parent’s prefix plus the left child’s sum range.
Following these rules gives us the prefix sum at every bottom-level leaf. This process is called the down-sweep. Together, the up-sweep and down-sweep compute the prefix sums of the entire sequence. This algorithm is known as the Blelloch Scan.
Can we use a similar parallel scan to compute DeltaNet? Yes. DeltaNet’s recurrence differs slightly from a standard prefix sum. Starting from Equation (2), we can rearrange it as
We have now converted the recurrence into another prefix-sum problem. However, to apply a parallel scan, the operator must be associative. So we need to prove that the operator we just defined is associative.
Proof.
Rewrite Equation (4) in matrix-multiplication form:
By induction, matrix multiplication is equivalent to the custom operator above. Since matrix multiplication is associative, our custom operator is associative as well.
Q.E.D.
Once associativity has been established, we can use a Blelloch-Scan-like algorithm to accelerate DeltaNet.
However, DeltaNet uses another parallel-scan algorithm called the Brent-Kung Scan. The key difference is that Brent-Kung reuses partial sums that were already computed during the up-sweep.
Suppose we want to compute
x0+x1+x2+x3+x4+x5+x6+x7
First, compute the following pairs independently:
p1=x0+x1,p3=x2+x3,p5=x4+x5,p7=x6+x7
Then combine them further:
p3←p1+p3=S0:3
p7←p5+p7=S4:7
Finally,
p7←=p3+p7=S0:7
This completes the up-sweep. At this point, we already have several prefix sums:
P1=p1=S0:1,P3=p3=S0:3,P7=p7=S0:7
Next, compute the remaining prefix sums in the down-sweep:
P2=P1+x2=S0:2
P4=P3+x4=S0:4
P5=P3+p5=S0:5
P6=P5+x6=S0:6
Now we have all prefix sums. So the idea behind the Brent-Kung Scan is to use results we already computed to fill in the prefixes that were not explicitly produced by the up-sweep. The computation of DeltaNet follows the same idea: first compute [M0,X0]⊕[M1,X1] and [M2,X2]⊕[M3,X3], then combine those results, and finally reuse the intermediate results to recover the remaining prefix.
However, DeltaNet does not only involve matrix multiplication by M. Repeated multiplication of the M matrices introduces another problem. Consider multiplying two of them:
Let us compare the cost of two ways of performing this computation. The first is to treat each M as a dense matrix. Multiplying two d×d matrices costs O(d3). Alternatively, because each M is represented as a sum of rank-1 terms, we can exploit that structure and reduce an individual product to roughly O(d2) by separately computing the required outer products and inner products before summing them.
The problem is that as the recurrence depth increases, the number of expanded terms also grows. Equation (6) already shows how each multiplication produces more terms, and this expansion grows exponentially with depth. So exploiting the low-rank structure directly does not seem especially attractive; in practice, it may not be much better than simply treating the matrices as dense.
The second problem is space complexity. A parallel scan needs to store intermediate matrices. For a sequence of length L, this requires O(Ld2) memory.
Let us consider a different approach. The state computation of Linear Attention can be written as
St=i=1∑tvikiT
Because this is a sum of vector outer products, we do not need to store every intermediate state. But the computation is completely sequential. A compromise is to introduce intermediate checkpoints. Suppose we split a sequence of length L into chunks of size C, giving n=⌈L/C⌉ chunks. We treat each chunk boundary as a checkpoint, and compute the state matrix at each boundary using matrix multiplication.
Define
S[i]:=SiC∈Rd×d, the state matrix at the beginning of chunk i,
□[i]=□iC+1:(i+1)C∈RC×d for □∈{Q,K,V,O}, the matrix formed by the slice belonging to chunk i,
and □[i]r=□iC+r∈{q,k,v,o,S}, the r-th element, or the r-th state matrix, inside chunk i.
Then the Linear Attention computation can be written as
S[i]r=S[i]+i=1∑rv[i]tk[i]tTstarting from the chunk boundary, accumulate the keys and values up to position r
o[i]r=S[i]q[i]r+t=1∑rv[i]t(kitTq[i]r)the output is obtained from the state matrix and the query q
This allows us to write the computation in matrix form:
S[t+1]=S[t]+V[t]TK[t]the state at the start of the next chunk is the current chunk’s starting state plus the KV contribution of this chunk
O[t]=Q[t]S[t]T+(Q[t]K[t]T⊙M)V[t]all outputs in the chunk are computed from the chunk’s queries, state, and KV pairs
Here, M is the causal mask. With this formulation, we do not need to store every intermediate state, nor do we need to execute the entire computation sequentially. At the same time, the heavy computation is expressed as matrix multiplication, allowing us to take advantage of Tensor Cores.
Chunkwise parallelism for DeltaNet is slightly more involved. In the previous analysis, every multiplication of the M matrices seemed to increase the number of terms exponentially. However, there is a much more compact representation of these products.
We can now derive the chunkwise-parallel form of DeltaNet. Suppose we again split the sequence into chunks of size C. Expanding the DeltaNet state recurrence within a chunk gives
S[i]r=S[i]r−1M[i]r+X[i]r=(S[i]r−2M[i]r−1+X[i]r−1)M[i]r+X[i]r=S[i]r−2M[i]r−1M[i]r+X[i]r−1M[i]r+X[i]r=⋯=S[i]t=1∏rM[i]t+t=1∑rX[i]ts=t+1∏rM[i]s=S[i]Product of Mt=1∏r(I−β[i]tk[i]tk[i]tT)+Expansion of St=1∑r(β[i]tv[i]tk[i]tTs=t+1∏r(I−β[i]sk[i]sk[i]sT))
Notice that the second term is exactly the form obtained by expanding the state matrix for r steps: it is a sum of X terms multiplied by subsequent M matrices. Using the two compact expressions derived above, we get
So DeltaNet can also be accelerated using a chunkwise formulation. Chunkwise parallelism not only lets us exploit fast matrix multiplication, but also avoids storing every intermediate state matrix. It is essentially a trade-off between parallelism and space complexity.
There is still one remaining problem: computing w[t]r and u[t]r appears to be sequential. Fortunately, both variables can be solved for directly.
Starting from
wr=βrkr−βri<r∑wi(kiTkr)
define
A_{ri}=-\beta_r k_i^Tk_r$$,
where $A$ is a strictly lower-triangular matrix \((i<r)\). Then
$$w_r=\beta_r k_r + \sum_{i<r} A_{ri}w_i
Now write everything in matrix form:
K=k1T⋮kCT
W=w1T⋮wCT
B=diag(β1,…,βC)
Then
W=BK+AW⇒W=(I−A)−1BK
Similarly,
U=(I−A)−1BV
So once again, the computation can be accelerated with matrix multiplication.