code wiki / _hdl_build / nx_nofloat_xformer_gate.nx
nx_nofloat_xformer_gate.nx source
↩ module page · 220 lines · 12226 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"
22
23const XLOG: *u8 = "knowledge/status/nofloat_xformer.log"
24const Q16: i64 = 65536
25const OP_SOFTMAX: i64 = 5
26const OP_SILU: i64 = 6
27const OP_RMSNORM: i64 = 7
28
29func g_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v }
30func 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 }
31func 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 }
32func x_wn(fd: i64, v: i64) -> i64 {
33 let b: *u8 = sys_mmap(28); var m: i64=v; if m<0 { sys_write(fd,"-" as *u8,1); m=0-m }
34 let t: *u8 = sys_mmap(28); var k: i64=0; if m==0 { t[0]=48; k=1 }
35 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
36 var i: i64=0; while i<k { b[i]=t[k-1-i]; i=i+1 } sys_write(fd,b,k); return 0
37}
38
39// ---- build loss = mse(OP(x), target) on the general tape; leaves[0] = the x leaf. ----
40func xf_loss(tape: *i64, vals: *i64, st: *i64, op_sel: i64, xs: *i64, ts: *i64, n: i64, leaves: *i64) -> i64 {
41 st[0]=0; st[1]=0
42 let nx: i64 = nfa_leaf(tape,vals,st,n,1,xs,0)
43 var nop: i64 = nx
44 if op_sel == OP_SOFTMAX { nop = nfa_softmax(tape,vals,st,nx) }
45 if op_sel == OP_SILU { nop = nfa_silu(tape,vals,st,nx) }
46 if op_sel == OP_RMSNORM { nop = nfa_rmsnorm(tape,vals,st,nx) }
47 let nt: i64 = nfa_leaf(tape,vals,st,n,1,ts,0)
48 let loss: i64 = nfa_mse(tape,vals,st,nop,nt)
49 leaves[0]=nx
50 return loss
51}
52func xf_lossval(tape: *i64, vals: *i64, st: *i64, op_sel: i64, xs: *i64, ts: *i64, n: i64) -> i64 {
53 let lv: *i64 = sys_mmap(8) as *i64
54 let loss: i64 = xf_loss(tape,vals,st,op_sel,xs,ts,n,lv)
55 return nfa_val(tape,vals,loss,0)
56}
57// central finite diff of the loss wrt x[pi], Q16 step h
58func xf_fd(tape: *i64, vals: *i64, st: *i64, op_sel: i64, xs: *i64, ts: *i64, n: i64, pi: i64, h: i64) -> i64 {
59 let xp: *i64 = sys_mmap(n*8) as *i64
60 let xm: *i64 = sys_mmap(n*8) as *i64
61 var i: i64 = 0
62 while i < n { xp[i]=xs[i]; xm[i]=xs[i]; i=i+1 }
63 xp[pi]=xs[pi]+h; xm[pi]=xs[pi]-h
64 let lp: i64 = xf_lossval(tape,vals,st,op_sel,xp,ts,n)
65 let lm: i64 = xf_lossval(tape,vals,st,op_sel,xm,ts,n)
66 return ((lp - lm) * Q16) / (2 * h)
67}
68// gradcheck one op over all n inputs; sets worst[0]=worst relative-error milli; returns 1 if all within tol.
69func 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 {
70 let lv: *i64 = sys_mmap(8) as *i64
71 let loss: i64 = xf_loss(tape,vals,st,op_sel,xs,ts,n,lv)
72 nfa_backward(tape,vals,grads,st[0],loss)
73 let nx: i64 = lv[0]
74 var ok: i64 = 1; worst[0]=0
75 var i: i64 = 0
76 while i < n {
77 let ana: i64 = nfa_grad(tape,grads,nx,i)
78 let fd: i64 = xf_fd(tape,vals,st,op_sel,xs,ts,n,i,h)
79 let num: i64 = g_abs(fd - ana)
80 var den: i64 = g_abs(ana); if den < floor_q { den = floor_q }
81 let thresh: i64 = (tol_q * den) >> 16
82 if num >= thresh { ok = 0 }
83 let rel: i64 = (num * 1000) / den
84 if rel > worst[0] { worst[0] = rel }
85 i = i + 1
86 }
87 return ok
88}
89
90// ---- Gate B/C: train w to fit y = silu(w*.x) (realizable, w*=1.5 Q16) via tape + silu backward ----
91func xf_silu_build(tape: *i64, vals: *i64, st: *i64, wp: *i64, X: *i64, Y: *i64, T: i64, outW: *i64) -> i64 {
92 st[0]=0; st[1]=0
93 let nw: i64 = nfa_leaf(tape,vals,st,1,1,wp,0)
94 outW[0]=nw
95 var root: i64 = 0 - 1
96 var t: i64 = 0
97 while t < T {
98 let nx: i64 = nfa_leaf(tape,vals,st,1,1,X,t)
99 let h: i64 = nfa_matvec(tape,vals,st,nw,nx) // w*x
100 let s: i64 = nfa_silu(tape,vals,st,h) // silu(w*x)
101 let ny: i64 = nfa_leaf(tape,vals,st,1,1,Y,t)
102 let nm: i64 = nfa_mse(tape,vals,st,s,ny)
103 if root < 0 { root = nm } else { root = nfa_vadd(tape,vals,st,root,nm) }
104 t = t + 1
105 }
106 return root
107}
108func xf_silu_train(tape: *i64, vals: *i64, grads: *i64, st: *i64, epochs: i64, lr_q: i64, wout: *i64, lf: *i64, ll: *i64) -> i64 {
109 let T: i64 = 4
110 let Wt: i64 = 98304 // w* = 1.5 Q16
111 let X: *i64 = sys_mmap(T*8) as *i64
112 X[0]=32768; X[1]=65536; X[2]=98304; X[3]=131072 // x = 0.5,1.0,1.5,2.0
113 let Y: *i64 = sys_mmap(T*8) as *i64
114 var t: i64 = 0
115 while t < T { Y[t] = nfa_siluf((Wt * X[t]) >> 16); t = t + 1 } // realizable targets via the lib's silu
116 let wp: *i64 = sys_mmap(8) as *i64; wp[0]=0 // learn from ZERO
117 let outW: *i64 = sys_mmap(8) as *i64
118 let g: *i64 = sys_mmap(8) as *i64
119 var ep: i64 = 0
120 while ep < epochs {
121 let root: i64 = xf_silu_build(tape,vals,st,wp,X,Y,T,outW)
122 nfa_backward(tape,vals,grads,st[0],root)
123 if ep == 0 { *lf = nfa_val(tape,vals,root,0) }
124 *ll = nfa_val(tape,vals,root,0)
125 g[0] = nfa_grad(tape,grads,outW[0],0)
126 nfa_sgd(wp, g, 1, lr_q)
127 ep = ep + 1
128 }
129 wout[0]=wp[0]
130 return 0
131}
132
133func main() -> i64 {
134 g_puts("nx_nofloat_xformer gate (backprop through softmax/silu/rmsnorm in PURE INTEGER Q16 -- MEASURED)\n" as *u8)
135 var pass: i64 = 0; var total: i64 = 0
136 let tape: *i64 = sys_mmap(512*7*8) as *i64
137 let vals: *i64 = sys_mmap(4096*8) as *i64
138 let grads: *i64 = sys_mmap(4096*8) as *i64
139 let st: *i64 = sys_mmap(2*8) as *i64
140 let n: i64 = 4
141 let h: i64 = 512
142 let floor_q: i64 = 4096
143 let worst: *i64 = sys_mmap(8) as *i64
144
145 // ---- A1: softmax gradcheck ----
146 let xs1: *i64 = sys_mmap(n*8) as *i64; xs1[0]=32768; xs1[1]=0-16384; xs1[2]=49152; xs1[3]=0
147 let ts1: *i64 = sys_mmap(n*8) as *i64; ts1[0]=26214; ts1[1]=6554; ts1[2]=26214; ts1[3]=6554
148 let sm_ok: i64 = xf_gradcheck(tape,vals,grads,st,OP_SOFTMAX,xs1,ts1,n,h,4096,floor_q,worst) // tol 1/16
149 g_puts(" [measure] softmax worst rel grad err = " as *u8); g_pn(worst[0]); g_puts(" /1000 (tol=62/1000)\n" as *u8)
150 pass = pass + g_check("A1: softmax gradcheck -- tape Jacobian-vector backward == finite differences" as *u8, sm_ok); total=total+1
151
152 // ---- A2: silu gradcheck ----
153 let xs2: *i64 = sys_mmap(n*8) as *i64; xs2[0]=32768; xs2[1]=0-32768; xs2[2]=65536; xs2[3]=0-65536
154 let ts2: *i64 = sys_mmap(n*8) as *i64; ts2[0]=19661; ts2[1]=0-13107; ts2[2]=52429; ts2[3]=0-17695
155 let si_ok: i64 = xf_gradcheck(tape,vals,grads,st,OP_SILU,xs2,ts2,n,h,4096,floor_q,worst) // tol 1/16
156 g_puts(" [measure] silu worst rel grad err = " as *u8); g_pn(worst[0]); g_puts(" /1000 (tol=62/1000)\n" as *u8)
157 pass = pass + g_check("A2: silu gradcheck -- tape x*sigmoid(x) backward == finite differences" as *u8, si_ok); total=total+1
158
159 // ---- A3: rmsnorm gradcheck (normalization Jacobian; fixed-point isqrt/div -> looser honest tol) ----
160 let xs3: *i64 = sys_mmap(n*8) as *i64; xs3[0]=32768; xs3[1]=65536; xs3[2]=0-32768; xs3[3]=16384
161 let ts3: *i64 = sys_mmap(n*8) as *i64; ts3[0]=13107; ts3[1]=58982; ts3[2]=0-39322; ts3[3]=6554
162 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)
163 g_puts(" [measure] rmsnorm worst rel grad err = " as *u8); g_pn(worst[0]); g_puts(" /1000 (tol=62/1000)\n" as *u8)
164 pass = pass + g_check("A3: rmsnorm gradcheck -- tape normalization-Jacobian backward == finite differences" as *u8, rn_ok); total=total+1
165
166 // ---- D: neg-control (teeth) on silu ----
167 let lv: *i64 = sys_mmap(8) as *i64
168 let loss: i64 = xf_loss(tape,vals,st,OP_SILU,xs2,ts2,n,lv)
169 nfa_backward(tape,vals,grads,st[0],loss)
170 let ana0: i64 = nfa_grad(tape,grads,lv[0],0)
171 let fd0: i64 = xf_fd(tape,vals,st,OP_SILU,xs2,ts2,n,0,h)
172 let bad: i64 = 0 - ana0
173 var den0: i64 = g_abs(ana0); if den0 < floor_q { den0 = floor_q }
174 let thr0: i64 = (4096 * den0) >> 16
175 var caught: i64 = 1
176 if g_abs(fd0 - bad) < thr0 { caught = 0 }
177 pass = pass + g_check("D: neg-control -- a deliberately WRONG grad is rejected by the gradcheck (teeth)" as *u8, caught); total=total+1
178
179 // ---- B: a transformer activation TRAINS (silu regression, realizable) ----
180 let wbox: *i64 = sys_mmap(8) as *i64
181 let lf: *i64 = sys_mmap(8) as *i64
182 let ll: *i64 = sys_mmap(8) as *i64
183 xf_silu_train(tape,vals,grads,st, 6000, 1024, wbox, lf, ll)
184 g_puts(" [measure] silu-regression loss: start=" as *u8); g_pn(*lf); g_puts(" end=" as *u8); g_pn(*ll)
185 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)
186 var learns: i64 = 1
187 if (*ll) * 10 > (*lf) { learns = 0 } // >= 90% loss reduction
188 if g_abs(wbox[0] - 98304) > 9830 { learns = 0 } // within 15% of w*
189 if (*lf) <= 0 { learns = 0 }
190 pass = pass + g_check("B: a transformer activation LEARNS in pure integer -- silu regression converges to w*" as *u8, learns); total=total+1
191
192 // ---- C: bit-exact reproducible ----
193 let wbox2: *i64 = sys_mmap(8) as *i64
194 let lf2: *i64 = sys_mmap(8) as *i64
195 let ll2: *i64 = sys_mmap(8) as *i64
196 xf_silu_train(tape,vals,grads,st, 6000, 1024, wbox2, lf2, ll2)
197 var bitexact: i64 = 1
198 if wbox2[0] != wbox[0] { bitexact = 0 }
199 pass = pass + g_check("C: bit-exact -- training twice gives IDENTICAL integer w (determinism)" as *u8, bitexact); total=total+1
200
201 // ---- emit ----
202 var okall: i64 = 0
203 if pass == total { okall = 1 }
204 x_ws(1, "NOFLOATXFORMER authored=organ ops=softmax,silu,rmsnorm" as *u8)
205 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)
206 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]))
207 x_ws(1, " | C_bitexact=" as *u8); x_wn(1, bitexact); x_ws(1, "\n" as *u8)
208 let logf: i64 = sys_openat_append(XLOG, 420)
209 if logf >= 0 {
210 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)
211 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)
212 x_ws(logf, " C=" as *u8); x_wn(logf, bitexact)
213 if okall==1 { x_ws(logf, " verdict=GREEN\n" as *u8) } else { x_ws(logf, " verdict=RED\n" as *u8) }
214 sys_close(logf)
215 }
216
217 g_puts("---- nofloat_xformer gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8)
218 if okall == 1 { g_puts("verdict=GREEN\n" as *u8); sys_exit(0); return 0 }
219 g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1
220}