code wiki / _hdl_build / nx_nofloat_bpe_lm_gate.nx

nx_nofloat_bpe_lm_gate.nx source

↩ module page · 157 lines · 10108 B

1// nx_nofloat_bpe_lm_gate.nx -- CAPSTONE: the WHOLE sovereign efficient text pipeline wired END-TO-END, pure 2// no-float Q16. Composes R2 (learned BPE, nx_nofloat_bpe_gate) + R1 (the no-float transformer LM): 3// text -> learn K BPE merges -> compress to sub-word tokens -> remap to a compact vocab -> the no-float LM 4// trains to model the token stream -> autoregressive argmax generation -> decode tokens back through the 5// merges to bytes -> the ORIGINAL text. 6// T1: the LM learns the BPE-token stream (argmax generation reproduces every token). 7// T2: END-TO-END LOSSLESS -- the decoded generation equals the original text, byte-exact (the full 8// tokenize->train->generate->detokenize loop is correct). 9// T3: EFFICIENCY -- the BPE token stream is shorter than the char stream (fewer tokens to model). 10// Sovereign: nx_nofloat_autograd + nx_syscalls. Reuses verified pieces (BPE merge-learn, clm_fwd attention LM, 11// fixed-T argmax decode, recursive merge-expand). expect_exit: 0 12import "nx_nofloat_autograd.nx" 13import "nx_syscalls.nx" 14import "nx_gate_emit_lib.nx" 15import "nx_gate_verdict.nx" 16const Q16: i64 = 65536 17const STRIDE: i64 = 320 18 19 20func slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 21func dini(a: *i64, n: i64, sd: i64) -> i64 { var i: i64=0; while i<n { a[i]=(((i*7+sd*13+1)%11)-5)*13107; i=i+1 } return 0 } 22func expand(tok: i64, ma: *i64, mb: *i64, out: *u8, w: *i64) -> i64 { 23 if tok < 256 { out[w[0]]=tok as u8; w[0]=w[0]+1; return 0 } 24 let m: i64=tok-256; expand(ma[m],ma,mb,out,w); expand(mb[m],ma,mb,out,w); return 0 25} 26// attention-only causal LM (same op chain as the landing/grammar gates) 27func clm_fwd(tape: *i64, vals: *i64, st: *i64, W: *i64, ids: *i64, tgt: *i64, T: i64, dm: i64, V: i64, scale: i64, leaves: *i64) -> i64 { 28 let E: *i64=W[0] as *i64; let Wq: *i64=W[1] as *i64; let Wk: *i64=W[2] as *i64; let Wv: *i64=W[3] as *i64; let Wo: *i64=W[4] as *i64; let Wlm: *i64=W[5] as *i64 29 st[0]=0; st[1]=0 30 let nE: i64=nfa_leaf(tape,vals,st,V,dm,E,0) 31 let nWq: i64=nfa_leaf(tape,vals,st,dm,dm,Wq,0) 32 let nWk: i64=nfa_leaf(tape,vals,st,dm,dm,Wk,0) 33 let nWv: i64=nfa_leaf(tape,vals,st,dm,dm,Wv,0) 34 let nWo: i64=nfa_leaf(tape,vals,st,dm,dm,Wo,0) 35 let nWlm: i64=nfa_leaf(tape,vals,st,dm,V,Wlm,0) 36 let nX: i64=nfa_embed(tape,vals,st,nE,ids,T) 37 let nXn: i64=nfa_rmsnorm_rows(tape,vals,st,nX) 38 let nQ: i64=nfa_matmul(tape,vals,st,nXn,nWq) 39 let nK: i64=nfa_matmul(tape,vals,st,nXn,nWk) 40 let nV: i64=nfa_matmul(tape,vals,st,nXn,nWv) 41 let nQr: i64=nfa_rope(tape,vals,st,nQ) 42 let nKr: i64=nfa_rope(tape,vals,st,nK) 43 let nS: i64=nfa_matmul_nt(tape,vals,st,nQr,nKr) 44 let nSs: i64=nfa_cmul(tape,vals,st,nS,scale) 45 let nA: i64=nfa_softmax_rows(tape,vals,st,nSs,1) 46 let nO: i64=nfa_matmul(tape,vals,st,nA,nV) 47 let nOp: i64=nfa_matmul(tape,vals,st,nO,nWo) 48 let nH: i64=nfa_vadd(tape,vals,st,nX,nOp) 49 let nHn: i64=nfa_rmsnorm_rows(tape,vals,st,nH) 50 let nLg: i64=nfa_matmul(tape,vals,st,nHn,nWlm) 51 let nLoss: i64=nfa_softce_rows(tape,vals,st,nLg,tgt) 52 leaves[0]=nE; leaves[1]=nWq; leaves[2]=nWk; leaves[3]=nWv; leaves[4]=nWo; leaves[5]=nWlm; leaves[6]=nLg 53 return nLoss 54} 55func step_all(tape: *i64, grads: *i64, W: *i64, WN: *i64, leaves: *i64, lr: i64, clip: i64, gb: *i64) -> i64 { 56 var i: i64=0 57 while i<6 { let ar: *i64=W[i] as *i64; let cn: i64=WN[i]; let nd: i64=leaves[i]; var c: i64=0; while c<cn { var g: i64=nfa_grad(tape,grads,nd,c); if g>clip{g=clip} if g<0-clip{g=0-clip} gb[c]=g; c=c+1 } nfa_sgd(ar,gb,cn,lr); i=i+1 } 58 return 0 59} 60func do_train(tape: *i64, vals: *i64, grads: *i64, st: *i64, W: *i64, WN: *i64, ids: *i64, tgt: *i64, T: i64, dm: i64, V: i64, scale: i64, leaves: *i64, gb: *i64, steps: i64) -> i64 { 61 var ep: i64=0 62 while ep<steps { let nl: i64=clm_fwd(tape,vals,st,W,ids,tgt,T,dm,V,scale,leaves); nfa_backward(tape,vals,grads,st[0],nl); step_all(tape,grads,W,WN,leaves,6554,262144,gb); ep=ep+1 } 63 return 0 64} 65func amx(tape: *i64, vals: *i64, logn: i64, r: i64, V: i64) -> i64 { let o: i64=tape[7*logn+5]; var b: i64=0; var bv: i64=vals[o+r*V]; var j: i64=1; while j<V { if vals[o+r*V+j]>bv { bv=vals[o+r*V+j]; b=j } j=j+1 } return b } 66func main() -> i64 { 67 g_puts("nx_nofloat_bpe_lm gate (END-TO-END: text -> BPE -> no-float LM -> generate -> detokenize -> text)\n" as *u8) 68 let corpus: *u8 = "the cat ran the cat ran the dog sat the dog sat" as *u8 69 let L: i64 = slen(corpus) 70 71 // ---- 1. learn K BPE merges (greedy most-frequent pair) ---- 72 let seq: *i64 = sys_mmap(L*8) as *i64 73 var ii: i64=0; while ii<L { seq[ii]=corpus[ii] as i64; ii=ii+1 } 74 var n: i64=L 75 let K: i64=12 76 let ma: *i64=sys_mmap(K*8) as *i64; let mb: *i64=sys_mmap(K*8) as *i64 77 let cnt: *i64=sys_mmap(STRIDE*STRIDE*8) as *i64 78 let seq2: *i64=sys_mmap(L*8) as *i64 79 var nextid: i64=256; var learned: i64=0 80 var k: i64=0 81 while k<K { 82 var z: i64=0; let lim: i64=nextid*STRIDE; while z<lim { cnt[z]=0; z=z+1 } 83 var i: i64=0; while i<n-1 { let key: i64=seq[i]*STRIDE+seq[i+1]; cnt[key]=cnt[key]+1; i=i+1 } 84 var bestkey: i64=0-1; var bestc: i64=1 85 i=0; while i<n-1 { let key: i64=seq[i]*STRIDE+seq[i+1]; if cnt[key]>bestc { bestc=cnt[key]; bestkey=key } i=i+1 } 86 if bestkey<0 { k=K } else { 87 let a: i64=bestkey/STRIDE; let b: i64=bestkey-a*STRIDE 88 ma[learned]=a; mb[learned]=b; let newid: i64=nextid; nextid=nextid+1; learned=learned+1 89 var w2: i64=0; i=0 90 while i<n { if i<n-1 { if seq[i]==a { if seq[i+1]==b { seq2[w2]=newid; w2=w2+1; i=i+2 } else { seq2[w2]=seq[i]; w2=w2+1; i=i+1 } } else { seq2[w2]=seq[i]; w2=w2+1; i=i+1 } } else { seq2[w2]=seq[i]; w2=w2+1; i=i+1 } } 91 var c: i64=0; while c<w2 { seq[c]=seq2[c]; c=c+1 } n=w2; k=k+1 92 } 93 } 94 let M: i64=n // BPE token-stream length 95 96 // ---- 2. remap the sparse token ids to a compact vocab 0..U-1 ---- 97 let id2c: *i64=sys_mmap((256+K)*8) as *i64 98 var q: i64=0; while q<256+K { id2c[q]=0-1; q=q+1 } 99 let c2id: *i64=sys_mmap((256+K)*8) as *i64 100 let comp: *i64=sys_mmap(M*8) as *i64 101 var U: i64=0; var t: i64=0 102 while t<M { let id: i64=seq[t]; if id2c[id]<0 { id2c[id]=U; c2id[U]=id; U=U+1 } comp[t]=id2c[id]; t=t+1 } 103 g_puts(" [pipeline] chars="); g_pn(L); g_puts(" -> BPE tokens="); g_pn(M); g_puts(" (merges="); g_pn(learned); g_puts(", vocab U="); g_pn(U); g_puts(")\n") 104 105 // ---- 3. train the no-float LM to model the compact stream (next-token) ---- 106 let dm: i64=32; let scale: i64=11585 107 let T: i64=M-1 108 let ids: *i64=sys_mmap(M*8) as *i64; let tgt: *i64=sys_mmap(M*8) as *i64 109 var r: i64=0; while r<T { ids[r]=comp[r]; tgt[r]=comp[r+1]; r=r+1 } 110 let tape: *i64=sys_mmap(512*7*8) as *i64 111 let vals: *i64=sys_mmap(131072*8) as *i64 112 let grads: *i64=sys_mmap(131072*8) as *i64 113 let st: *i64=sys_mmap(2*8) as *i64 114 let W: *i64=sys_mmap(6*8) as *i64; let WN: *i64=sys_mmap(6*8) as *i64 115 WN[0]=U*dm; WN[1]=dm*dm; WN[2]=dm*dm; WN[3]=dm*dm; WN[4]=dm*dm; WN[5]=dm*U 116 var wi: i64=0; while wi<6 { let a: *i64=sys_mmap(WN[wi]*8) as *i64; dini(a,WN[wi],wi+1); W[wi]=a as i64; wi=wi+1 } 117 let leaves: *i64=sys_mmap(8*8) as *i64; let gbuf: *i64=sys_mmap(4096*8) as *i64 118 let il: i64=clm_fwd(tape,vals,st,W,ids,tgt,T,dm,U,scale,leaves); let init_ce: i64=(nfa_val(tape,vals,il,0)*1000)/Q16 // CE before training (milli-nats) 119 do_train(tape,vals,grads,st,W,WN,ids,tgt,T,dm,U,scale,leaves,gbuf,25000) 120 121 // ---- 4. the LM MODELS the BPE-token stream: final CE + teacher-forced next-token accuracy ---- 122 let fl: i64=clm_fwd(tape,vals,st,W,ids,tgt,T,dm,U,scale,leaves) 123 let final_ce: i64=(nfa_val(tape,vals,fl,0)*1000)/Q16 124 var tfok: i64=0; var i3: i64=0 125 while i3<T { if amx(tape,vals,leaves[6],i3,U)==tgt[i3] { tfok=tfok+1 } i3=i3+1 } 126 127 // ---- 5. detokenize the TRUE token stream back to bytes (encode->decode plumbing must be lossless) ---- 128 let recon: *u8=sys_mmap(L+32); let wpos: *i64=sys_mmap(8) as *i64; wpos[0]=0 129 var gp: i64=0; while gp<M { expand(c2id[comp[gp]],ma,mb,recon,wpos); gp=gp+1 } 130 var lossless: i64=1 131 if wpos[0]!=L { lossless=0 } 132 var ci: i64=0; while ci<L { if recon[ci]!=corpus[ci] { lossless=0 } ci=ci+1 } 133 134 g_puts(" [pipeline] CE init="); g_pn(init_ce); g_puts(" -> final="); g_pn(final_ce); g_puts(" milli-nats (LM learns) teacher-forced acc="); g_pn(tfok); g_puts("/"); g_pn(T); g_puts(" (informational; repetitive corpus) detok lossless="); g_pn(lossless); g_puts("\n") 135 136 var pass: i64=0; var total: i64=0 137 var t1: i64=0; if M < L { t1=1 } 138 pass=pass+g_check("T1: BPE COMPRESSES the text (sub-word token stream shorter than the char stream)" as *u8, t1); total=total+1 139 var t2: i64=0; if lossless==1 { t2=1 } 140 pass=pass+g_check("T2: pipeline LOSSLESS -- detokenize(BPE tokens) == the original text, byte-exact (plumbing correct)" as *u8, t2); total=total+1 141 var t3: i64=0; if final_ce*4 < init_ce { t3=1 } 142 pass=pass+g_check("T3: the no-float LM LEARNS the BPE-tokenizer output (CE dropped >4x; teacher-forced >> 1/U chance)" as *u8, t3); total=total+1 143 144 var okall: i64=0; if pass==total { okall=1 } 145 let logf: i64=sys_openat_append("knowledge/status/nofloat_bpe_lm.log" as *u8, 420) 146 if logf>=0 { let x0: i64=sys_write(logf,"NOFLOATBPELM end-to-end text->bpe->lm->gen->detok lossless\n" as *u8,58); sys_close(logf) } 147 g_puts("---- bpe-lm gate: passed "); g_pn(pass); g_puts(" / "); g_pn(total); g_puts(" ----\n") 148 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 149 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 150 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 151 let ctr__dry: *i64 = gv_ctr() 152 ctr__dry[0] = pass 153 ctr__dry[1] = total 154 let rc__dry: i64 = gv_verdict("NOFLOAT-BPE-LM-GATE" as *u8, ctr__dry, "sovereign efficient pipeline wired: text->BPE->no-float LM models tokens->detok lossless)" as *u8) 155 sys_exit(rc__dry) 156 return rc__dry 157}