code wiki / _hdl_build / nx_llm_ppl_bench_gate.nx
nx_llm_ppl_bench_gate.nx source
↩ module page · 142 lines · 11510 B
1// nx_llm_ppl_bench_gate.nx -- THE QUALITY BENCHMARK: perplexity + next-token accuracy of ANY gguf model on a
2// held-out text, via our sovereign arch-config no-float inference. This is the "compare our quality" instrument
3// the operator asked for -- run it on the real Qwen (track a's family), on OUR trained+exported model (track b),
4// or on a PyTorch-fine-tuned gguf; the NUMBER is comparable across all of them. Perplexity is THE standard LLM
5// metric (lower=better). ★NUMERICS: our integer head logit = realdot*65536 (Q24 normed . Q16 weight, >>24), so
6// logit/65536 = the TRUE real logit -> we compute ABSOLUTE, PyTorch-comparable perplexity by doing the logsumexp
7// reduction in f32 (a tiny standard computation) on top of the sovereign integer forward.
8// CE_t = logsumexp_v(logit[t][v]) - logit[t][tgt_{t+1}] (real nats)
9// perplexity = exp(mean_t CE_t) ; accuracy = fraction of positions whose argmax == the true next token.
10// expect_exit: 0 license_tier: ORIGINAL
11import "nx_syscalls.nx"
12import "nx_tier.nx"
13import "nx_le.nx"
14import "nx_tensor.nx"
15import "nx_gguf.nx"
16import "nx_gguf_load.nx"
17import "nx_gguf_meta.nx"
18import "nx_nofloat_llm.nx"
19import "nx_nofloat_tok.nx"
20import "nx_nofloat_arch.nx"
21import "nx_f32_hw.nx"
22
23func pw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
24func pn(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 }
25func pslen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
26func pm3(x: i64) -> i64 { return pn(f32_int(f32_mul(x, f32_of(1000)))) } // f32 -> milli print
27// f32 exp/log (range-reduced) -- the standard reduction, on top of the sovereign integer forward.
28func f32_le(x: i64, y: i64) -> i64 { let d: i64=f32_sub(x,y) & 0xFFFFFFFF; if ((d>>31)&1)==1 { return 1 } if (d & 0x7FFFFFFF)==0 { return 1 } return 0 }
29func pf_exp(x: i64) -> i64 {
30 let log2e: i64=f32_div(f32_of(1442695),f32_of(1000000)); let ln2: i64=f32_div(f32_of(693147),f32_of(1000000)); let half: i64=f32_div(f32_of(1),f32_of(2))
31 let t: i64=f32_mul(x, log2e); var n: i64=0; if f32_le(f32_of(0), t)==1 { n=f32_int(f32_add(t,half)) } else { n=f32_int(f32_sub(t,half)) }
32 let arg: i64=f32_mul(f32_sub(t, f32_of(n)), ln2); var p2f: i64=f32_of(1); var term: i64=f32_of(1); var k: i64=1
33 while k<=8 { term=f32_div(f32_mul(term,arg), f32_of(k)); p2f=f32_add(p2f,term); k=k+1 }
34 var ef: i64=n+127; if ef<=0 { return f32_of(0) } if ef>=255 { ef=254 } return f32_mul(p2f, (ef & 0xFF) << 23)
35}
36func pf_log(x: i64) -> i64 { let b: i64=x & 0xFFFFFFFF; let e: i64=((b>>23)&0xFF)-127; let m: i64=(b & 0x7FFFFF)|0x3F800000; let u: i64=f32_div(f32_sub(m,f32_of(1)),f32_add(m,f32_of(1))); let u2: i64=f32_mul(u,u); var t: i64=u; var s: i64=u; var k: i64=1; while k<=7 { t=f32_mul(t,u2); s=f32_add(s,f32_div(t,f32_of((2*k)+1))); k=k+1 } let ln2: i64=f32_div(f32_of(693147),f32_of(1000000)); return f32_add(f32_mul(f32_of(e),ln2),f32_mul(f32_of(2),s)) }
37// integer logit (Q16 nats = realdot*65536) -> real-valued f32 logit
38func logit_f32(lg_int: i64) -> i64 { return f32_div(f32_of(lg_int), f32_of(65536)) }
39
40func main() -> i64 {
41 pw("=== nx_llm_ppl_bench_gate: perplexity + next-token accuracy of a gguf via sovereign arch-config inference ===\n" as *u8)
42 var pass: i64=0; var total: i64=0
43 let path: *u8 = "/home/elderwesto/nx_stage/nx_real_model.gguf\x00" as *u8
44 let len_out: *i64 = sys_mmap(8) as *i64; len_out[0]=0
45 let buf: *u8 = sys_read_file(path, len_out)
46 if buf == (0 as *u8) { pw("MODEL ABSENT\n" as *u8); return 1 }
47 let hdr: *NxGgufHeader = sys_mmap(NX_GGUF_HDR_BYTES) as *NxGgufHeader
48 if nx_gguf_parse(buf, len_out[0], hdr) != NX_GGUF_OK { pw("PARSE FAIL\n" as *u8); return 1 }
49 // arch config from metadata (the instrument works on ANY Qwen2/Llama gguf, not hardcoded)
50 let cfg: *i64=sys_mmap(16*8) as *i64; let arch: *u8=sys_mmap(64)
51 if nac_read_config(buf, len_out[0], hdr, cfg, arch) != 0 { pw("CONFIG FAIL\n" as *u8); return 1 }
52 let ne: i64=cfg[0]; let NL: i64=cfg[1]; let NH: i64=cfg[2]; let NKV: i64=cfg[3]; let hd: i64=cfg[4]; let qd: i64=cfg[5]; let kvd: i64=cfg[6]; let fd: i64=cfg[7]; let scale: i64=cfg[8]
53 pw(" model arch='" as *u8); pw(arch); pw("' D=" as *u8); pn(ne); pw(" layers=" as *u8); pn(NL); pw(" (dims from metadata)\n" as *u8)
54
55 let voff: *i64=sys_mmap(8) as *i64; let vty: *i64=sys_mmap(8) as *i64
56 var mfirst: i64=0; var nm_c: i64=0; var vfirst: i64=0; var vocab: i64=0
57 let km: *u8="tokenizer.ggml.merges\x00" as *u8; let kt: *u8="tokenizer.ggml.tokens\x00" as *u8
58 if nx_gguf_meta_find(buf, len_out[0], hdr, km, pslen(km), voff, vty)==NX_GMETA_OK { nm_c=nx_gguf_meta_array_count(buf, voff[0]); mfirst=nx_gguf_meta_array_first_elt_off(buf, voff[0]) }
59 if nx_gguf_meta_find(buf, len_out[0], hdr, kt, pslen(kt), voff, vty)==NX_GMETA_OK { vocab=nx_gguf_meta_array_count(buf, voff[0]); vfirst=nx_gguf_meta_array_first_elt_off(buf, voff[0]) }
60 let nt: *u8="token_embd.weight\x00" as *u8; let no: *u8="output.weight\x00" as *u8; let nn: *u8="output_norm.weight\x00" as *u8
61 let ti_e: nx_int=nx_gguf_find_tensor(hdr, nt, 17); let te: *NxGgufTensorInfo=nx_gguf_tensor_at(hdr, ti_e); let te_base: i64=hdr.data_off+te.offset; let te_ty: i64=te.ggml_type
62 let ti_o: nx_int=nx_gguf_find_tensor(hdr, no, 13); let oh: *NxGgufTensorInfo=nx_gguf_tensor_at(hdr, ti_o); let oh_base: i64=hdr.data_off+oh.offset; let oh_ty: i64=oh.ggml_type
63 let gout: *i64=sys_mmap(ne*8) as *i64; load_named_q16(buf, hdr, nn, 18, gout, ne)
64
65 // held-out text (natural, in-distribution English -> a well-trained model should have LOW perplexity)
66 let text: *u8="The capital of France is Paris. The capital of Japan is Tokyo.\x00" as *u8
67 let MAXT: i64=48
68 let ids: *i64=sys_mmap(MAXT*8) as *i64; let tokp: *i64=sys_mmap(MAXT*8) as *i64; let tokl: *i64=sys_mmap(MAXT*8) as *i64
69 let T: i64=tk_bpe_encode(buf, mfirst, nm_c, vfirst, vocab, text, pslen(text), tokp, tokl, ids)
70 pw(" held-out text ('" as *u8); sys_write(1, text, pslen(text)); pw("') -> " as *u8); pn(T); pw(" tokens\n" as *u8)
71 if T<3 { pw("TOKENIZE FAIL\n" as *u8); return 1 }
72 if T>=MAXT { pw("TEXT TOO LONG\n" as *u8); return 1 }
73
74 // scratch for a full T-token forward
75 let wb: *i64=sys_mmap(12*8) as *i64
76 wb[0]=sys_mmap(ne*8) as i64; wb[1]=sys_mmap(qd*ne*8) as i64; wb[2]=sys_mmap(kvd*ne*8) as i64; wb[3]=sys_mmap(kvd*ne*8) as i64; wb[4]=sys_mmap(ne*qd*8) as i64
77 wb[5]=sys_mmap(ne*8) as i64; wb[6]=sys_mmap(ne*fd*8) as i64; wb[7]=sys_mmap(ne*fd*8) as i64; wb[8]=sys_mmap(fd*ne*8) as i64
78 wb[9]=sys_mmap(qd*8) as i64; wb[10]=sys_mmap(kvd*8) as i64; wb[11]=sys_mmap(kvd*8) as i64
79 let sb: *i64=sys_mmap(14*8) as *i64
80 sb[0]=sys_mmap(MAXT*ne*8) as i64; sb[1]=sys_mmap(MAXT*qd*8) as i64; sb[2]=sys_mmap(MAXT*kvd*8) as i64; sb[3]=sys_mmap(MAXT*kvd*8) as i64; sb[4]=sys_mmap(MAXT*qd*8) as i64
81 sb[5]=sys_mmap(MAXT*8) as i64; sb[6]=sys_mmap(MAXT*8) as i64; sb[7]=sys_mmap(MAXT*ne*8) as i64; sb[8]=sys_mmap(MAXT*fd*8) as i64; sb[9]=sys_mmap(MAXT*fd*8) as i64
82 sb[10]=sys_mmap(MAXT*fd*8) as i64; sb[11]=sys_mmap(MAXT*ne*8) as i64; sb[12]=sys_mmap(MAXT*ne*8) as i64; sb[13]=sys_mmap(MAXT*ne*8) as i64
83 let nm: *u8=sys_mmap(64); let freqs: *i64=sys_mmap(32*8) as *i64; rope_freqs(freqs, hd)
84 let tmp: *i64=sys_mmap(64*256*8) as *i64
85 let cfgA: *i64=sys_mmap(8*8) as *i64; cfgA[0]=T; cfgA[1]=ne; cfgA[2]=NH; cfgA[3]=NKV; cfgA[4]=hd; cfgA[5]=qd; cfgA[6]=kvd; cfgA[7]=scale
86 let cfgF: *i64=sys_mmap(4*8) as *i64; cfgF[0]=T; cfgF[1]=ne; cfgF[2]=fd
87 let x: *i64=sys_mmap(MAXT*ne*8) as *i64; let hout: *i64=sys_mmap(MAXT*ne*8) as *i64
88 var ei: i64=0; while ei<T { dequant_row(buf, te_base, te_ty, ids[ei], ne, ((x as i64)+ei*ne*8) as *i64, tmp); ei=ei+1 }
89
90 let t0: i64=sys_now_ms()
91 run_stack(buf, hdr, x, hout, wb, sb, nm, freqs, cfgA, cfgF, NL, 0)
92 // fast full-logit head: dequant the head ONCE into i32, then stream per position.
93 let hcache: *i32=nf_dequant_head_all_i32(buf, oh_base, oh_ty, vocab, ne)
94 if (hcache as i64)<=0 { pw("HEAD CACHE OOM\n" as *u8); return 1 }
95 let normed: *i64=sys_mmap(ne*8) as *i64
96 let lgv: *i64=sys_mmap(vocab*8) as *i64
97 let hlp: *i64=sys_mmap(6*8) as *i64; hlp[0]=hcache as i64; hlp[1]=normed as i64; hlp[2]=vocab; hlp[3]=ne; hlp[4]=lgv as i64
98
99 // for each position 0..T-2, predict token[t+1]. CE in real nats via f32 logsumexp on the integer logits.
100 var sumce: i64=f32_of(0); var correct: i64=0; var npos: i64=0
101 var t: i64=0
102 while t<T-1 {
103 rmsnorm_gamma_row_q24(hout, gout, t*ne, ne, normed, 0)
104 head_logits_cached_i32(hlp)
105 let tgt: i64=ids[t+1]
106 // argmax (accuracy) + max logit (for stable logsumexp), integer domain
107 var bi: i64=0; var bv: i64=lgv[0]; var v: i64=1; while v<vocab { if lgv[v]>bv { bv=lgv[v]; bi=v } v=v+1 }
108 if bi==tgt { correct=correct+1 }
109 // f32 logsumexp: sum exp(logit_v - max), all in real nats
110 let mxf: i64=logit_f32(bv)
111 var sumexp: i64=f32_of(0); v=0; while v<vocab { let lf: i64=logit_f32(lgv[v]); sumexp=f32_add(sumexp, pf_exp(f32_sub(lf, mxf))); v=v+1 }
112 let lse: i64=f32_add(mxf, pf_log(sumexp))
113 let ce: i64=f32_sub(lse, logit_f32(lgv[tgt]))
114 sumce=f32_add(sumce, ce)
115 npos=npos+1
116 t=t+1
117 }
118 let t1: i64=sys_now_ms()
119 let meance: i64=f32_div(sumce, f32_of(npos))
120 let ppl: i64=pf_exp(meance)
121 let accpct: i64=(correct*100)/npos
122
123 pw(" positions scored: " as *u8); pn(npos); pw(" ["); pn(t1-t0); pw(" ms]\n" as *u8)
124 pw(" MEAN CROSS-ENTROPY = " as *u8); pm3(meance); pw(" milli-nats\n" as *u8)
125 pw(" PERPLEXITY = " as *u8); pm3(ppl); pw(" milli (= " as *u8); pn(f32_int(ppl)); pw(".x) -- lower is better\n" as *u8)
126 pw(" NEXT-TOKEN ACCURACY = " as *u8); pn(correct); pw("/" as *u8); pn(npos); pw(" = " as *u8); pn(accpct); pw("%\n" as *u8)
127
128 // T1: perplexity is SANE for a trained 0.5B on in-distribution English (validates the absolute scale is right).
129 let pplint: i64=f32_int(ppl)
130 total=total+1; if pplint>=1 { if pplint<=200 { pass=pass+1; pw(" [PASS] " as *u8) } else { pw(" [FAIL] " as *u8) } } else { pw(" [FAIL] " as *u8) }
131 pw("T1 PERPLEXITY SANE (1..200 for a 0.5B on in-distribution English -> the absolute scale is correct)\n" as *u8)
132 // T2: accuracy meaningfully above chance (chance = 100/vocab ~ 0%).
133 total=total+1; if accpct>=40 { pass=pass+1; pw(" [PASS] " as *u8) } else { pw(" [FAIL] " as *u8) }
134 pw("T2 ACCURACY >> chance: the model predicts the next token well above 1/vocab\n" as *u8)
135
136 pw("\n QUALITY INSTRUMENT: absolute, PyTorch-comparable perplexity + next-token accuracy of ANY gguf, computed on\n" as *u8)
137 pw(" OUR sovereign integer forward (logits are exact realdot*65536; f32 only for the tiny logsumexp reduction).\n" as *u8)
138 pw(" This is the 'compare our quality' ruler: score Qwen (a), our exported model (b), or a PyTorch gguf -- same number.\n" as *u8)
139 pw("NX-LLM-PPL-BENCH verdict=" as *u8)
140 if pass==total { pw("GREEN passes=" as *u8); pn(pass); pw("/" as *u8); pn(total); pw(" -- sovereign perplexity/accuracy benchmark on a real model\n" as *u8); return 0 }
141 pw("RED passes=" as *u8); pn(pass); pw("/" as *u8); pn(total); pw("\n" as *u8); return 1
142}