nx_f32_attn_multi.nx
buildroot/runtime/nx_f32_attn_multi.nx
about
nx_f32_attn_multi.nx -- bits-up f32 multi-token attention kernel.
L7 / L8 composition brick. The prerequisite for both prefill
(processing a whole prompt) and KV cache decode (attending to
growing cache).
Composes nx_f32_dot + nx_f32_mul + nx_f32_softmax + nx_f32_add.
No libm.
Algorithm:
Inputs:
Q [n_tokens_q, head_dim] query tensor
K [n_tokens_k, head_dim] key tensor (may be larger when
attending to a KV cache)
V [n_tokens_k, head_dim] value tensor
For each query token i in 0..n_tokens_q:
For each key token j in 0..n_tokens_k:
scores[j] = dot(Q[i,:], K[j,:]) * attn_scale
(if causal: positions j > q_pos_i are masked with -inf)
probs = softmax(scores)
For each output dim d:
out[i, d] = sum_j probs[j] * V[j, d]
For causal LM during prefill: q_pos_i = i (query i can attend
to keys 0..=i).
For causal LM during KV-cache decode: q_pos_i = n_tokens_k -
n_tokens_q + i (query at end of cache, attends to all prior).
K^T transpose is handled by index arithmetic (we access K row-by-
row in its natural [n_tokens_k, head_dim] layout); no physical
transpose needed.
genealogy_id: vaswani_2017_attention + causal_mask_standard
lineage_id: substrate_f32_attn_multi_v1
dependencies 5 imports · 12 importers
diagram shows first 10 each side; +0 more imports, +2 more importers in the complete lists below.
imports: nx_syscalls.nxnx_tier.nxnx_f32.nxnx_f32_matmul.nxnx_f32_softmax.nx
imported by: nx_f32_attn_cached.nxnx_f32_attn_cached_test.nxnx_f32_attn_multi_test.nxnx_f32_attn_paged.nxnx_f32_llama_block.nxnx_f32_llama_block_test.nxnx_f32_llama_block_v4.nxnx_f32_llama_block_v4_test.nxnx_f32_llama_v4b.nxnx_f32_llama_v4p.nxnx_f32_mha_multi.nxnx_f32_mha_multi_test.nx
structs
| none |
consts
| 44 | const NX_F32_AM_OK: nx_int = 0 |
| 45 | const NX_F32_AM_ERR_BAD_DIM: nx_int = 1 |
| 46 | const NX_F32_AM_N_VERDICTS: nx_int = 2 |
functions
| 48 | func nx_f32_am_verdict_is_valid(v: nx_int) -> nx_int called by 1: main |
| 62 | func nx_f32_attn_multi( |