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}