code wiki / _hdl_build / nx_nofloat_rope_gate.nx

nx_nofloat_rope_gate.nx source

↩ module page · 186 lines · 10286 B

1// nx_nofloat_rope_gate.nx -- HARD-EVIDENCE gate for RoPE (rotary position embedding) backward + RoPE composed 2// into the attention path. Advances CAP-NF-ATTN-FULL: with RoPE the attention is positionally-aware AND still 3// fully differentiable in pure integer Q16. RoPE is parameter-free (orthogonal rotation), so its backward is 4// the inverse rotation -- here proven correct by finite differences AND inside the full attention block. 5// 6// A1 RoPE gradcheck : loss=mse(RoPE(x), t); tape grad dL/dx == central finite difference. 7// A2 attention+RoPE gradcheck: X->{Q,K,V}; RoPE(Q),RoPE(K); S=QK^T; scale; causal softmax; O=A.V; mse; 8// gradcheck dL/dWq -- the gradient flowing through RoPE + softmax + both matmuls (the real RoPE-attn backward). 9// D neg-control teeth : a wrong RoPE grad is rejected. 10// C bit-exact : the attention+RoPE gradient is identical across two runs (determinism). 11// 12// Evidence -> knowledge/status/nofloat_rope.log. Sovereign: imports nx_nofloat_autograd (pure integer) + nx_syscalls. 13// HONEST scope: single-head; output-projection + multi-head/GQA remain (bookkeeping over matmul+vadd). expect_exit: 0 14import "nx_nofloat_autograd.nx" 15import "nx_syscalls.nx" 16import "nx_gate_emit_lib.nx" 17 18const RLOG: *u8 = "knowledge/status/nofloat_rope.log" 19const Q16: i64 = 65536 20 21 22func g_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } 23func r_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 } 24func r_wn(fd: i64, v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{sys_write(fd,"-" as *u8,1);m=0-m} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48;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(fd,b,k); return 0 } 25 26// ---- A1: RoPE gradcheck (loss = mse(RoPE(x), target)) ---- 27func rope_loss(tape: *i64, vals: *i64, st: *i64, Xs: *i64, T: i64, hd: i64, Ts: *i64, leaves: *i64) -> i64 { 28 st[0]=0; st[1]=0 29 let nX: i64 = nfa_leaf(tape,vals,st,T,hd,Xs,0) 30 let nR: i64 = nfa_rope(tape,vals,st,nX) 31 let nt: i64 = nfa_leaf(tape,vals,st,T,hd,Ts,0) 32 let loss: i64 = nfa_mse(tape,vals,st,nR,nt) 33 leaves[0]=nX 34 return loss 35} 36func rope_lossval(tape: *i64, vals: *i64, st: *i64, Xs: *i64, T: i64, hd: i64, Ts: *i64) -> i64 { 37 let lv: *i64 = sys_mmap(8) as *i64 38 let loss: i64 = rope_loss(tape,vals,st,Xs,T,hd,Ts,lv) 39 return nfa_val(tape,vals,loss,0) 40} 41 42// ---- A2: attention + RoPE forward (leaves[0..3]=nWq,nWk,nWv,nX) -> O node ---- 43func ar_fwd(tape: *i64, vals: *i64, st: *i64, Xs: *i64, Wqs: *i64, Wks: *i64, Wvs: *i64, T: i64, d: i64, scale: i64, leaves: *i64) -> i64 { 44 st[0]=0; st[1]=0 45 let nX: i64 = nfa_leaf(tape,vals,st,T,d,Xs,0) 46 let nWq: i64 = nfa_leaf(tape,vals,st,d,d,Wqs,0) 47 let nWk: i64 = nfa_leaf(tape,vals,st,d,d,Wks,0) 48 let nWv: i64 = nfa_leaf(tape,vals,st,d,d,Wvs,0) 49 let nQ: i64 = nfa_matmul(tape,vals,st,nX,nWq) 50 let nK: i64 = nfa_matmul(tape,vals,st,nX,nWk) 51 let nV: i64 = nfa_matmul(tape,vals,st,nX,nWv) 52 let nQr: i64 = nfa_rope(tape,vals,st,nQ) 53 let nKr: i64 = nfa_rope(tape,vals,st,nK) 54 let nS: i64 = nfa_matmul_nt(tape,vals,st,nQr,nKr) 55 let nSs: i64 = nfa_cmul(tape,vals,st,nS,scale) 56 let nA: i64 = nfa_softmax_rows(tape,vals,st,nSs,1) 57 let nO: i64 = nfa_matmul(tape,vals,st,nA,nV) 58 leaves[0]=nWq; leaves[1]=nWk; leaves[2]=nWv; leaves[3]=nX 59 return nO 60} 61func ar_loss(tape: *i64, vals: *i64, st: *i64, Xs: *i64, Wqs: *i64, Wks: *i64, Wvs: *i64, Ts: *i64, T: i64, d: i64, scale: i64, leaves: *i64) -> i64 { 62 let nO: i64 = ar_fwd(tape,vals,st,Xs,Wqs,Wks,Wvs,T,d,scale,leaves) 63 let nt: i64 = nfa_leaf(tape,vals,st,T,d,Ts,0) 64 return nfa_mse(tape,vals,st,nO,nt) 65} 66func ar_lossval(tape: *i64, vals: *i64, st: *i64, Xs: *i64, Wqs: *i64, Wks: *i64, Wvs: *i64, Ts: *i64, T: i64, d: i64, scale: i64) -> i64 { 67 let lv: *i64 = sys_mmap(4*8) as *i64 68 let loss: i64 = ar_loss(tape,vals,st,Xs,Wqs,Wks,Wvs,Ts,T,d,scale,lv) 69 return nfa_val(tape,vals,loss,0) 70} 71 72func main() -> i64 { 73 g_puts("nx_nofloat_rope gate (RoPE backward + RoPE-in-attention, PURE INTEGER Q16 -- MEASURED)\n" as *u8) 74 var pass: i64=0; var total: i64=0 75 let tape: *i64 = sys_mmap(512*7*8) as *i64 76 let vals: *i64 = sys_mmap(8192*8) as *i64 77 let grads: *i64 = sys_mmap(8192*8) as *i64 78 let st: *i64 = sys_mmap(2*8) as *i64 79 let h: i64 = 512 80 let floor_q: i64 = 4096 81 82 // ---- A1: RoPE gradcheck ---- 83 let T: i64 = 3; let hd: i64 = 2 84 let Xs: *i64 = sys_mmap(T*hd*8) as *i64; Xs[0]=32768; Xs[1]=49152; Xs[2]=0-16384; Xs[3]=65536; Xs[4]=24576; Xs[5]=0-40960 85 let Ts: *i64 = sys_mmap(T*hd*8) as *i64; Ts[0]=13107; Ts[1]=0-6554; Ts[2]=19661; Ts[3]=6554; Ts[4]=0-26214; Ts[5]=32768 86 let lv: *i64 = sys_mmap(8) as *i64 87 let loss1: i64 = rope_loss(tape,vals,st,Xs,T,hd,Ts,lv) 88 nfa_backward(tape,vals,grads,st[0],loss1) 89 let nX: i64 = lv[0] 90 var r1_ok: i64 = 1; var r1_worst: i64 = 0 91 var pi: i64 = 0 92 while pi < T*hd { 93 let ana: i64 = nfa_grad(tape,grads,nX,pi) 94 let xp: *i64 = sys_mmap(T*hd*8) as *i64 95 let xm: *i64 = sys_mmap(T*hd*8) as *i64 96 var z: i64=0 97 while z<T*hd { xp[z]=Xs[z]; xm[z]=Xs[z]; z=z+1 } 98 xp[pi]=Xs[pi]+h; xm[pi]=Xs[pi]-h 99 let lp: i64 = rope_lossval(tape,vals,st,xp,T,hd,Ts) 100 let lm: i64 = rope_lossval(tape,vals,st,xm,T,hd,Ts) 101 let fd: i64 = ((lp-lm)*Q16)/(2*h) 102 let num: i64 = g_abs(fd-ana) 103 var den: i64 = g_abs(ana); if den<floor_q { den=floor_q } 104 if num >= ((4096*den)>>16) { r1_ok=0 } // tol 1/16 105 let rel: i64 = (num*1000)/den 106 if rel>r1_worst { r1_worst=rel } 107 pi=pi+1 108 } 109 g_puts(" [measure] RoPE worst rel grad err = " as *u8); g_pn(r1_worst); g_puts(" /1000 (tol=62)\n" as *u8) 110 pass=pass+g_check("A1: RoPE gradcheck -- rotation backward (rotate by -angle) == finite differences" as *u8, r1_ok); total=total+1 111 112 // ---- A2: attention + RoPE gradcheck wrt Wq ---- 113 let d: i64 = 2; let scale: i64 = 46341 114 let aX: *i64 = sys_mmap(T*d*8) as *i64; aX[0]=32768; aX[1]=16384; aX[2]=0-16384; aX[3]=49152; aX[4]=65536; aX[5]=0-32768 115 let Wq: *i64 = sys_mmap(d*d*8) as *i64; Wq[0]=49152; Wq[1]=0-16384; Wq[2]=32768; Wq[3]=65536 116 let Wk: *i64 = sys_mmap(d*d*8) as *i64; Wk[0]=16384; Wk[1]=32768; Wk[2]=0-32768; Wk[3]=49152 117 let Wv: *i64 = sys_mmap(d*d*8) as *i64; Wv[0]=65536; Wv[1]=0-32768; Wv[2]=16384; Wv[3]=49152 118 let aT: *i64 = sys_mmap(T*d*8) as *i64; aT[0]=13107; aT[1]=0-6554; aT[2]=19661; aT[3]=6554; aT[4]=0-13107; aT[5]=26214 119 let lv2: *i64 = sys_mmap(4*8) as *i64 120 let loss2: i64 = ar_loss(tape,vals,st,aX,Wq,Wk,Wv,aT,T,d,scale,lv2) 121 nfa_backward(tape,vals,grads,st[0],loss2) 122 let nWq: i64 = lv2[0] 123 var r2_ok: i64 = 1; var r2_worst: i64 = 0 124 var qi: i64 = 0 125 while qi < d*d { 126 let ana: i64 = nfa_grad(tape,grads,nWq,qi) 127 let wqp: *i64 = sys_mmap(d*d*8) as *i64 128 let wqm: *i64 = sys_mmap(d*d*8) as *i64 129 var z: i64=0 130 while z<d*d { wqp[z]=Wq[z]; wqm[z]=Wq[z]; z=z+1 } 131 wqp[qi]=Wq[qi]+h; wqm[qi]=Wq[qi]-h 132 let lp: i64 = ar_lossval(tape,vals,st,aX,wqp,Wk,Wv,aT,T,d,scale) 133 let lm: i64 = ar_lossval(tape,vals,st,aX,wqm,Wk,Wv,aT,T,d,scale) 134 let fd: i64 = ((lp-lm)*Q16)/(2*h) 135 let num: i64 = g_abs(fd-ana) 136 var den: i64 = g_abs(ana); if den<floor_q { den=floor_q } 137 if num >= ((8192*den)>>16) { r2_ok=0 } // tol 1/8 (long chain through RoPE+softmax) 138 let rel: i64 = (num*1000)/den 139 if rel>r2_worst { r2_worst=rel } 140 qi=qi+1 141 } 142 g_puts(" [measure] attention+RoPE dL/dWq worst rel grad err = " as *u8); g_pn(r2_worst); g_puts(" /1000 (tol=125)\n" as *u8) 143 pass=pass+g_check("A2: attention+RoPE gradcheck -- dL/dWq through RoPE + causal-softmax + QK^T + A.V == finite diff" as *u8, r2_ok); total=total+1 144 145 // ---- D: neg-control teeth (RoPE) ---- 146 let lossd: i64 = rope_loss(tape,vals,st,Xs,T,hd,Ts,lv) 147 nfa_backward(tape,vals,grads,st[0],lossd) 148 let rana0: i64 = nfa_grad(tape,grads,lv[0],0) 149 let xp0: *i64 = sys_mmap(T*hd*8) as *i64 150 let xm0: *i64 = sys_mmap(T*hd*8) as *i64 151 var z0: i64=0 152 while z0<T*hd { xp0[z0]=Xs[z0]; xm0[z0]=Xs[z0]; z0=z0+1 } 153 xp0[0]=Xs[0]+h; xm0[0]=Xs[0]-h 154 let fdr0: i64 = ((rope_lossval(tape,vals,st,xp0,T,hd,Ts) - rope_lossval(tape,vals,st,xm0,T,hd,Ts))*Q16)/(2*h) 155 let bad: i64 = 0 - rana0 156 var rden0: i64 = g_abs(rana0); if rden0<floor_q { rden0=floor_q } 157 var caught: i64 = 1 158 if g_abs(fdr0-bad) < ((4096*rden0)>>16) { caught=0 } 159 pass=pass+g_check("D: neg-control -- a deliberately WRONG RoPE grad is rejected (teeth)" as *u8, caught); total=total+1 160 161 // ---- C: bit-exact (attention+RoPE gradient identical across two runs) ---- 162 let lvc: *i64 = sys_mmap(4*8) as *i64 163 let lossc: i64 = ar_loss(tape,vals,st,aX,Wq,Wk,Wv,aT,T,d,scale,lvc) 164 nfa_backward(tape,vals,grads,st[0],lossc) 165 let gA: i64 = nfa_grad(tape,grads,lvc[0],0); let gB: i64 = nfa_grad(tape,grads,lvc[0],1) 166 let lossc2: i64 = ar_loss(tape,vals,st,aX,Wq,Wk,Wv,aT,T,d,scale,lvc) 167 nfa_backward(tape,vals,grads,st[0],lossc2) 168 let gA2: i64 = nfa_grad(tape,grads,lvc[0],0); let gB2: i64 = nfa_grad(tape,grads,lvc[0],1) 169 var bitexact: i64 = 1 170 if gA2 != gA { bitexact=0 } 171 if gB2 != gB { bitexact=0 } 172 pass=pass+g_check("C: bit-exact -- attention+RoPE gradient identical across two runs (determinism)" as *u8, bitexact); total=total+1 173 174 // ---- emit ---- 175 var okall: i64=0; if pass==total { okall=1 } 176 let logf: i64 = sys_openat_append(RLOG, 420) 177 if logf >= 0 { 178 r_ws(logf,"NOFLOATROPE A1_rope=" as *u8); r_wn(logf,r1_ok); r_ws(logf," A2_attn_rope=" as *u8); r_wn(logf,r2_ok) 179 r_ws(logf," D=" as *u8); r_wn(logf,caught); r_ws(logf," C=" as *u8); r_wn(logf,bitexact) 180 if okall==1 { r_ws(logf," verdict=GREEN\n" as *u8) } else { r_ws(logf," verdict=RED\n" as *u8) } 181 sys_close(logf) 182 } 183 g_puts("---- nofloat_rope gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8) 184 if okall==1 { g_puts("verdict=GREEN\n" as *u8); sys_exit(0); return 0 } 185 g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1 186}