Card: standardized form with hero
Browse files
CARD.md
CHANGED
|
@@ -5,95 +5,27 @@ license: apache-2.0
|
|
| 5 |
|
| 6 |
# gated-deltanet
|
| 7 |
|
| 8 |
-
The gated delta rule in recurrent form, loadable through `kernels`.
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
```
|
| 30 |
-
|
| 31 |
-
The delta rule is what separates this from plain linear attention. The state is
|
| 32 |
-
corrected by the difference between the value and what the state already holds
|
| 33 |
-
for that key, rather than having the value added blindly, so writing the same
|
| 34 |
-
key twice does not double its contribution. Two gates control it: `exp(g)`
|
| 35 |
-
decides how much of the past survives, `beta` how strongly the correction lands.
|
| 36 |
-
|
| 37 |
-
The state is the whole cost, 128 x 128 floats per head, 64 KiB, and a
|
| 38 |
-
straightforward implementation reads and writes it several times per token. Here
|
| 39 |
-
one block owns one (batch, head) pair and holds the entire state in its threads'
|
| 40 |
-
registers for the whole sequence: a thread owns one value column and a slice of
|
| 41 |
-
the key rows. The state is read from memory once at the start and written once
|
| 42 |
-
at the end, whatever the length, and every intermediate token touches registers
|
| 43 |
-
only. Prefill and decode are therefore the same kernel, differing only in how
|
| 44 |
-
many tokens the loop runs.
|
| 45 |
-
|
| 46 |
-
## Measured
|
| 47 |
-
|
| 48 |
-
RTX 6000 Ada (48 GB), torch 2.10 + CUDA 12.6, 48 heads, 128 x 128 state, against
|
| 49 |
-
the eager reference on the same inputs.
|
| 50 |
-
|
| 51 |
-
| batch | tokens | eager | this | speedup |
|
| 52 |
-
|---|---|---|---|---|
|
| 53 |
-
| 1 | 1 | 0.435 ms | 0.028 ms | **15.3x** |
|
| 54 |
-
| 1 | 64 | 7.451 ms | 0.347 ms | **21.4x** |
|
| 55 |
-
| 1 | 512 | 61.114 ms | 2.787 ms | **21.9x** |
|
| 56 |
-
| 4 | 256 | 40.268 ms | 2.468 ms | 16.3x |
|
| 57 |
-
|
| 58 |
-
The eager path is a Python loop over timesteps, each step launching several
|
| 59 |
-
tensor operations over the full state; this kernel runs the loop on the device
|
| 60 |
-
with the state resident in registers.
|
| 61 |
-
|
| 62 |
-
State footprint, Bonsai 27B geometry:
|
| 63 |
-
|
| 64 |
-
| | |
|
| 65 |
-
|---|---|
|
| 66 |
-
| per layer, per sequence | 3.0 MB |
|
| 67 |
-
| all 48 linear layers | **144 MB, constant in context length** |
|
| 68 |
-
|
| 69 |
-
## Correctness
|
| 70 |
-
|
| 71 |
-
Verified on RTX 6000 Ada against transformers 5.13.
|
| 72 |
-
|
| 73 |
-
- **Output and final state** agree with the reference to 5.5e-7 relative across
|
| 74 |
-
batch 1 to 3, 8 to 256 tokens, 2 to 8 heads, both 64 and 128 dimensions, with
|
| 75 |
-
and without the in-kernel L2 normalization of queries and keys.
|
| 76 |
-
- **Chunked equals whole.** Running a 96-token sequence in six 16-token calls,
|
| 77 |
-
carrying the state, is `torch.equal` to one call. Prefill and decode are the
|
| 78 |
-
same operation.
|
| 79 |
-
- **Token by token equals whole.** Decoding 48 tokens one at a time is
|
| 80 |
-
`torch.equal` to the batched pass, state included.
|
| 81 |
-
- **An initial state is respected**, matching the reference given the same
|
| 82 |
-
start.
|
| 83 |
-
- **Gate semantics.** `beta = 0` leaves the state exactly untouched; a large
|
| 84 |
-
negative `g` shrinks it by nine orders of magnitude; `g = 0` with `beta = 0`
|
| 85 |
-
is the exact identity.
|
| 86 |
-
- **Deterministic.** Repeated runs are bitwise identical.
|
| 87 |
-
|
| 88 |
-
### A stability note, not a kernel limit
|
| 89 |
-
|
| 90 |
-
The delta rule is stable only while `beta * |k|^2` stays near or below 2. Raw
|
| 91 |
-
N(0,1) keys at dimension 128 give roughly 65, and the recurrence genuinely
|
| 92 |
-
diverges: the reference reaches 1.3e26 on such input and this kernel reproduces
|
| 93 |
-
that to five significant figures. Real models avoid it by L2 normalizing the
|
| 94 |
-
keys, which is what `use_qk_l2norm` does. If you see the state explode, the
|
| 95 |
-
input is outside the rule's stable region and both implementations will agree
|
| 96 |
-
that it is.
|
| 97 |
|
| 98 |
## Usage
|
| 99 |
|
|
@@ -111,8 +43,9 @@ out = gdn.gated_delta_rule(q, k, v, g, beta, state, use_qk_l2norm=True)
|
|
| 111 |
|
| 112 |
`version` selects the release branch; `trust_remote_code` is required by
|
| 113 |
`kernels` for publishers without the trusted-publisher mark. `g` is the log
|
| 114 |
-
decay: the kernel applies `exp(g)`, matching the reference,
|
| 115 |
-
|
|
|
|
| 116 |
|
| 117 |
## API
|
| 118 |
|
|
@@ -122,36 +55,79 @@ pre-exponential gate.
|
|
| 122 |
| `new_state(batch, heads, key_dim, value_dim)` | a zeroed `[B, H, Dk, Dv]` fp32 state |
|
| 123 |
| `GatedDeltaNet(batch, heads, key_dim, value_dim, use_qk_l2norm)` | module holding the state across steps, one per layer |
|
| 124 |
|
| 125 |
-
|
| 126 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
|
| 128 |
## Requirements and limits
|
| 129 |
|
| 130 |
-
- NVIDIA GPU with compute capability 8.0+
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
this
|
| 137 |
-
|
| 138 |
-
-
|
| 139 |
-
|
| 140 |
-
of a more complex derivation. This kernel keeps the exact recurrence, which is
|
| 141 |
-
what makes chunked and token-by-token bitwise identical, and it is already
|
| 142 |
-
20x the eager path.
|
| 143 |
-
- Grouped heads are the caller's business: a model with more value heads than
|
| 144 |
-
key heads repeats the key and query heads before calling, as the reference
|
| 145 |
-
layer does.
|
| 146 |
-
- Forward only.
|
| 147 |
|
| 148 |
## References
|
| 149 |
|
| 150 |
-
Yang et al., "Gated Delta Networks: Improving Mamba2 with Delta Rule"
|
| 151 |
-
Yang et al., "Parallelizing Linear Transformers with the Delta Rule
|
| 152 |
-
Sequence Length" (2024); Schlag et al., "Linear Transformers Are
|
| 153 |
-
Weight Programmers" (2021); the reference implementation in
|
| 154 |
-
`Qwen3_5GatedDeltaNet`.
|
| 155 |
|
| 156 |
## License
|
| 157 |
|
|
|
|
| 5 |
|
| 6 |
# gated-deltanet
|
| 7 |
|
| 8 |
+
The gated delta rule in recurrent form, loadable through `kernels`. The
|
| 9 |
+
reference baseline is transformers' `torch_recurrent_gated_delta_rule`, which
|
| 10 |
+
this kernel matches to 5.5e-7 relative and replaces via
|
| 11 |
+
`@use_kernel_forward_from_hub("Qwen3_5GatedDeltaNet")`.
|
| 12 |
+
|
| 13 |
+
Three of every four layers in a hybrid-attention model are not attention:
|
| 14 |
+
they carry a fixed-size state per head and update it once per token, so
|
| 15 |
+
memory does not grow with context. The catch is speed: written in framework
|
| 16 |
+
ops the recurrence is a Python loop that reads and writes the whole state
|
| 17 |
+
several times per token. This kernel holds the entire state in registers for
|
| 18 |
+
the whole sequence, one block per (batch, head) pair, reading it from memory
|
| 19 |
+
once and writing it once whatever the length, which makes prefill and decode
|
| 20 |
+
the same kernel and the eager loop about twenty times slower.
|
| 21 |
+
|
| 22 |
+

|
| 23 |
+
|
| 24 |
+
*One head's 128 x 128 state filmed live across 2,048 tokens of updates,
|
| 25 |
+
including periodic retention-gate wipes (`g` large and negative erases the
|
| 26 |
+
past, then the state re-blooms). At 48 layers the recurrent memory is 144 MB
|
| 27 |
+
at any context; attention's KV cache at the same geometry passes 155 GB by
|
| 28 |
+
131,072 tokens. Output matches the transformers reference to 1e-6.*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
## Usage
|
| 31 |
|
|
|
|
| 43 |
|
| 44 |
`version` selects the release branch; `trust_remote_code` is required by
|
| 45 |
`kernels` for publishers without the trusted-publisher mark. `g` is the log
|
| 46 |
+
decay: the kernel applies `exp(g)`, matching the reference. `q`, `k` are
|
| 47 |
+
`[B, T, H, Dk]`; `v` is `[B, T, H, Dv]`; `g`, `beta` are `[B, T, H]`;
|
| 48 |
+
returns `[B, T, H, Dv]`.
|
| 49 |
|
| 50 |
## API
|
| 51 |
|
|
|
|
| 55 |
| `new_state(batch, heads, key_dim, value_dim)` | a zeroed `[B, H, Dk, Dv]` fp32 state |
|
| 56 |
| `GatedDeltaNet(batch, heads, key_dim, value_dim, use_qk_l2norm)` | module holding the state across steps, one per layer |
|
| 57 |
|
| 58 |
+
## Method
|
| 59 |
+
|
| 60 |
+
Per token the update is a decay, a read, a rank-one correction and a read:
|
| 61 |
+
|
| 62 |
+
```
|
| 63 |
+
S <- S * exp(g) gated decay, one scalar per head
|
| 64 |
+
m <- k^T S what the state already predicts for this key
|
| 65 |
+
d <- (v - m) * beta the delta, scaled by the write gate
|
| 66 |
+
S <- S + k d^T rank-one write
|
| 67 |
+
out <- q^T S read with the query
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
The delta rule corrects the state by the difference between the value and
|
| 71 |
+
what the state already holds for that key, so writing the same key twice does
|
| 72 |
+
not double its contribution. The state is the whole cost, 64 KiB per head,
|
| 73 |
+
and here one block owns one (batch, head) pair with the state in its threads'
|
| 74 |
+
registers for the whole sequence: a thread owns one value column and a slice
|
| 75 |
+
of the key rows. Every intermediate token touches registers only.
|
| 76 |
+
|
| 77 |
+
## Measured
|
| 78 |
+
|
| 79 |
+
RTX 6000 Ada, 48 heads, 128 x 128 state, against the eager reference on the
|
| 80 |
+
same inputs:
|
| 81 |
+
|
| 82 |
+
| batch | tokens | eager | this | speedup |
|
| 83 |
+
|---|---|---|---|---|
|
| 84 |
+
| 1 | 1 | 0.435 ms | 0.028 ms | 15.3x |
|
| 85 |
+
| 1 | 64 | 7.451 ms | 0.347 ms | 21.4x |
|
| 86 |
+
| 1 | 512 | 61.114 ms | 2.787 ms | 21.9x |
|
| 87 |
+
| 4 | 256 | 40.268 ms | 2.468 ms | 16.3x |
|
| 88 |
+
|
| 89 |
+
State footprint, Bonsai 27B geometry: 3.0 MB per layer per sequence, 144 MB
|
| 90 |
+
across all 48 linear layers, constant in context length.
|
| 91 |
+
|
| 92 |
+
## Correctness
|
| 93 |
+
|
| 94 |
+
Verified against transformers 5.13:
|
| 95 |
+
|
| 96 |
+
- Output and final state agree with the reference to 5.5e-7 relative across
|
| 97 |
+
batch 1 to 3, 8 to 256 tokens, 2 to 8 heads, 64 and 128 dimensions, with
|
| 98 |
+
and without the in-kernel L2 normalization.
|
| 99 |
+
- Chunked equals whole: a 96-token sequence in six 16-token calls, carrying
|
| 100 |
+
the state, is `torch.equal` to one call; decoding token by token equals
|
| 101 |
+
the batched pass, state included.
|
| 102 |
+
- Gate semantics: `beta = 0` leaves the state exactly untouched; a large
|
| 103 |
+
negative `g` shrinks it by nine orders of magnitude; `g = 0` with
|
| 104 |
+
`beta = 0` is the exact identity.
|
| 105 |
+
- Deterministic: repeated runs are bitwise identical.
|
| 106 |
+
- The delta rule is stable only while `beta * |k|^2` stays near or below 2;
|
| 107 |
+
real models L2-normalize keys (`use_qk_l2norm`), and on out-of-region
|
| 108 |
+
input this kernel reproduces the reference's divergence to five
|
| 109 |
+
significant figures.
|
| 110 |
|
| 111 |
## Requirements and limits
|
| 112 |
|
| 113 |
+
- NVIDIA GPU with compute capability 8.0+; fp32 arithmetic (the state is a
|
| 114 |
+
long product chain).
|
| 115 |
+
- `Dv` must divide the 256-thread block, `Dk` divisible by `256 / Dv`,
|
| 116 |
+
`Dk / (256 / Dv) <= 64`; `Dk <= 256`. The 128 x 128 and 64 x 64
|
| 117 |
+
geometries satisfy all constraints.
|
| 118 |
+
- Recurrent form only: long prefills would run faster in the chunked
|
| 119 |
+
formulation; this kernel keeps the exact recurrence, which is what makes
|
| 120 |
+
chunked and token-by-token bitwise identical.
|
| 121 |
+
- Grouped heads are the caller's: repeat key and query heads before calling,
|
| 122 |
+
as the reference layer does. Forward only.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
|
| 124 |
## References
|
| 125 |
|
| 126 |
+
Yang et al., "Gated Delta Networks: Improving Mamba2 with Delta Rule"
|
| 127 |
+
(2024); Yang et al., "Parallelizing Linear Transformers with the Delta Rule
|
| 128 |
+
over Sequence Length" (2024); Schlag et al., "Linear Transformers Are
|
| 129 |
+
Secretly Fast Weight Programmers" (2021); the reference implementation in
|
| 130 |
+
transformers' `Qwen3_5GatedDeltaNet`.
|
| 131 |
|
| 132 |
## License
|
| 133 |
|
README.md
CHANGED
|
@@ -5,95 +5,27 @@ license: apache-2.0
|
|
| 5 |
|
| 6 |
# gated-deltanet
|
| 7 |
|
| 8 |
-
The gated delta rule in recurrent form, loadable through `kernels`.
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
```
|
| 30 |
-
|
| 31 |
-
The delta rule is what separates this from plain linear attention. The state is
|
| 32 |
-
corrected by the difference between the value and what the state already holds
|
| 33 |
-
for that key, rather than having the value added blindly, so writing the same
|
| 34 |
-
key twice does not double its contribution. Two gates control it: `exp(g)`
|
| 35 |
-
decides how much of the past survives, `beta` how strongly the correction lands.
|
| 36 |
-
|
| 37 |
-
The state is the whole cost, 128 x 128 floats per head, 64 KiB, and a
|
| 38 |
-
straightforward implementation reads and writes it several times per token. Here
|
| 39 |
-
one block owns one (batch, head) pair and holds the entire state in its threads'
|
| 40 |
-
registers for the whole sequence: a thread owns one value column and a slice of
|
| 41 |
-
the key rows. The state is read from memory once at the start and written once
|
| 42 |
-
at the end, whatever the length, and every intermediate token touches registers
|
| 43 |
-
only. Prefill and decode are therefore the same kernel, differing only in how
|
| 44 |
-
many tokens the loop runs.
|
| 45 |
-
|
| 46 |
-
## Measured
|
| 47 |
-
|
| 48 |
-
RTX 6000 Ada (48 GB), torch 2.10 + CUDA 12.6, 48 heads, 128 x 128 state, against
|
| 49 |
-
the eager reference on the same inputs.
|
| 50 |
-
|
| 51 |
-
| batch | tokens | eager | this | speedup |
|
| 52 |
-
|---|---|---|---|---|
|
| 53 |
-
| 1 | 1 | 0.435 ms | 0.028 ms | **15.3x** |
|
| 54 |
-
| 1 | 64 | 7.451 ms | 0.347 ms | **21.4x** |
|
| 55 |
-
| 1 | 512 | 61.114 ms | 2.787 ms | **21.9x** |
|
| 56 |
-
| 4 | 256 | 40.268 ms | 2.468 ms | 16.3x |
|
| 57 |
-
|
| 58 |
-
The eager path is a Python loop over timesteps, each step launching several
|
| 59 |
-
tensor operations over the full state; this kernel runs the loop on the device
|
| 60 |
-
with the state resident in registers.
|
| 61 |
-
|
| 62 |
-
State footprint, Bonsai 27B geometry:
|
| 63 |
-
|
| 64 |
-
| | |
|
| 65 |
-
|---|---|
|
| 66 |
-
| per layer, per sequence | 3.0 MB |
|
| 67 |
-
| all 48 linear layers | **144 MB, constant in context length** |
|
| 68 |
-
|
| 69 |
-
## Correctness
|
| 70 |
-
|
| 71 |
-
Verified on RTX 6000 Ada against transformers 5.13.
|
| 72 |
-
|
| 73 |
-
- **Output and final state** agree with the reference to 5.5e-7 relative across
|
| 74 |
-
batch 1 to 3, 8 to 256 tokens, 2 to 8 heads, both 64 and 128 dimensions, with
|
| 75 |
-
and without the in-kernel L2 normalization of queries and keys.
|
| 76 |
-
- **Chunked equals whole.** Running a 96-token sequence in six 16-token calls,
|
| 77 |
-
carrying the state, is `torch.equal` to one call. Prefill and decode are the
|
| 78 |
-
same operation.
|
| 79 |
-
- **Token by token equals whole.** Decoding 48 tokens one at a time is
|
| 80 |
-
`torch.equal` to the batched pass, state included.
|
| 81 |
-
- **An initial state is respected**, matching the reference given the same
|
| 82 |
-
start.
|
| 83 |
-
- **Gate semantics.** `beta = 0` leaves the state exactly untouched; a large
|
| 84 |
-
negative `g` shrinks it by nine orders of magnitude; `g = 0` with `beta = 0`
|
| 85 |
-
is the exact identity.
|
| 86 |
-
- **Deterministic.** Repeated runs are bitwise identical.
|
| 87 |
-
|
| 88 |
-
### A stability note, not a kernel limit
|
| 89 |
-
|
| 90 |
-
The delta rule is stable only while `beta * |k|^2` stays near or below 2. Raw
|
| 91 |
-
N(0,1) keys at dimension 128 give roughly 65, and the recurrence genuinely
|
| 92 |
-
diverges: the reference reaches 1.3e26 on such input and this kernel reproduces
|
| 93 |
-
that to five significant figures. Real models avoid it by L2 normalizing the
|
| 94 |
-
keys, which is what `use_qk_l2norm` does. If you see the state explode, the
|
| 95 |
-
input is outside the rule's stable region and both implementations will agree
|
| 96 |
-
that it is.
|
| 97 |
|
| 98 |
## Usage
|
| 99 |
|
|
@@ -111,8 +43,9 @@ out = gdn.gated_delta_rule(q, k, v, g, beta, state, use_qk_l2norm=True)
|
|
| 111 |
|
| 112 |
`version` selects the release branch; `trust_remote_code` is required by
|
| 113 |
`kernels` for publishers without the trusted-publisher mark. `g` is the log
|
| 114 |
-
decay: the kernel applies `exp(g)`, matching the reference,
|
| 115 |
-
|
|
|
|
| 116 |
|
| 117 |
## API
|
| 118 |
|
|
@@ -122,36 +55,79 @@ pre-exponential gate.
|
|
| 122 |
| `new_state(batch, heads, key_dim, value_dim)` | a zeroed `[B, H, Dk, Dv]` fp32 state |
|
| 123 |
| `GatedDeltaNet(batch, heads, key_dim, value_dim, use_qk_l2norm)` | module holding the state across steps, one per layer |
|
| 124 |
|
| 125 |
-
|
| 126 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
|
| 128 |
## Requirements and limits
|
| 129 |
|
| 130 |
-
- NVIDIA GPU with compute capability 8.0+
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
this
|
| 137 |
-
|
| 138 |
-
-
|
| 139 |
-
|
| 140 |
-
of a more complex derivation. This kernel keeps the exact recurrence, which is
|
| 141 |
-
what makes chunked and token-by-token bitwise identical, and it is already
|
| 142 |
-
20x the eager path.
|
| 143 |
-
- Grouped heads are the caller's business: a model with more value heads than
|
| 144 |
-
key heads repeats the key and query heads before calling, as the reference
|
| 145 |
-
layer does.
|
| 146 |
-
- Forward only.
|
| 147 |
|
| 148 |
## References
|
| 149 |
|
| 150 |
-
Yang et al., "Gated Delta Networks: Improving Mamba2 with Delta Rule"
|
| 151 |
-
Yang et al., "Parallelizing Linear Transformers with the Delta Rule
|
| 152 |
-
Sequence Length" (2024); Schlag et al., "Linear Transformers Are
|
| 153 |
-
Weight Programmers" (2021); the reference implementation in
|
| 154 |
-
`Qwen3_5GatedDeltaNet`.
|
| 155 |
|
| 156 |
## License
|
| 157 |
|
|
|
|
| 5 |
|
| 6 |
# gated-deltanet
|
| 7 |
|
| 8 |
+
The gated delta rule in recurrent form, loadable through `kernels`. The
|
| 9 |
+
reference baseline is transformers' `torch_recurrent_gated_delta_rule`, which
|
| 10 |
+
this kernel matches to 5.5e-7 relative and replaces via
|
| 11 |
+
`@use_kernel_forward_from_hub("Qwen3_5GatedDeltaNet")`.
|
| 12 |
+
|
| 13 |
+
Three of every four layers in a hybrid-attention model are not attention:
|
| 14 |
+
they carry a fixed-size state per head and update it once per token, so
|
| 15 |
+
memory does not grow with context. The catch is speed: written in framework
|
| 16 |
+
ops the recurrence is a Python loop that reads and writes the whole state
|
| 17 |
+
several times per token. This kernel holds the entire state in registers for
|
| 18 |
+
the whole sequence, one block per (batch, head) pair, reading it from memory
|
| 19 |
+
once and writing it once whatever the length, which makes prefill and decode
|
| 20 |
+
the same kernel and the eager loop about twenty times slower.
|
| 21 |
+
|
| 22 |
+

|
| 23 |
+
|
| 24 |
+
*One head's 128 x 128 state filmed live across 2,048 tokens of updates,
|
| 25 |
+
including periodic retention-gate wipes (`g` large and negative erases the
|
| 26 |
+
past, then the state re-blooms). At 48 layers the recurrent memory is 144 MB
|
| 27 |
+
at any context; attention's KV cache at the same geometry passes 155 GB by
|
| 28 |
+
131,072 tokens. Output matches the transformers reference to 1e-6.*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
## Usage
|
| 31 |
|
|
|
|
| 43 |
|
| 44 |
`version` selects the release branch; `trust_remote_code` is required by
|
| 45 |
`kernels` for publishers without the trusted-publisher mark. `g` is the log
|
| 46 |
+
decay: the kernel applies `exp(g)`, matching the reference. `q`, `k` are
|
| 47 |
+
`[B, T, H, Dk]`; `v` is `[B, T, H, Dv]`; `g`, `beta` are `[B, T, H]`;
|
| 48 |
+
returns `[B, T, H, Dv]`.
|
| 49 |
|
| 50 |
## API
|
| 51 |
|
|
|
|
| 55 |
| `new_state(batch, heads, key_dim, value_dim)` | a zeroed `[B, H, Dk, Dv]` fp32 state |
|
| 56 |
| `GatedDeltaNet(batch, heads, key_dim, value_dim, use_qk_l2norm)` | module holding the state across steps, one per layer |
|
| 57 |
|
| 58 |
+
## Method
|
| 59 |
+
|
| 60 |
+
Per token the update is a decay, a read, a rank-one correction and a read:
|
| 61 |
+
|
| 62 |
+
```
|
| 63 |
+
S <- S * exp(g) gated decay, one scalar per head
|
| 64 |
+
m <- k^T S what the state already predicts for this key
|
| 65 |
+
d <- (v - m) * beta the delta, scaled by the write gate
|
| 66 |
+
S <- S + k d^T rank-one write
|
| 67 |
+
out <- q^T S read with the query
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
The delta rule corrects the state by the difference between the value and
|
| 71 |
+
what the state already holds for that key, so writing the same key twice does
|
| 72 |
+
not double its contribution. The state is the whole cost, 64 KiB per head,
|
| 73 |
+
and here one block owns one (batch, head) pair with the state in its threads'
|
| 74 |
+
registers for the whole sequence: a thread owns one value column and a slice
|
| 75 |
+
of the key rows. Every intermediate token touches registers only.
|
| 76 |
+
|
| 77 |
+
## Measured
|
| 78 |
+
|
| 79 |
+
RTX 6000 Ada, 48 heads, 128 x 128 state, against the eager reference on the
|
| 80 |
+
same inputs:
|
| 81 |
+
|
| 82 |
+
| batch | tokens | eager | this | speedup |
|
| 83 |
+
|---|---|---|---|---|
|
| 84 |
+
| 1 | 1 | 0.435 ms | 0.028 ms | 15.3x |
|
| 85 |
+
| 1 | 64 | 7.451 ms | 0.347 ms | 21.4x |
|
| 86 |
+
| 1 | 512 | 61.114 ms | 2.787 ms | 21.9x |
|
| 87 |
+
| 4 | 256 | 40.268 ms | 2.468 ms | 16.3x |
|
| 88 |
+
|
| 89 |
+
State footprint, Bonsai 27B geometry: 3.0 MB per layer per sequence, 144 MB
|
| 90 |
+
across all 48 linear layers, constant in context length.
|
| 91 |
+
|
| 92 |
+
## Correctness
|
| 93 |
+
|
| 94 |
+
Verified against transformers 5.13:
|
| 95 |
+
|
| 96 |
+
- Output and final state agree with the reference to 5.5e-7 relative across
|
| 97 |
+
batch 1 to 3, 8 to 256 tokens, 2 to 8 heads, 64 and 128 dimensions, with
|
| 98 |
+
and without the in-kernel L2 normalization.
|
| 99 |
+
- Chunked equals whole: a 96-token sequence in six 16-token calls, carrying
|
| 100 |
+
the state, is `torch.equal` to one call; decoding token by token equals
|
| 101 |
+
the batched pass, state included.
|
| 102 |
+
- Gate semantics: `beta = 0` leaves the state exactly untouched; a large
|
| 103 |
+
negative `g` shrinks it by nine orders of magnitude; `g = 0` with
|
| 104 |
+
`beta = 0` is the exact identity.
|
| 105 |
+
- Deterministic: repeated runs are bitwise identical.
|
| 106 |
+
- The delta rule is stable only while `beta * |k|^2` stays near or below 2;
|
| 107 |
+
real models L2-normalize keys (`use_qk_l2norm`), and on out-of-region
|
| 108 |
+
input this kernel reproduces the reference's divergence to five
|
| 109 |
+
significant figures.
|
| 110 |
|
| 111 |
## Requirements and limits
|
| 112 |
|
| 113 |
+
- NVIDIA GPU with compute capability 8.0+; fp32 arithmetic (the state is a
|
| 114 |
+
long product chain).
|
| 115 |
+
- `Dv` must divide the 256-thread block, `Dk` divisible by `256 / Dv`,
|
| 116 |
+
`Dk / (256 / Dv) <= 64`; `Dk <= 256`. The 128 x 128 and 64 x 64
|
| 117 |
+
geometries satisfy all constraints.
|
| 118 |
+
- Recurrent form only: long prefills would run faster in the chunked
|
| 119 |
+
formulation; this kernel keeps the exact recurrence, which is what makes
|
| 120 |
+
chunked and token-by-token bitwise identical.
|
| 121 |
+
- Grouped heads are the caller's: repeat key and query heads before calling,
|
| 122 |
+
as the reference layer does. Forward only.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
|
| 124 |
## References
|
| 125 |
|
| 126 |
+
Yang et al., "Gated Delta Networks: Improving Mamba2 with Delta Rule"
|
| 127 |
+
(2024); Yang et al., "Parallelizing Linear Transformers with the Delta Rule
|
| 128 |
+
over Sequence Length" (2024); Schlag et al., "Linear Transformers Are
|
| 129 |
+
Secretly Fast Weight Programmers" (2021); the reference implementation in
|
| 130 |
+
transformers' `Qwen3_5GatedDeltaNet`.
|
| 131 |
|
| 132 |
## License
|
| 133 |
|