README: re-measured perf on torch 2.13.0; exact chunk ~1.3x; chunked-wrapper dg caveat quantified; compiled decode step; bwd_batched from ~16 items
Browse files- README.md +63 -37
- build/torch-neuron/__init__.py +4 -4
README.md
CHANGED
|
@@ -60,11 +60,14 @@ Verify with `python -c "from kernels.backends import _backend; print(_backend().
|
|
| 60 |
scalar-mean decay approximation for the intra-chunk term — **see the warning below**.
|
| 61 |
- **`kda_chunk_step_exact(q, k, v, beta, g, state_in)`** — numerically exact
|
| 62 |
per-channel prefill (sub-chunk + WY reformulation). Use this when the model's gate
|
| 63 |
-
decay is non-trivial (see warning below). ~1.
|
| 64 |
- **`kda_chunk_step_exact_multihead(q, k, v, beta, g, state_in)`** — head-interleaved
|
| 65 |
exact prefill over `NV` heads (`[NV, C, dk]` shapes).
|
| 66 |
- **`kda_decode_batch(q, k, v, g, beta, state_in)`** — batched multi-(request, head)
|
| 67 |
decode; advances all `B*nv` items one token in a single call. Shapes `[B, nv, dk]`.
|
|
|
|
|
|
|
|
|
|
| 68 |
- **`kda_chunk_step_exact_bwd(q, k, v, beta, g, state_in, d_output, dS_final)`** —
|
| 69 |
exact chunked BACKWARD (gradient of `kda_chunk_step_exact`). Returns
|
| 70 |
`dq, dk, dv, dg, dbeta, dstate_in`, matching fla-core autograd at **cos_sim 1.0
|
|
@@ -82,20 +85,23 @@ Verify with `python -c "from kernels.backends import _backend; print(_backend().
|
|
| 82 |
state carry-over across chunks.
|
| 83 |
- **`kda_chunked_fused(q, k, v, g, beta, initial_state=None)`** → `(output, final_state)`.
|
| 84 |
Same numerics as `kda_chunked`, but processes all chunks in one NKI launch per
|
| 85 |
-
direction. Faster on multi-chunk sequences. **
|
|
|
|
|
|
|
| 86 |
- Raw kernels also exported: `kda_recurrent_fwd_v2`, `kda_chunk_step_v2`,
|
| 87 |
`kda_recurrent_bwd`, `kda_chunk_bwd`, `kda_fused_chunked_fwd`, `kda_fused_chunked_bwd`.
|
| 88 |
- **`kda_recurrent_bwd_batched(q, k, v, g, beta, state_stack, d_output, dS_final)`**
|
| 89 |
— batched recurrent backward over all `B*nv` (request, head) items in one launch
|
| 90 |
-
(flat work list + ping-pong state). ~
|
|
|
|
| 91 |
gradients bit-match the single-item `kda_recurrent_bwd`.
|
| 92 |
|
| 93 |
## Requirements
|
| 94 |
|
| 95 |
- **Hardware**: AWS Trainium (tested on trn2.3xlarge).
|
| 96 |
-
- **SDK / runtime**: PyTorch Native (`device="neuron"`)
|
| 97 |
- **NKI** ≥ 0.4.0.
|
| 98 |
-
- **`kernels`** ≥ 0.
|
| 99 |
- **`transformers`** with `KernelConfig` support, if using the `KernelConfig` path.
|
| 100 |
|
| 101 |
## Usage
|
|
@@ -151,6 +157,10 @@ loss.backward() # gradients flow through the NKI backward
|
|
| 151 |
# q.grad, k.grad, v.grad, g.grad, beta.grad now populated
|
| 152 |
```
|
| 153 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
Kernels operate per (batch, head); loop `B*H` in the caller.
|
| 155 |
|
| 156 |
## Input contract
|
|
@@ -200,13 +210,15 @@ cosine similarity vs the fla-core reference:
|
|
| 200 |
|
| 201 |
**If your model has non-trivial gate decay, use `kda_chunk_step_exact`** (or
|
| 202 |
`kda_chunk_step_exact_multihead`), which is numerically exact (cos_sim ≥ 0.9999999
|
| 203 |
-
across all gate regimes) at ~1.
|
| 204 |
(`kda_recurrent_fwd`, `kda_recurrent`) are exact in all regimes.
|
| 205 |
|
| 206 |
Because `kda_chunked` / `kda_chunked_fused` differentiate the approximate forward,
|
| 207 |
-
their `dg` gradient is the
|
| 208 |
-
|
| 209 |
-
|
|
|
|
|
|
|
| 210 |
|
| 211 |
## Parity
|
| 212 |
|
|
@@ -238,43 +250,57 @@ use `kda_chunk_step_exact_bwd` to fix it).
|
|
| 238 |
|
| 239 |
## Performance
|
| 240 |
|
| 241 |
-
Measured on trn2.3xlarge, LNC=2, single logical core,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 242 |
|
| 243 |
-
###
|
| 244 |
|
| 245 |
-
|
|
| 246 |
-
|--------|-------|
|
| 247 |
-
|
|
| 248 |
-
|
|
| 249 |
-
| Achieved TFLOPS | 1.89 |
|
| 250 |
-
| MFU (BF16 peak 158 TFLOPS/LNC=2) | 1.19% |
|
| 251 |
-
| MBU (empirical 218 GB/s/LNC=2) | 3.11% |
|
| 252 |
|
| 253 |
-
|
| 254 |
|
| 255 |
-
|
|
| 256 |
-
|--------|-------|
|
| 257 |
-
|
|
| 258 |
-
|
|
|
|
|
| 259 |
|
| 260 |
-
The
|
| 261 |
-
throughput, batch tokens (or requests via `kda_decode_batch`): per-token wall-clock
|
| 262 |
-
drops from ~70 μs at S=1 to ~6 μs at S=128, and `kda_decode_batch` amortizes launch
|
| 263 |
-
overhead across a whole serving batch.
|
| 264 |
|
| 265 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 266 |
|
| 267 |
-
|
| 268 |
-
|---|--------|----------------------|---------------------|
|
| 269 |
-
| 256 | 2 | 695 μs | 336 μs |
|
| 270 |
-
| 512 | 4 | 1320 μs | 338 μs |
|
| 271 |
-
| 1024 | 8 | 2588 μs | 529 μs |
|
| 272 |
|
| 273 |
-
|
| 274 |
-
|
|
|
|
|
|
|
|
|
|
| 275 |
|
| 276 |
-
|
| 277 |
-
|
| 278 |
|
| 279 |
## Not provided
|
| 280 |
|
|
|
|
| 60 |
scalar-mean decay approximation for the intra-chunk term — **see the warning below**.
|
| 61 |
- **`kda_chunk_step_exact(q, k, v, beta, g, state_in)`** — numerically exact
|
| 62 |
per-channel prefill (sub-chunk + WY reformulation). Use this when the model's gate
|
| 63 |
+
decay is non-trivial (see warning below). ~1.3× the latency of `kda_chunk_step`.
|
| 64 |
- **`kda_chunk_step_exact_multihead(q, k, v, beta, g, state_in)`** — head-interleaved
|
| 65 |
exact prefill over `NV` heads (`[NV, C, dk]` shapes).
|
| 66 |
- **`kda_decode_batch(q, k, v, g, beta, state_in)`** — batched multi-(request, head)
|
| 67 |
decode; advances all `B*nv` items one token in a single call. Shapes `[B, nv, dk]`.
|
| 68 |
+
9.4-19.5× faster than one launch per item. **But** on the tested build a `torch.compile`d
|
| 69 |
+
plain-PyTorch batched step (three `einsum`s, below) is 1.8-6.6× faster than this kernel at
|
| 70 |
+
B=1-32 × 32 heads; prefer that when your decode step is a static batched function.
|
| 71 |
- **`kda_chunk_step_exact_bwd(q, k, v, beta, g, state_in, d_output, dS_final)`** —
|
| 72 |
exact chunked BACKWARD (gradient of `kda_chunk_step_exact`). Returns
|
| 73 |
`dq, dk, dv, dg, dbeta, dstate_in`, matching fla-core autograd at **cos_sim 1.0
|
|
|
|
| 85 |
state carry-over across chunks.
|
| 86 |
- **`kda_chunked_fused(q, k, v, g, beta, initial_state=None)`** → `(output, final_state)`.
|
| 87 |
Same numerics as `kda_chunked`, but processes all chunks in one NKI launch per
|
| 88 |
+
direction. Faster on multi-chunk sequences. **Its `dg` is not the exact gradient** (cos
|
| 89 |
+
0.60-0.73 vs exact, even at g=0.01; see the warning below). For exact training use
|
| 90 |
+
`kda_recurrent`, or `kda_chunk_step_exact` + `kda_chunk_step_exact_bwd`.
|
| 91 |
- Raw kernels also exported: `kda_recurrent_fwd_v2`, `kda_chunk_step_v2`,
|
| 92 |
`kda_recurrent_bwd`, `kda_chunk_bwd`, `kda_fused_chunked_fwd`, `kda_fused_chunked_bwd`.
|
| 93 |
- **`kda_recurrent_bwd_batched(q, k, v, g, beta, state_stack, d_output, dS_final)`**
|
| 94 |
— batched recurrent backward over all `B*nv` (request, head) items in one launch
|
| 95 |
+
(flat work list + ping-pong state). Use from ~16 items: 0.80× at 4 items, 0.84× at 8,
|
| 96 |
+
1.40× at 16, 1.33× at 32 vs a per-(b,h) loop (S=8). All six
|
| 97 |
gradients bit-match the single-item `kda_recurrent_bwd`.
|
| 98 |
|
| 99 |
## Requirements
|
| 100 |
|
| 101 |
- **Hardware**: AWS Trainium (tested on trn2.3xlarge).
|
| 102 |
+
- **SDK / runtime**: PyTorch Native (`device="neuron"`). Tested: torch 2.13.0 / torch-neuronx 2.13.3 / neuronx-cc 2.0.404056 / NKI 0.7.0b1.
|
| 103 |
- **NKI** ≥ 0.4.0.
|
| 104 |
+
- **`kernels`** ≥ 0.17 (to load via `get_kernel`).
|
| 105 |
- **`transformers`** with `KernelConfig` support, if using the `KernelConfig` path.
|
| 106 |
|
| 107 |
## Usage
|
|
|
|
| 157 |
# q.grad, k.grad, v.grad, g.grad, beta.grad now populated
|
| 158 |
```
|
| 159 |
|
| 160 |
+
> `g.grad` from `kda_chunked_fused` is the gradient of the approximate forward (cos 0.60-0.73
|
| 161 |
+
> vs exact on the tested build). If the gate is trained, use `kda_recurrent` instead (same call
|
| 162 |
+
> signature) or the exact chunk kernels.
|
| 163 |
+
|
| 164 |
Kernels operate per (batch, head); loop `B*H` in the caller.
|
| 165 |
|
| 166 |
## Input contract
|
|
|
|
| 210 |
|
| 211 |
**If your model has non-trivial gate decay, use `kda_chunk_step_exact`** (or
|
| 212 |
`kda_chunk_step_exact_multihead`), which is numerically exact (cos_sim ≥ 0.9999999
|
| 213 |
+
across all gate regimes) at ~1.3× the latency. The recurrent kernels
|
| 214 |
(`kda_recurrent_fwd`, `kda_recurrent`) are exact in all regimes.
|
| 215 |
|
| 216 |
Because `kda_chunked` / `kda_chunked_fused` differentiate the approximate forward,
|
| 217 |
+
their `dg` gradient is the gradient of the *approximate* forward, not the exact
|
| 218 |
+
per-channel `dg`. Measured on the tested build, it is **cos 0.60-0.73 vs the exact
|
| 219 |
+
gradient even at g=0.01**, so do not rely on it for training a model with per-channel
|
| 220 |
+
gates. Use `kda_recurrent`, or `kda_chunk_step_exact` + `kda_chunk_step_exact_bwd`
|
| 221 |
+
(all six gradients cos ≥ 0.9999997 in every gate regime).
|
| 222 |
|
| 223 |
## Parity
|
| 224 |
|
|
|
|
| 250 |
|
| 251 |
## Performance
|
| 252 |
|
| 253 |
+
Measured on trn2.3xlarge, LNC=2, single logical core, 32 heads × 128 (dk = dv = 128).
|
| 254 |
+
Build: torch 2.13.0 / torch-neuronx 2.13.3 / neuronx-cc 2.0.404056 / NKI 0.7.0b1. Median device time with `torch.neuron.synchronize()` before each timer stop.
|
| 255 |
+
Measured on a pre-release PyTorch Native build; re-run on the release with `bash run.sh` from the companion benchmark repo.
|
| 256 |
+
|
| 257 |
+
### Prefill (one 128-token chunk, single (batch, head))
|
| 258 |
+
|
| 259 |
+
| Kernel | Wall-clock per chunk |
|
| 260 |
+
|--------|---------------------:|
|
| 261 |
+
| `kda_chunk_step` (approximate) | 248 μs |
|
| 262 |
+
| `kda_chunk_step_exact` | 318 μs (~1.3×) |
|
| 263 |
+
|
| 264 |
+
`kda_chunk_step_exact_multihead`, per head: 304 / 180 / 123 / 97 μs at NV = 1 / 2 / 4 / 8,
|
| 265 |
+
vs 340 / 204 / 156 / 148 μs for a per-head loop (1.53× at NV=8).
|
| 266 |
|
| 267 |
+
### Decode
|
| 268 |
|
| 269 |
+
| Kernel | Wall-clock per call |
|
| 270 |
+
|--------|--------------------:|
|
| 271 |
+
| `kda_recurrent_fwd`, S=1 | 297 μs |
|
| 272 |
+
| `kda_recurrent_fwd`, S=128 | 1,078 μs |
|
|
|
|
|
|
|
|
|
|
| 273 |
|
| 274 |
+
One decode step over B requests × 32 heads (μs per step):
|
| 275 |
|
| 276 |
+
| B | per-item launches | `kda_decode_batch` | compiled PyTorch step |
|
| 277 |
+
|--:|------------------:|-------------------:|----------------------:|
|
| 278 |
+
| 1 | 3,649 | 387 | **213** |
|
| 279 |
+
| 8 | 29,157 | 1,581 | **372** |
|
| 280 |
+
| 32 | 118,191 | 6,051 | **911** |
|
| 281 |
|
| 282 |
+
The compiled step is:
|
|
|
|
|
|
|
|
|
|
| 283 |
|
| 284 |
+
```python
|
| 285 |
+
def decode_step(q, k, v, g, beta, S): # [B, nv, D], state [B, nv, D, D]
|
| 286 |
+
S = S * g.exp().unsqueeze(-1)
|
| 287 |
+
kv = torch.einsum("bhk,bhkv->bhv", k, S)
|
| 288 |
+
S = S + torch.einsum("bhk,bhv->bhkv", beta * k, v - kv)
|
| 289 |
+
return torch.einsum("bhk,bhkv->bhv", q, S), S
|
| 290 |
+
|
| 291 |
+
step = torch.compile(decode_step, backend="neuron", dynamic=False)
|
| 292 |
+
```
|
| 293 |
|
| 294 |
+
### Training (fwd+bwd)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
|
| 296 |
+
| S | `kda_chunked_fused` |
|
| 297 |
+
|---|--------------------:|
|
| 298 |
+
| 256 | 1.41 ms |
|
| 299 |
+
| 512 | 1.89 ms |
|
| 300 |
+
| 1024 | 2.72 ms |
|
| 301 |
|
| 302 |
+
`kda_chunked` (Python chunk loop) at S=1024: 7.22 ms. `kda_recurrent` at S=128: 4.24 ms.
|
| 303 |
+
See the warning above before using the chunked wrappers for training.
|
| 304 |
|
| 305 |
## Not provided
|
| 306 |
|
build/torch-neuron/__init__.py
CHANGED
|
@@ -37,8 +37,8 @@ Functional warning:
|
|
| 37 |
regimes. See the README for details.
|
| 38 |
|
| 39 |
Requirements:
|
| 40 |
-
- PyTorch Native (device="neuron")
|
| 41 |
-
- NKI >= 0.4.0
|
| 42 |
|
| 43 |
License: Apache-2.0. Inference/training runtime kernel package (not a model).
|
| 44 |
The fla-core algorithm reference is MIT-licensed and compatible.
|
|
@@ -66,7 +66,7 @@ from .kda_fused_chunked_bwd import kda_fused_chunked_bwd
|
|
| 66 |
# amortizes launch overhead across a serving batch.
|
| 67 |
# - kda_chunk_step_exact: numerically exact per-channel prefill
|
| 68 |
# (cos_sim >= 0.9999999 in all gate regimes) vs the scalar-mean approximation
|
| 69 |
-
# in kda_chunk_step. ~1.
|
| 70 |
# - kda_chunk_step_exact_multihead: head-interleaved exact prefill.
|
| 71 |
from .nki_kda_decode_batch import kda_decode_batch
|
| 72 |
from .nki_kda_chunked_exact import kda_chunk_step_exact
|
|
@@ -84,7 +84,7 @@ from .nki_kda_chunked_exact_bwd import kda_chunk_step_exact_bwd
|
|
| 84 |
|
| 85 |
# Batched recurrent BACKWARD: advances all B*nv (request, head) items' reverse-token
|
| 86 |
# backward in one launch (flat work list + ping-pong state), mirroring the batched
|
| 87 |
-
# forward decode.
|
| 88 |
# single-item kernel.
|
| 89 |
from .nki_kda_recurrent_bwd_batched import kda_recurrent_bwd_batched
|
| 90 |
|
|
|
|
| 37 |
regimes. See the README for details.
|
| 38 |
|
| 39 |
Requirements:
|
| 40 |
+
- PyTorch Native (device="neuron"); tested on torch 2.13.0 / torch-neuronx 2.13.3
|
| 41 |
+
- NKI >= 0.4.0 (tested 0.7.0b1)
|
| 42 |
|
| 43 |
License: Apache-2.0. Inference/training runtime kernel package (not a model).
|
| 44 |
The fla-core algorithm reference is MIT-licensed and compatible.
|
|
|
|
| 66 |
# amortizes launch overhead across a serving batch.
|
| 67 |
# - kda_chunk_step_exact: numerically exact per-channel prefill
|
| 68 |
# (cos_sim >= 0.9999999 in all gate regimes) vs the scalar-mean approximation
|
| 69 |
+
# in kda_chunk_step. ~1.3x the latency of the approximation.
|
| 70 |
# - kda_chunk_step_exact_multihead: head-interleaved exact prefill.
|
| 71 |
from .nki_kda_decode_batch import kda_decode_batch
|
| 72 |
from .nki_kda_chunked_exact import kda_chunk_step_exact
|
|
|
|
| 84 |
|
| 85 |
# Batched recurrent BACKWARD: advances all B*nv (request, head) items' reverse-token
|
| 86 |
# backward in one launch (flat work list + ping-pong state), mirroring the batched
|
| 87 |
+
# forward decode. 1.3-1.4x over the per-(b,h) loop from ~16 items (slower below 8); all 6 gradients bit-match the
|
| 88 |
# single-item kernel.
|
| 89 |
from .nki_kda_recurrent_bwd_batched import kda_recurrent_bwd_batched
|
| 90 |
|