Repository navigation
feat(indexed_attention): windowed GQA forward + deterministic key-tile dK/dV (Triton) - #22
Merged
Merged
Conversation
faresobeid
marked this pull request as ready for review
October 24, 2026 17:54
samsja
approved these changes
Oct 26, 2026
samsja
pushed a commit
to PrimeIntellect-ai/prime-rl
that referenced
this pull request
Oct 26, 2026
…on plan under AC (#4279) Bumps prime-kernels from `v0.1.0-3101960` to `v0.1.0-b52bd9d` (wheel URLs, `deps/prime-kernels` submodule, `uv.lock`). Also adds `prime_kernels::indexed_attention_plan` to `MANDATORY_SAVE_OPERATIONS`, so full AC does not rebuild the plan in the recompute. ## What the new kernels bring (Qwen3.8-Flash-Next QSA; API unchanged) - PrimeIntellect-ai/prime-kernels#22: `indexed_attention` as windowed GQA Triton kernels. A new plan op groups 5 queries per window. 1.2-3.7x per QSA layer fwd+bwd on H200 (16K: 116 -> 31 ms, 64K: 352 -> 191 ms, CP8 rank 16K x 131K: 84 -> 65 ms) and lower peak memory. The dK/dV backward is key-major with no atomics, so it is bitwise deterministic. - PrimeIntellect-ai/prime-kernels#23: `select_indexed_blocks` uses query-tiled scores and a radix select without atomics. 3.8-4.4x on selection (64K: 32 -> 7.2 ms, CP8 at 1M: 2186 -> 516 ms). Scores and selected sets are bitwise equal to before, and the output order is now deterministic (ascending). - The release also carries the DeepSelect wheel (#17), used by #3958; this PR does not pin it. ## Plan save under full AC The plan depends only on the indices and syncs to host for its sizes. Without the save it is built twice per step (forward and recompute). Profiled step (4-layer Qwen3.8, one QSA layer, full AC): `_window_keys_kernel` launches 4 -> 2, so the plan is built once. ## Numbers (1 node, 8x H200, FSDP, 4-layer Qwen3.8 `q38-4l-small`, full AC, SGD; median step after 2 warmup steps, 8 steps) | tokens / rank | main (3101960) | new kernels, plan not saved | this PR | |---|---|---|---| | 16K | 1.087 s | 0.908 s | 0.904 s | | 64K | 3.754 s | 3.613 s | 3.593 s | - Only 1 of the 4 layers is QSA, so the full-model gain is smaller than the per-layer gain. Saving the plan saves about 20 ms per QSA layer at 64K. - Loss per step matches main to about 1e-4 relative, the same run-to-run noise main shows. The two new-kernel arms give bitwise-equal losses over all 8 steps. ## Validation - H200 with the release wheel: `test_qwen3_8_flash_next.py` + `test_checkpointing.py` (16 passed). prime-kernels `smoke_test.py prime-kernels` OK, prime-kernels `tests/` (6 passed). - `pytest -m "not gpu" tests/unit/orchestrator tests/unit/test_configs.py tests/unit/train` (620 passed), `ruff check`, `ruff format --check`, `uv lock --check` (uv 0.13.5). <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches training correctness under full activation checkpointing and swaps prebuilt GPU kernel wheels; mis-saving the plan could change numerics or performance on QSA paths. > > **Overview** > Bumps **prime-kernels** from `v0.1.0-3101960` to **`v0.1.0-b52bd9d`** on Linux x86_64 and aarch64 (`pyproject.toml` wheel URLs and matching **`uv.lock`** hashes). > > Adds **`prime_kernels::indexed_attention_plan`** to **`MANDATORY_SAVE_OPERATIONS`** in activation checkpointing so **full AC** keeps the indexed-attention plan across forward and recompute instead of rebuilding it (paired with the new kernels’ plan op). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 96d8822. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rewrites the
indexed_attentionkernels (Qwen3.8-Flash-Next QSA) as windowed GQA Triton kernels with a deterministic backward. The public API is unchanged:indexed_attention(query, key, value, indices, scale).select_indexed_blocksstays in TileLang.On main, one TileLang CTA runs per query and KV head: the 12 heads of a KV group are padded to 16 MMA rows, each CTA gathers its ~2,051 selected K/V rows by itself, and the backward scatters dK/dV with fp32 atomics (not deterministic).
Change
prime_kernels::indexed_attention_plan, new): groups 5 consecutive queries into a window and stores, per window, the sorted distinct keys with a 5-bit mask of which queries select each key, plus the transpose (per 32-key tile, the selecting windows in order). Built once per call and saved for backward; smaller than the indices main saves (60 MiB vs 128 MiB at 16K).requiresgainstriton.Numbers (H200, one Qwen3.8 QSA layer: 24 q / 2 KV heads, head_dim 256, 2,048-token budget; median ms, fwd+bwd incl. plan)
Indices come from prime-rl's
SparseAttentionIndexerwith random weights on locally correlated hidden states. The gain depends on window overlap: with a less local selection (union 3.8x at 64K) it is 1.08x.Validation
torch.compile(fullgraph=True, dynamic=True)is bitwise equal to eager. batch=2 matches two single calls.Notes
prime_kernels::indexed_attention_planis added to the AC save list. Using this in prime-rl needs a wheel release and a pin bump.In a prime-rl RL run
prime-rl main
1882f7b98on 1 node (8×H200). Random-weight 4-layer Qwen3.8 (indexed_attentionruns in layer 3; the n-gram table is not frozen). Reverse-text task,debugalgorithm, NCCL broadcast, vLLM TP4. Batch 64 × ~3.1K tokens (above the 2,048-token budget). 24 steps, no AC. A = main's kernel (prime-kernels3101960), B = this PR (20685c4). Each arm is the built wheel onPYTHONPATH; a per-rank call counter confirmed the trainer used the intended kernel.Mismatch KL rises 0.093 → 0.104 in all four runs as token staleness grows (mean 11, max 23;
max_staleness = 32). There is no difference between the kernels.Exact check: same weights and batch, one trainer forward + backward (4 GPUs, full AC, two packed documents). Diffs of per-token logprobs, and of the layer-3 attention parameter gradients (relative L2):
A vs B differs by no more than main's kernel differs from itself on a repeat. With this PR, the whole trainer forward and backward is bitwise reproducible, with and without CP.