This document is relevant for: Trn2, Trn3
Sparse Attention Indexer MX BF16Score Kernel API Reference#
DeepSeek Sparse Attention Indexer — MX projections + BF16 score.
Supported/optimal usage: head_dim == 128; dim and q_lora_rank multiples of 512; batch_size == 1 and S a multiple of P_MAX (=128) on the validated v3_long/h64 configs; LNC sharding degree up to 2.
Background#
The sparse_attention_indexer_mx_bf16score kernel implements the DeepSeek Sparse Attention Indexer with MX projections and a BF16 score path.
API Reference#
Source code for this kernel API can be found at: sparse_attention_indexer_mx_bf16score.py
sparse_attention_indexer_mx_bf16score#
- nkilib.experimental.sparse_attention_indexer.sparse_attention_indexer_mx_bf16score(x: nl.NkiTensor, wq_b: nl.NkiTensor, wk: nl.NkiTensor, k_norm_gamma: nl.NkiTensor, k_norm_beta: nl.NkiTensor, weights_proj: nl.NkiTensor, cos: nl.NkiTensor, sin: nl.NkiTensor, k_cache: nl.NkiTensor, mask: nl.NkiTensor, n_heads: int, head_dim: int, rope_head_dim: int, index_topk: int, start_pos: int, use_hadamard: bool = False, batch_size: int = 1, wq_b_scale: Optional[nl.NkiTensor] = None, wk_scale: Optional[nl.NkiTensor] = None, k_scale_cache: Optional[nl.NkiTensor] = None, x_non_mx: Optional[nl.NkiTensor] = None, x_mx_data: Optional[nl.NkiTensor] = None, x_mx_scale: Optional[nl.NkiTensor] = None, qr_qtz_hbm: Optional[nl.NkiTensor] = None, qr_scale_hbm: Optional[nl.NkiTensor] = None, phase: str = 'all', k_seq_out_hbm: Optional[nl.NkiTensor] = None, end_pos_arg: Optional[int] = None, emit_flat_topk: bool = False, emit_tiled_topk: bool = False) tuple[nl.NkiTensor, nl.NkiTensor]#
DeepSeek Sparse Attention Indexer — MX projections + BF16 score.
- Parameters:
x (
nl.NkiTensor) – [B*S, dim] hidden states.qr_qtz_hbm (
Optional[nl.NkiTensor]) – [num_s_tiles, P_MAX, q_lora_rank // (P_MAX*H_PACK), P_MAX] uint32 — pre-quantized (fp8x4-as-uint32) compressed query from the upstream QKV kernel.qr_scale_hbm (
Optional[nl.NkiTensor]) – matching uint8 block-32 e8m0 scales for qr_qtz_hbm.wq_b (
nl.NkiTensor) – [q_lora_rank // 4, n_heads * head_dim] fp8_e4m3fn_x4.wq_b_scale (
Optional[nl.NkiTensor]) – [q_lora_rank // 32, n_heads * head_dim] uint8 e8m0.wk (
nl.NkiTensor) – [dim // 4, head_dim] fp8_e4m3fn_x4 (contraction dim on partition).wk_scale (
Optional[nl.NkiTensor]) – [dim // 32, head_dim] uint8 e8m0. k_norm_gamma, k_norm_beta: [head_dim] LayerNorm gamma/beta.weights_proj (
nl.NkiTensor) – [n_heads, dim] per-head weights projection (always bf16). cos, sin: [S, rope_head_dim // 2] RoPE caches.k_cache (
nl.NkiTensor) – [B, head_dim, max_seq_len] bf16 (mutable).k_scale_cache (
Optional[nl.NkiTensor]) – ignored (no MX scales in bf16 path).mask (
nl.NkiTensor) – [B*S, end_pos] attention mask.index_topk (
int) – number of top positions to select per query (topk k).x_non_mx (
Optional[nl.NkiTensor]) – pre-cast bf16 view of x for W-projection (skips the f32->bf16 cast). x_mx_data, x_mx_scale: pre-quantized x for K-projection (skips the in-kernel swizzle + quantize_mx). qr_qtz_hbm, qr_scale_hbm: pre-quantized qr latent from an upstream QKV kernel (indexer skips its own qr transpose+norm+quantize). This is the only Q input path — qr is never quantized in-kernel.phase (
str) – context-parallel phased split. “all” (default): fused self-attention (queries == keys == S). “kproj”: project K for this rank’s S shard only; write seq-major [S, head_dim] to k_seq_out_hbm, return (that, None), no score. “score”: skip K-proj; score this rank’s S queries vs the pre-gathered full k_cache [B, head_dim, end_pos_arg=S_kv] over [0, S_kv).k_seq_out_hbm (
Optional[nl.NkiTensor]) – [S, head_dim] bf16 K output for phase=”kproj”.end_pos_arg (
Optional[int]) – key range for phase=”score” (defaults to start_pos + S).emit_flat_topk (
bool) – decode the snake topk to per-query positions in-kernel and return flat [B*S, index_topk] int32 (the sparse_mla_latent_attn topk_indices contract). Fuses the out-of-kernel snake->flat decode.emit_tiled_topk (
bool) – split-fix output — skip the per-query scatter and return positions in the natural partition-tiled layout [num_s_tiles, NUM_TOPK_BATCHES, P_MAX, index_topk // 16] int32, read per-query by the paired attention kernel. Mutually exclusive with emit_flat_topk; both default False (snake output, decoded by the consumer, e.g. the fused mega kernel).
- Returns:
[B*S, end_pos] f32 — pre-topk per-position scores.
- Return type:
nl.ndarray- Returns:
[num_S_tiles_total, NUM_TOPK_BATCHES, P_MAX, index_topk] uint32 — hardware-topk output.
topk_idx[s_tile, t, 16g + j%16, j//16]holds the position (0-based in[0, end_pos)) of query8t + g’s j-th largest score (ascending).num_S_tiles_total = batch_size * ceil(S / P_MAX).- Return type:
nl.ndarray
Notes:
Q/K/W projections still use
nc_matmul_mxfor speed, but the score matmul uses bf16 nc_matmul (no Q/K quantization, no Hadamard rotation). This removes the Q swizzle + quantize_mx + Hadamard chain from the per-S-tile critical path.K cache stores bf16 instead of fp8x4 (no need for MX format if downstream consumers use this same kernel; otherwise downstream must coordinate).
Algorithm equivalent to the MX variant via Hadamard’s orthogonality:
q_H @ (k_H).T = q @ H @ H.T @ k.T = q @ k.Tso dropping Hadamard is mathematically a no-op. The MX quantization that Hadamard exists to support is also dropped on the score path. Score precision improves (bf16 score matmul vs MX-rounded score matmul).
Dimensions:
B: batch size (= batch_size).
S: query sequence length per batch.
M: B * S (total query rows, = x.shape[0]).
dim: hidden size (= x.shape[1]).
q_lora_rank: compressed-query rank (derived from qr_qtz_hbm layout).
n_heads: number of indexer heads.
head_dim: per-head dimension (== 128).
rope_head_dim: RoPE-rotated slice of head_dim.
end_pos: start_pos + S (KV positions scored per query).
P_MAX: partition tile size (= 128).
This document is relevant for: Trn2, Trn3