Chunkwise-Parallel Execution of KronLSTM
Token-by-token KronLSTM updates serialize memory access; chunkwise execution turns the within-chunk dependencies into a Gram-based triangular solve and propagates memory only between chunks.
What it is
- Chunkwise solve Group a chunk's causally linked write strengths into a triangular system, where each position depends only on earlier positions, instead of running every memory update in a token loop.
- Factored similarities Compute pairwise key similarities and value similarities separately, then multiply matching entries. This avoids constructing large combined key-value vectors.
- Boundary memory Each chunk uses its incoming memory to determine write strengths and produce the next state. Chunk-local preparation can happen together, but the state handoff remains sequential.
Why it matters
This exposes parallel work inside a recurrent sequence without changing its update rule. Token interactions become matrix operations and a structured solve, while memory still carries information from one chunk to the next.
The short version is that KronLSTM can reorganize a chunk's recurrent updates into matrix operations and a triangular solve. It avoids building large combined key-value vectors, but it does not make chunks independent: each chunk still needs the memory left by the previous one.
- Serial dependence: Imagine two consecutive tokens. The first writes to memory, changing the score used to decide the second token's write. Batching them must preserve that interaction, not pretend it disappears.
- Feature size: A combined key-value feature contains every key-coordinate/value-coordinate pairing. For the same two tokens, constructing both combined features just to compare them is unnecessary: their interaction factors into separate key and value comparisons.
- State continuity: The next chunk must inherit the current chunk's memory. Like processing a batch of transactions against an opening balance, local calculations can be prepared together, but the next batch still needs the closing balance. Unlike a bank balance, this state is a matrix.
So what replaces the serial token walk?
Each token's write has a scalar strength. That strength depends on how well its key-value pair matches memory. In our two-token example, the first write changes the second token's match score; it cannot change an earlier score. Collect these one-way dependencies and you get a triangular system: each position depends only on preceding positions. Solving it preserves the causal interactions rather than discarding them.
But what determines the interaction between those two writes?
Compare their keys, compare their values, and multiply the two similarities. That gives the combined-feature interaction without constructing the combined features. A Gram matrix is simply a table of pairwise dot products: here we combine a key-interaction table with a value-interaction table, entry by entry.
Forgetting complicates the key side. A write from the first token is faded before the second token scores it. The formulation handles this by absorbing cumulative decay into differently scaled scoring and writing keys. Think of keeping accounts in adjusted units; the limit of that analogy is that each key coordinate has its own adjustment. How does the opening memory enter this accounting?
For each token, the incoming memory contributes a scalar pair-match score. Those scores feed the solve. The write gate supplies the candidate write strength, while the erase gate controls the response to both incoming memory and earlier writes. The resulting system accounts for all three contributions together. Once the strengths are known, what remains to compute?
Scale each value by its solved strength, assemble the writes carried through the chunk's remaining forgetting, and add them to the decayed incoming memory. Readouts can likewise combine the incoming-memory contribution with the relevant writes, including the current token's own write.
I like the precision of this boundary: chunk-local interaction tables and state-independent solve terms can be prepared across chunks, but incoming-memory scores, actual write strengths, and the outgoing state remain linked. This is not “the same loop, magically parallel”; it is a different organization of its dependencies. How much work should a particular implementation group into each chunk?
Read the deep dive
Why People Wanted It
A recurrent memory update is naturally sequential: each token changes the memory used by the next token. The problem is the price of that dependency when training on long sequences. So the real question was never just how to batch tokens; it was whether their causal interactions could be reorganized without explicitly constructing the large combined key-value features.
KronLSTM has a useful property: the coefficient of each rank-one write depends on memory through a scalar score. Solve for those coefficients within a chunk, and you can assemble its writes and readouts using matrix operations. The memory still passes from one chunk to the next.
“All token interactions inside a chunk are expressed as dense matrix products and one small triangular solve, and the memory is propagated only between chunks.” — A8, p. 49
The Core Move
Replace the within-chunk recurrence with a unit lower-triangular system whose interactions factor into key similarities and value similarities.
For a chunk of tokens, the write coefficients satisfy
Here contains the scores against the incoming memory, contains the write gates, and contains the erase gates. The strictly lower-triangular matrix accounts for how earlier writes change later scores. The diagonal of is all ones: this is a triangular solve, not an assumption that the tokens are independent.
“Hence , which is row of .” — Proposition A5 proof, p. 50
Why the Gram Product Replaces Kronecker Features
Here is the part that gets technical: the combined-feature interaction factors into a key inner product times a value inner product.
Forgetting is absorbed into asymmetric keys: is the decay-scaled scoring key, while is the writing key in the decay-normalized frame. Their corresponding combined features are
The mixed-product identity gives
So the interaction can be computed without forming either combined feature. Let be the strictly lower-triangular decay-weighted key Gram matrix and the value Gram matrix. The system matrix uses
The elementwise product combines the two similarities; multiplication by weights each row by that token's erase gate. Strict lower-triangular masking preserves causality: an earlier write can change a later write coefficient, but not the reverse.
The asymmetric keys matter. With channel-wise forgetting, this is not simply the ordinary symmetric key Gram matrix. The scoring and writing sides carry different decay scalings.
“The -dimensional features are never formed: two Gram matrices of - and -dimensional vectors and one Hadamard product suffice.” — A8.3, p. 50
This removes the large feature construction. But how does the incoming memory enter the solve?
Why the Incoming Memory Enters as Scalar Scores
Now the version for readers who want more of the machinery: unrolling the decay-normalized recurrence separates the incoming-memory score from the scores contributed by earlier writes.
The token-level recurrence is
where is the diagonal key-side forget gate. The readout uses the memory after the current write:
Because the forget matrices are diagonal and commute, cumulative decay can be absorbed into the asymmetric keys. In that frame, the incoming state contributes
Substituting the unrolled memory into each score produces the coefficient equation from the core move. Its terms have distinct jobs: sets the candidate write; corrects for the incoming memory; and corrects for earlier writes within the chunk.
The write gate therefore enters only the right-hand side. The erase gate enters both the system matrix and the incoming-memory term. Since is strictly lower triangular, is invertible for every erase-gate value and every input. This is an algebraic reformulation of the recurrence, not an approximation to it.
“The write gate enters only the right-hand side of the solve, the erase gate enters the system matrix and the coupling to .” — A8.3, p. 50
“ is strictly lower triangular, so is unit lower triangular and invertible for every and every input.” — Proposition A5, p. 50
Once those coefficients are known, do we still need every intermediate memory matrix?
Why Memory Propagates Only at Chunk Boundaries
Here is the deeper chunk-level consequence: solved write coefficients let you assemble the outgoing memory without materializing every intermediate revision.
Each token's pseudo-value is its original value scaled by . Using for cumulative diagonal decay through the chunk, the end state is
The first term carries the incoming memory through the chunk's forgetting. Each term in the sum carries a solved write through the decay remaining after its position. This is the end-state expression used in the proof of Theorem A11.
Readouts follow the same additive representation:
Here is the query scaled by cumulative decay. Stacking the readouts turns the sum into multiplication by the causal readout Gram matrix. Its diagonal is included because each query sees its own token's write.
The chunk-local Gram matrices can be prepared across chunks. With , the state-independent terms and can also be prepared in parallel. This inverse notation describes the algebra; the computation is organized around a triangular solve.
The remaining dependency is incoming memory, then scores , then coefficients , then outgoing memory. The next chunk must receive that outgoing state before its state-dependent part can be evaluated.
“Everything in (A152)–(A159) except , and [the pseudo-value matrix] is local to a chunk and is computed for all chunks at once.” — A8.4, p. 51
“The dependence is the only sequential part.” — A8.4, p. 51
How much work should you group into a chunk when this state handoff remains?
Minimal Causal Code
This plain PyTorch loop implements the recurrence in A149. It is a reference for the semantics, not a fast chunkwise implementation: the triangular solve replaces the loop's within-chunk coefficient dependencies.
import torch
def kronlstm_chunk_reference(S, q, k, v, beta, c, forget):
# S: [dv, dk]; q, k: [C, dk]; v: [C, dv]
# beta, c: [C]; forget: [C, dk], with entries in (0, 1)
reads = []
for r in range(k.shape[0]):
# Apply key-side forgetting before scoring the current pair.
decayed_S = S * forget[r].unsqueeze(0)
score = v[r] @ (decayed_S @ k[r])
u = c[r] - beta[r] * score
# Visible state transition: decayed memory plus rank-one write.
S = decayed_S + u * torch.outer(v[r], k[r])
# The query sees the current token's write.
reads.append(S @ q[r])
return S, torch.stack(reads)
What You Gain, and What You Lose
You gain dense chunk-local computation without constructing combined features of dimension . The write coefficients come from a structured triangular system, and readouts can be assembled without explicitly stepping through every intermediate memory.
You do not gain independent chunks. The incoming state still determines the scalar scores and therefore the outgoing state. You also introduce chunk-local Gram matrices and a triangular solve rather than simply making the recurrent loop disappear. Chunk length controls how much work is grouped into that machinery; this formulation alone does not specify an optimal choice.
Finally, the rewrite depends on the update structure: diagonal key-side decay and a rank-one write whose coefficient is affine in a scalar score. It is not a drop-in transformation for arbitrary recurrent networks.
“The derivation uses only the structure ‘diagonal decay on the key side, rank-one write along with a coefficient affine in the scalar score’.” — A8.6, p. 51
Inside a chunk, KronLSTM trades serial token updates for a triangular solve over factored Gram interactions; the state-dependent memory handoff between chunks remains sequential.