code wiki / _hdl_build / nx_nofloat_xformer_gate.nx

nx_nofloat_xformer_gate.nx source

↩ module page · 228 lines · 12678 B

1// nx_nofloat_xformer_gate.nx -- HARD-EVIDENCE gate for the TRANSFORMER-SUBLAYER backward ops added to the 2// no-float autograd (softmax / silu / rmsnorm): the nonlinearities of a Qwen block, now DIFFERENTIABLE in 3// pure integer Q16. This is the CAP-NF-TRAIN-XFORMER rung: backprop through the transformer's own ops. 4// 5// A GRADCHECK each op (oracle = mathematics): build loss = mse(OP(x), target), compare the tape's analytic 6// reverse-sweep grad dL/dx_i against a CENTRAL finite difference (L(x+h)-L(x-h))/2h, all Q16. Done for 7// softmax (Jacobian-vector product), silu (x*sigmoid(x) derivative), rmsnorm (normalization Jacobian). 8// D TEETH (neg-control): negate one analytic grad and assert the SAME check now FAILS -> a wrong gradient 9// is provably caught (the agreement in A is real, not vacuous). 10// B A TRANSFORMER ACTIVATION TRAINS: fit y = silu(w*.x) (realizable, w*=1.5) from w=0 by GD through the 11// tape+silu backward. Assert loss collapses >=90% and w converges to w*. Proves the FFN nonlinearity is 12// trainable end-to-end in pure integer. 13// C BIT-EXACT: train twice from zero -> identical integer w (determinism is structural for integer). 14// 15// Evidence -> knowledge/status/nofloat_xformer.log. Sovereign: imports nx_nofloat_autograd (pure integer; NO 16// nx_f32 in the import graph) + nx_syscalls. license_tier: ORIGINAL expect_exit: 0 17import "nx_nofloat_autograd.nx" 18import "nx_g_check_lib.nx" 19import "nx_g_pn_lib.nx" 20import "nx_g_puts_lib.nx" 21import "nx_syscalls.nx" 22import "nx_gate_verdict.nx" 23 24const XLOG: *u8 = "knowledge/status/nofloat_xformer.log" 25const Q16: i64 = 65536 26const OP_SOFTMAX: i64 = 5 27const OP_SILU: i64 = 6 28const OP_RMSNORM: i64 = 7 29 30func g_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } 31func q_milli(q: i64) -> i64 { var neg: i64=0; var a: i64=q; if a<0 { neg=1; a=0-a } let m: i64=(a*1000)/Q16; if neg==1 { return 0-m } return m } 32func x_ws(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 } 33func x_wn(fd: i64, v: i64) -> i64 { 34 let b: *u8 = sys_mmap(28); var m: i64=v; if m<0 { sys_write(fd,"-" as *u8,1); m=0-m } 35 let t: *u8 = sys_mmap(28); var k: i64=0; if m==0 { t[0]=48; k=1 } 36 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } 37 var i: i64=0; while i<k { b[i]=t[k-1-i]; i=i+1 } sys_write(fd,b,k); return 0 38} 39 40// ---- build loss = mse(OP(x), target) on the general tape; leaves[0] = the x leaf. ---- 41func xf_loss(tape: *i64, vals: *i64, st: *i64, op_sel: i64, xs: *i64, ts: *i64, n: i64, leaves: *i64) -> i64 { 42 st[0]=0; st[1]=0 43 let nx: i64 = nfa_leaf(tape,vals,st,n,1,xs,0) 44 var nop: i64 = nx 45 if op_sel == OP_SOFTMAX { nop = nfa_softmax(tape,vals,st,nx) } 46 if op_sel == OP_SILU { nop = nfa_silu(tape,vals,st,nx) } 47 if op_sel == OP_RMSNORM { nop = nfa_rmsnorm(tape,vals,st,nx) } 48 let nt: i64 = nfa_leaf(tape,vals,st,n,1,ts,0) 49 let loss: i64 = nfa_mse(tape,vals,st,nop,nt) 50 leaves[0]=nx 51 return loss 52} 53func xf_lossval(tape: *i64, vals: *i64, st: *i64, op_sel: i64, xs: *i64, ts: *i64, n: i64) -> i64 { 54 let lv: *i64 = sys_mmap(8) as *i64 55 let loss: i64 = xf_loss(tape,vals,st,op_sel,xs,ts,n,lv) 56 return nfa_val(tape,vals,loss,0) 57} 58// central finite diff of the loss wrt x[pi], Q16 step h 59func xf_fd(tape: *i64, vals: *i64, st: *i64, op_sel: i64, xs: *i64, ts: *i64, n: i64, pi: i64, h: i64) -> i64 { 60 let xp: *i64 = sys_mmap(n*8) as *i64 61 let xm: *i64 = sys_mmap(n*8) as *i64 62 var i: i64 = 0 63 while i < n { xp[i]=xs[i]; xm[i]=xs[i]; i=i+1 } 64 xp[pi]=xs[pi]+h; xm[pi]=xs[pi]-h 65 let lp: i64 = xf_lossval(tape,vals,st,op_sel,xp,ts,n) 66 let lm: i64 = xf_lossval(tape,vals,st,op_sel,xm,ts,n) 67 return ((lp - lm) * Q16) / (2 * h) 68} 69// gradcheck one op over all n inputs; sets worst[0]=worst relative-error milli; returns 1 if all within tol. 70func xf_gradcheck(tape: *i64, vals: *i64, grads: *i64, st: *i64, op_sel: i64, xs: *i64, ts: *i64, n: i64, h: i64, tol_q: i64, floor_q: i64, worst: *i64) -> i64 { 71 let lv: *i64 = sys_mmap(8) as *i64 72 let loss: i64 = xf_loss(tape,vals,st,op_sel,xs,ts,n,lv) 73 nfa_backward(tape,vals,grads,st[0],loss) 74 let nx: i64 = lv[0] 75 var ok: i64 = 1; worst[0]=0 76 var i: i64 = 0 77 while i < n { 78 let ana: i64 = nfa_grad(tape,grads,nx,i) 79 let fd: i64 = xf_fd(tape,vals,st,op_sel,xs,ts,n,i,h) 80 let num: i64 = g_abs(fd - ana) 81 var den: i64 = g_abs(ana); if den < floor_q { den = floor_q } 82 let thresh: i64 = (tol_q * den) >> 16 83 if num >= thresh { ok = 0 } 84 let rel: i64 = (num * 1000) / den 85 if rel > worst[0] { worst[0] = rel } 86 i = i + 1 87 } 88 return ok 89} 90 91// ---- Gate B/C: train w to fit y = silu(w*.x) (realizable, w*=1.5 Q16) via tape + silu backward ---- 92func xf_silu_build(tape: *i64, vals: *i64, st: *i64, wp: *i64, X: *i64, Y: *i64, T: i64, outW: *i64) -> i64 { 93 st[0]=0; st[1]=0 94 let nw: i64 = nfa_leaf(tape,vals,st,1,1,wp,0) 95 outW[0]=nw 96 var root: i64 = 0 - 1 97 var t: i64 = 0 98 while t < T { 99 let nx: i64 = nfa_leaf(tape,vals,st,1,1,X,t) 100 let h: i64 = nfa_matvec(tape,vals,st,nw,nx) // w*x 101 let s: i64 = nfa_silu(tape,vals,st,h) // silu(w*x) 102 let ny: i64 = nfa_leaf(tape,vals,st,1,1,Y,t) 103 let nm: i64 = nfa_mse(tape,vals,st,s,ny) 104 if root < 0 { root = nm } else { root = nfa_vadd(tape,vals,st,root,nm) } 105 t = t + 1 106 } 107 return root 108} 109func xf_silu_train(tape: *i64, vals: *i64, grads: *i64, st: *i64, epochs: i64, lr_q: i64, wout: *i64, lf: *i64, ll: *i64) -> i64 { 110 let T: i64 = 4 111 let Wt: i64 = 98304 // w* = 1.5 Q16 112 let X: *i64 = sys_mmap(T*8) as *i64 113 X[0]=32768; X[1]=65536; X[2]=98304; X[3]=131072 // x = 0.5,1.0,1.5,2.0 114 let Y: *i64 = sys_mmap(T*8) as *i64 115 var t: i64 = 0 116 while t < T { Y[t] = nfa_siluf((Wt * X[t]) >> 16); t = t + 1 } // realizable targets via the lib's silu 117 let wp: *i64 = sys_mmap(8) as *i64; wp[0]=0 // learn from ZERO 118 let outW: *i64 = sys_mmap(8) as *i64 119 let g: *i64 = sys_mmap(8) as *i64 120 var ep: i64 = 0 121 while ep < epochs { 122 let root: i64 = xf_silu_build(tape,vals,st,wp,X,Y,T,outW) 123 nfa_backward(tape,vals,grads,st[0],root) 124 if ep == 0 { *lf = nfa_val(tape,vals,root,0) } 125 *ll = nfa_val(tape,vals,root,0) 126 g[0] = nfa_grad(tape,grads,outW[0],0) 127 nfa_sgd(wp, g, 1, lr_q) 128 ep = ep + 1 129 } 130 wout[0]=wp[0] 131 return 0 132} 133 134func main() -> i64 { 135 g_puts("nx_nofloat_xformer gate (backprop through softmax/silu/rmsnorm in PURE INTEGER Q16 -- MEASURED)\n" as *u8) 136 var pass: i64 = 0; var total: i64 = 0 137 let tape: *i64 = sys_mmap(512*7*8) as *i64 138 let vals: *i64 = sys_mmap(4096*8) as *i64 139 let grads: *i64 = sys_mmap(4096*8) as *i64 140 let st: *i64 = sys_mmap(2*8) as *i64 141 let n: i64 = 4 142 let h: i64 = 512 143 let floor_q: i64 = 4096 144 let worst: *i64 = sys_mmap(8) as *i64 145 146 // ---- A1: softmax gradcheck ---- 147 let xs1: *i64 = sys_mmap(n*8) as *i64; xs1[0]=32768; xs1[1]=0-16384; xs1[2]=49152; xs1[3]=0 148 let ts1: *i64 = sys_mmap(n*8) as *i64; ts1[0]=26214; ts1[1]=6554; ts1[2]=26214; ts1[3]=6554 149 let sm_ok: i64 = xf_gradcheck(tape,vals,grads,st,OP_SOFTMAX,xs1,ts1,n,h,4096,floor_q,worst) // tol 1/16 150 g_puts(" [measure] softmax worst rel grad err = " as *u8); g_pn(worst[0]); g_puts(" /1000 (tol=62/1000)\n" as *u8) 151 pass = pass + g_check("A1: softmax gradcheck -- tape Jacobian-vector backward == finite differences" as *u8, sm_ok); total=total+1 152 153 // ---- A2: silu gradcheck ---- 154 let xs2: *i64 = sys_mmap(n*8) as *i64; xs2[0]=32768; xs2[1]=0-32768; xs2[2]=65536; xs2[3]=0-65536 155 let ts2: *i64 = sys_mmap(n*8) as *i64; ts2[0]=19661; ts2[1]=0-13107; ts2[2]=52429; ts2[3]=0-17695 156 let si_ok: i64 = xf_gradcheck(tape,vals,grads,st,OP_SILU,xs2,ts2,n,h,4096,floor_q,worst) // tol 1/16 157 g_puts(" [measure] silu worst rel grad err = " as *u8); g_pn(worst[0]); g_puts(" /1000 (tol=62/1000)\n" as *u8) 158 pass = pass + g_check("A2: silu gradcheck -- tape x*sigmoid(x) backward == finite differences" as *u8, si_ok); total=total+1 159 160 // ---- A3: rmsnorm gradcheck (normalization Jacobian; fixed-point isqrt/div -> looser honest tol) ---- 161 let xs3: *i64 = sys_mmap(n*8) as *i64; xs3[0]=32768; xs3[1]=65536; xs3[2]=0-32768; xs3[3]=16384 162 let ts3: *i64 = sys_mmap(n*8) as *i64; ts3[0]=13107; ts3[1]=58982; ts3[2]=0-39322; ts3[3]=6554 163 let rn_ok: i64 = xf_gradcheck(tape,vals,grads,st,OP_RMSNORM,xs3,ts3,n,h,4096,floor_q,worst) // tol 1/16 (measured 13/1000) 164 g_puts(" [measure] rmsnorm worst rel grad err = " as *u8); g_pn(worst[0]); g_puts(" /1000 (tol=62/1000)\n" as *u8) 165 pass = pass + g_check("A3: rmsnorm gradcheck -- tape normalization-Jacobian backward == finite differences" as *u8, rn_ok); total=total+1 166 167 // ---- D: neg-control (teeth) on silu ---- 168 let lv: *i64 = sys_mmap(8) as *i64 169 let loss: i64 = xf_loss(tape,vals,st,OP_SILU,xs2,ts2,n,lv) 170 nfa_backward(tape,vals,grads,st[0],loss) 171 let ana0: i64 = nfa_grad(tape,grads,lv[0],0) 172 let fd0: i64 = xf_fd(tape,vals,st,OP_SILU,xs2,ts2,n,0,h) 173 let bad: i64 = 0 - ana0 174 var den0: i64 = g_abs(ana0); if den0 < floor_q { den0 = floor_q } 175 let thr0: i64 = (4096 * den0) >> 16 176 var caught: i64 = 1 177 if g_abs(fd0 - bad) < thr0 { caught = 0 } 178 pass = pass + g_check("D: neg-control -- a deliberately WRONG grad is rejected by the gradcheck (teeth)" as *u8, caught); total=total+1 179 180 // ---- B: a transformer activation TRAINS (silu regression, realizable) ---- 181 let wbox: *i64 = sys_mmap(8) as *i64 182 let lf: *i64 = sys_mmap(8) as *i64 183 let ll: *i64 = sys_mmap(8) as *i64 184 xf_silu_train(tape,vals,grads,st, 6000, 1024, wbox, lf, ll) 185 g_puts(" [measure] silu-regression loss: start=" as *u8); g_pn(*lf); g_puts(" end=" as *u8); g_pn(*ll) 186 g_puts(" learned w=" as *u8); g_pn(wbox[0]); g_puts(" (milli=" as *u8); g_pn(q_milli(wbox[0])); g_puts(") vs w*=98304 (1500 milli)\n" as *u8) 187 var learns: i64 = 1 188 if (*ll) * 10 > (*lf) { learns = 0 } // >= 90% loss reduction 189 if g_abs(wbox[0] - 98304) > 9830 { learns = 0 } // within 15% of w* 190 if (*lf) <= 0 { learns = 0 } 191 pass = pass + g_check("B: a transformer activation LEARNS in pure integer -- silu regression converges to w*" as *u8, learns); total=total+1 192 193 // ---- C: bit-exact reproducible ---- 194 let wbox2: *i64 = sys_mmap(8) as *i64 195 let lf2: *i64 = sys_mmap(8) as *i64 196 let ll2: *i64 = sys_mmap(8) as *i64 197 xf_silu_train(tape,vals,grads,st, 6000, 1024, wbox2, lf2, ll2) 198 var bitexact: i64 = 1 199 if wbox2[0] != wbox[0] { bitexact = 0 } 200 pass = pass + g_check("C: bit-exact -- training twice gives IDENTICAL integer w (determinism)" as *u8, bitexact); total=total+1 201 202 // ---- emit ---- 203 var okall: i64 = 0 204 if pass == total { okall = 1 } 205 x_ws(1, "NOFLOATXFORMER authored=organ ops=softmax,silu,rmsnorm" as *u8) 206 x_ws(1, " | A1_softmax=" as *u8); x_wn(1, sm_ok); x_ws(1, " A2_silu=" as *u8); x_wn(1, si_ok); x_ws(1, " A3_rmsnorm=" as *u8); x_wn(1, rn_ok) 207 x_ws(1, " | D_teeth=" as *u8); x_wn(1, caught); x_ws(1, " | B_learns=" as *u8); x_wn(1, learns); x_ws(1, " w_milli=" as *u8); x_wn(1, q_milli(wbox[0])) 208 x_ws(1, " | C_bitexact=" as *u8); x_wn(1, bitexact); x_ws(1, "\n" as *u8) 209 let logf: i64 = sys_openat_append(XLOG, 420) 210 if logf >= 0 { 211 x_ws(logf, "NOFLOATXFORMER ops=softmax,silu,rmsnorm A1=" as *u8); x_wn(logf, sm_ok); x_ws(logf, " A2=" as *u8); x_wn(logf, si_ok) 212 x_ws(logf, " A3=" as *u8); x_wn(logf, rn_ok); x_ws(logf, " D=" as *u8); x_wn(logf, caught); x_ws(logf, " B=" as *u8); x_wn(logf, learns) 213 x_ws(logf, " C=" as *u8); x_wn(logf, bitexact) 214 if okall==1 { x_ws(logf, " verdict=GREEN\n" as *u8) } else { x_ws(logf, " verdict=RED\n" as *u8) } 215 sys_close(logf) 216 } 217 218 g_puts("---- nofloat_xformer gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8) 219 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 220 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 221 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 222 let ctr__dry: *i64 = gv_ctr() 223 ctr__dry[0] = pass 224 ctr__dry[1] = total 225 let rc__dry: i64 = gv_verdict("NOFLOAT-XFORMER-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 226 sys_exit(rc__dry) 227 return rc__dry 228}