nx_gen_qknorm_verify.nx
buildroot/runtime/nx_gen_qknorm_verify.nx
about
nx_gen_qknorm_verify.nx -- SOVEREIGN per-head QK-RMSNorm over a PACKED qkv, verified vs oracle.
out[t][h][d] = qkv[t][(head_base+h)*head_dim + d] / sqrt(mean_d(.^2) + eps) * w[d]
QK-norm normalizes each attention head's query (or key) vector independently over head_dim,
reading from the fused qkv projection where q, k and v are packed head-major in one row.
Z-Image, Qwen-Image and most recent DiTs do this; it is the first stage of the attention core.
Usage:
nx_gen_qknorm_verify <model> <qkv> <norm_w> <out> <head_dim> <n_heads> <head_base> [rows] [eps_recip]
head_base 0 for q; n_heads for k (q, k, v are packed in that order)
WHY THIS IS A SEPARATE ORGAN AND NOT THE RMSNORM ONE: the two tensors have DIFFERENT row
strides. The packed qkv row is (n_q + n_k + n_v) * head_dim wide, while the output row is
n_heads * head_dim. A generic normalizer that assumed one stride would read the wrong head and
still produce finite, plausible numbers -- the failure mode this lane keeps meeting.
Hardware __f32_* intrinsics in the hot loop, never the nx_f32_* software twins.
license_tier: ORIGINAL
dependencies 8 imports · 0 importers
imports: nx_syscalls.nxnx_le.nxnx_f32.nxnx_f32_div.nxnx_f32_cvt.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
structs
| none |
consts
| 29 | const K_MAGIC_1000000: i64 = 1000000 |
functions
| 31 | func zq_strlen(s: *u8) -> i64 called by 1: main |
| 37 | func main(argc: i64, argv: *i64) -> i64 |