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}