code wiki / (root) / nx_gen_sdpa_verify.nx

nx_gen_sdpa_verify.nx

buildroot/runtime/nx_gen_sdpa_verify.nx

7735 B186 linesdepth 6pulls 13 transitivereach 0 importersview sourcekind tooltopic gen
docsdependenciesstructsconstsfunctions

about

nx_gen_sdpa_verify.nx -- SOVEREIGN scaled dot-product attention, verified vs the oracle. scores[lk] = sum_d q[h][lq][d] * k[h][lk][d] / sqrt(head_dim) out[lq][h][d] = sum_lk softmax(scores)[lk] * v[lk][h][d] THE SCALE, derived not guessed: ggml_ext_attention_ext uses scale = 1/sqrt(d_head). It also takes a kv_scale (1/128 here) which it applies to k and v before an f16 cast to avoid overflow -- but that cancels EXACTLY: the flash path passes scale/kv_scale into the softmax and then multiplies the result by 1/kv_scale, and the fallback path never applies kv_scale at all. So the arithmetic to reproduce is plain SDPA with 1/sqrt(head_dim), and reading kv_scale as the softmax scale would have been wrong by 11x while still producing a finite, plausible tensor. Usage: nx_gen_sdpa_verify <model> <q> <k> <qkv> <out> <head_dim> <n_heads> <v_head_base> [rows] ⚠THREE DIFFERENT LAYOUTS MEET HERE, which is the whole difficulty: q, k [head_dim, L, n_heads] -> (h*L + l)*head_dim + d (post-RoPE order) v packed qkv [qkv_width, L] -> l*qkv_width + (base+h)*head_dim + d out [n_heads*head_dim, L] -> l*(n_heads*head_dim) + h*head_dim + d RoPE permuted q/k but v is still read straight from the fused projection, so v does NOT share q's layout. Every index is written out explicitly rather than shared. Softmax subtracts the row max before exponentiating -- without it, logits of a few hundred overflow f32 exp and the whole row becomes NaN or zero. license_tier: ORIGINAL

dependencies 9 imports · 0 importers

nx_syscalls.nx nx_le.nx nx_f32.nx nx_f32_div.nx nx_f32_cvt.nx nx_f32_exp.nx nx_strconv.nx nx_genfix.nx nx_genver.nx nx_gen_sdpa_verify.nx

imports: nx_syscalls.nxnx_le.nxnx_f32.nxnx_f32_div.nxnx_f32_cvt.nxnx_f32_exp.nxnx_strconv.nxnx_genfix.nxnx_genver.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main nx_genver_emit sys_mmap nxa_die sys_write sys_exit nxa_lock_take nxa_lock_addr sys_write ↻ nxa_lock_give nxa_lock_addr ↻ nxa_report_overrun sys_write ↻ nxa_dump_printable sys_write ↻ nxa_dump_sizes sys_write ↻ nx_strconv_format_i64 sys_write ↻ sys_mmap ↻ nx_strconv_parse_i64 nx_ascii_is_digit zs_strlen nx_genfix_dims sys_mmap ↻ _gf_read_manifest sys_mmap ↻ _gf_cpyz nx_genfix_root sys_openat_rd sys_read sys_close nx_genfix_load _gf_path sys_mmap ↻ _gf_cpyz ↻ nx_genfix_root ↻ _gf_cpy sys_openat_rd ↻ sys_mmap ↻

structs

none

consts

none

functions

36func zs_strlen(s: *u8) -> i64
called by 1: main
42func main(argc: i64, argv: *i64) -> i64