GPU / Attention / Interactive Lab
← All visualizations
SOURCE-GROUNDED · SUBBLOCKTOPK · PR #8335

How BlockSelector works

Watch 64 tokens become four 16-token mean vectors, produce a 4×4 similarity matrix, collapse into one FP32 block score, and finally become a sparse KV-block selection. All numbers are computed from reproducible synthetic Q/K tensors in your browser.

Q/K layout: BSHDDemo head dim: D=32Logical blocks: 64×6416-token poolingOriginal source ↗
STEP 01 / 05

Start with Q and K

Pick a query block and a key block to inspect their 64-token representations.

The current scorer pools 16-token groups instead of computing all 4096 Q×K token interactions.

Inside one 64 × 64 block pair

Q0 and K5 · four pooled vectors each

64 → 4 groups

Query tokens [64, 32]

Four contiguous 16-token groups; each position below is a token.

Key tokens [64, 32]

Same pooling, separately applied to K.
q̄ᵢ[d] = (1/16) × Σ q[16i+t, d] for t=0..15 k̄ⱼ[d] = (1/16) × Σ k[16j+t, d] for t=0..15 Q̄: [4, 32] K̄: [4, 32]

Sixteen similarities → one block score

Actual dot products from the pooled tensors above (D=32).

FP32 accumulator
Sᵢⱼ = mean(Qᵢ) · mean(Kⱼ) / √D
Click a value to inspect its Q/K subblock pair.
S_block = log ∑ᵢ₌₀³ ∑ⱼ₌₀³ exp(Sᵢⱼ) Implemented as two LogSumExp reductions: K subblocks → Q subblocks. The GPU uses exp2/log2 internally, then converts back to natural-log units.
Block relevance scoreone scalar for selected Q × K
0.000

Block scores → Top-k selection

4 query blocks × 24 key blocks; each cell is one LogSumExp score.

higher score → stronger bluefocused pair
Protected2
Top-k from candidates8
Total selected10

Upstream's _fused_topk uses 16–32 rounds of a Triton threshold search, then compacts selected block IDs. This page ranks scores exactly for illustration; tie/threshold behavior in the GPU implementation can differ in pathological cases.

BlockSelection contract

The adapter consumes indices and counts; it does not redo block selection.

EXISTING ABI
indices: int32 [B=1, Hq=1, Qblocks=4, capacity=10][0, 1, 4, 8, ...]counts: int32 [1, 1, 4][10, 10, 10, 10]
Sorted IDsUnique + in rangePrefix preservedConstant counts (current Top-k)
Top-p is not implemented here. The proposed adaptive selector in RFC 0002 would normalize these scores and produce variable counts per query block, while keeping the same ABI.

Source ↔ visualization

SubBlockTopK.select() └─ select_subblocks() [opaque custom op] └─ _route() ├─ block_budget() [round up to 8] ├─ _compute_scores() │ ├─ _fused_pool(Q), _fused_pool(K) │ └─ _fused_scores() [dot + LogSumExp] └─ _select_blocks() └─ _fused_topk() [threshold + compact] └─ BlockSelection(indices, counts)

The source branch is a draft of PR #8335 (not yet merged at creation). It supports CUDA, FP16/BF16 Q/K, a protected KV prefix, and native MHA/MQA/GQA mapping.

Important interpretation

The score is an approximation of Q-block relevance to a KV block. It is not the exact probability mass from full 64×64 token attention. Top-k uses the score rank rather than a Softmax probability.

The output has only KV-block IDs and counts. V is not used by this selector; the selected-key attention provider consumes Q/K/V afterward.

The data here are synthetic but every pooled mean, dot product, LogSumExp, budget and output array is recomputed on interaction. No CDN, tracking, external scripts or build dependencies.

Links: Upstream RFC #8396 · Adaptive selector RFC tracking