jburtoft commited on
Commit
ca4ade9
·
1 Parent(s): 4652a91

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
Files changed (2) hide show
  1. README.md +63 -37
  2. 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.05× 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
  - **`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. **Recommended for training.**
 
 
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). ~1.1–1.24× over a per-(b,h) loop; all six
 
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"`), torch-neuronx 2.11+, PyTorch 2.11+.
97
  - **NKI** ≥ 0.4.0.
98
- - **`kernels`** ≥ 0.15.2 (to load via `get_kernel`).
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.05× the latency. The recurrent kernels
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 exact gradient of the *approximate* forward — self-consistent
208
- for training with these kernels, but not equal to the exact-per-channel `dg` unless the
209
- approximation is accurate (i.e. small gate decay).
 
 
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, single (batch, head) invocation.
 
 
 
 
 
 
 
 
 
 
 
 
242
 
243
- ### Prefill (chunked)
244
 
245
- | Metric | Value |
246
- |--------|-------|
247
- | Wall-clock per chunk (C=128) | 87 μs |
248
- | Per-token effective | 0.68 μs |
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
- ### Decode (recurrent)
254
 
255
- | Metric | Value |
256
- |--------|-------|
257
- | Wall-clock per call (S=128) | 527 μs |
258
- | Per-token (amortized) | 4.1 μs |
 
259
 
260
- The recurrent kernel is overhead-dominated at small sequence lengths. For real decode
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
- ### Training (fused vs Python chunk loop, fwd+bwd)
 
 
 
 
 
 
 
 
266
 
267
- | S | Chunks | `kda_chunked` (loop) | `kda_chunked_fused` |
268
- |---|--------|----------------------|---------------------|
269
- | 256 | 2 | 695 μs | 336 μs |
270
- | 512 | 4 | 1320 μs | 338 μs |
271
- | 1024 | 8 | 2588 μs | 529 μs |
272
 
273
- The fused path pays per-launch overhead once instead of per chunk, so its advantage
274
- grows with sequence length. Prefer `kda_chunked_fused` for training.
 
 
 
275
 
276
- MFU/MBU denominators are per LNC=2 core on trn2 (NeuronCore-v3), from the AWS
277
- Trainium2 architecture guide and empirical measurements.
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"), torch-neuronx 2.11+, PyTorch 2.11+
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.05x 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,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. ~1.1-1.24x over the per-(b,h) loop; all 6 gradients bit-match the
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