code wiki / _hdl_build / _autograd_authored.nx

_autograd_authored.nx source

↩ module page · 195 lines · 8516 B

1// AUTHORED BY THE NISHI BUILDER (nx_module_author autograd template) -- L1 training substrate rung 1. 2// Tape reverse-mode autograd on the sovereign f32 tower; tutoring: specs/2026-06-09-tutoring-training-substrate-rung1.md 3import "nx_syscalls.nx" 4import "nx_f32.nx" 5import "nx_f32_div.nx" 6import "nx_f32_cvt.nx" 7func _ag_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 8func _ag_num(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)}; 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);m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(1,bb,k); return 0 } 9func ag_q(n: i64, d: i64) -> i64 { return nx_f32_div(nx_i32_to_f32(n), nx_i32_to_f32(d)) } 10func ag_milli(v: i64) -> i64 { 11 var neg: i64 = 0 12 var a: i64 = v 13 if nx_f32_lt(a, 0) == 1 { neg = 1; a = nx_f32_abs(a) } 14 let m: i64 = nx_f32_mul(a, nx_i32_to_f32(1000)) 15 var lo: i64 = 0 16 var hi: i64 = 16777216 17 while lo < hi { 18 let mid: i64 = (lo + hi + 1) / 2 19 if nx_f32_lt(m, nx_i32_to_f32(mid)) == 1 { hi = mid - 1 } else { lo = mid } 20 } 21 if neg == 1 { return 0 - lo } 22 return lo 23} 24func ag_node(tape: *i64, nb: *i64, op: i64, ai: i64, bi: i64, v: i64) -> i64 { 25 let r: i64 = nb[0] 26 tape[r*5+0] = op 27 tape[r*5+1] = ai 28 tape[r*5+2] = bi 29 tape[r*5+3] = v 30 tape[r*5+4] = 0 31 nb[0] = r + 1 32 return r 33} 34func ag_leaf(tape: *i64, nb: *i64, v: i64) -> i64 { return ag_node(tape, nb, 0, 0, 0, v) } 35func ag_add(tape: *i64, nb: *i64, x: i64, y: i64) -> i64 { return ag_node(tape, nb, 1, x, y, nx_f32_add(tape[x*5+3], tape[y*5+3])) } 36func ag_mul(tape: *i64, nb: *i64, x: i64, y: i64) -> i64 { return ag_node(tape, nb, 2, x, y, nx_f32_mul(tape[x*5+3], tape[y*5+3])) } 37func ag_sub(tape: *i64, nb: *i64, x: i64, y: i64) -> i64 { return ag_node(tape, nb, 3, x, y, nx_f32_sub(tape[x*5+3], tape[y*5+3])) } 38func ag_relu(tape: *i64, nb: *i64, x: i64) -> i64 { 39 var v: i64 = tape[x*5+3] 40 if nx_f32_lt(v, 0) == 1 { v = 0 } 41 return ag_node(tape, nb, 4, x, 0, v) 42} 43func ag_backward(tape: *i64, nt: i64, root: i64) -> i64 { 44 var i: i64 = 0 45 while i < nt { tape[i*5+4] = 0; i = i + 1 } 46 tape[root*5+4] = nx_i32_to_f32(1) 47 var r: i64 = nt - 1 48 while r >= 0 { 49 let op: i64 = tape[r*5+0] 50 let g: i64 = tape[r*5+4] 51 let ai: i64 = tape[r*5+1] 52 let bi: i64 = tape[r*5+2] 53 if op == 1 { 54 tape[ai*5+4] = nx_f32_add(tape[ai*5+4], g) 55 tape[bi*5+4] = nx_f32_add(tape[bi*5+4], g) 56 } 57 if op == 2 { 58 tape[ai*5+4] = nx_f32_add(tape[ai*5+4], nx_f32_mul(g, tape[bi*5+3])) 59 tape[bi*5+4] = nx_f32_add(tape[bi*5+4], nx_f32_mul(g, tape[ai*5+3])) 60 } 61 if op == 3 { 62 tape[ai*5+4] = nx_f32_add(tape[ai*5+4], g) 63 tape[bi*5+4] = nx_f32_add(tape[bi*5+4], nx_f32_neg(g)) 64 } 65 if op == 4 { 66 if nx_f32_gt(tape[ai*5+3], 0) == 1 { tape[ai*5+4] = nx_f32_add(tape[ai*5+4], g) } 67 } 68 r = r - 1 69 } 70 return 0 71} 72func gc_fwd(w1: i64, b1: i64, w2: i64, b2: i64, x: i64) -> i64 { 73 var a: i64 = nx_f32_add(nx_f32_mul(w1, x), b1) 74 if nx_f32_lt(a, 0) == 1 { a = 0 } 75 let y: i64 = nx_f32_add(nx_f32_mul(a, w2), b2) 76 return nx_f32_mul(y, y) 77} 78func gate_a(tape: *i64, nb: *i64) -> i64 { 79 let pv: *i64 = sys_mmap(64) as *i64 80 pv[0] = ag_q(2,3) 81 pv[1] = ag_q(1,4) 82 pv[2] = ag_q(3,2) 83 pv[3] = ag_q(1,4) 84 let xv: i64 = ag_q(3,4) 85 nb[0] = 0 86 let pix: *i64 = sys_mmap(64) as *i64 87 var k: i64 = 0 88 while k < 4 { pix[k] = ag_leaf(tape, nb, pv[k]); k = k + 1 } 89 let xn: i64 = ag_leaf(tape, nb, xv) 90 let a: i64 = ag_relu(tape, nb, ag_add(tape, nb, ag_mul(tape, nb, pix[0], xn), pix[1])) 91 let y: i64 = ag_add(tape, nb, ag_mul(tape, nb, a, pix[2]), pix[3]) 92 let loss: i64 = ag_mul(tape, nb, y, y) 93 ag_backward(tape, nb[0], loss) 94 let h: i64 = ag_q(1,128) 95 let wv: *i64 = sys_mmap(64) as *i64 96 var pass: i64 = 1 97 k = 0 98 while k < 4 { 99 var j: i64 = 0 100 while j < 4 { wv[j] = pv[j]; j = j + 1 } 101 wv[k] = nx_f32_add(pv[k], h) 102 let fp: i64 = gc_fwd(wv[0], wv[1], wv[2], wv[3], xv) 103 wv[k] = nx_f32_sub(pv[k], h) 104 let fm: i64 = gc_fwd(wv[0], wv[1], wv[2], wv[3], xv) 105 let fdif: i64 = nx_f32_div(nx_f32_sub(fp, fm), ag_q(1,64)) 106 let ga: i64 = tape[pix[k]*5+4] 107 var den: i64 = nx_f32_abs(fdif) 108 if nx_f32_lt(den, ag_q(1,64)) == 1 { den = ag_q(1,64) } 109 let rel: i64 = nx_f32_div(nx_f32_abs(nx_f32_sub(ga, fdif)), den) 110 _ag_puts(" gradcheck p" as *u8); _ag_num(k) 111 _ag_puts(" analytic-milli=" as *u8); _ag_num(ag_milli(ga)) 112 _ag_puts(" finite-diff-milli=" as *u8); _ag_num(ag_milli(fdif)) 113 _ag_puts(" rel-milli=" as *u8); _ag_num(ag_milli(rel)); _ag_puts("\n" as *u8) 114 if nx_f32_lt(rel, ag_q(1,32)) == 0 { pass = 0 } 115 k = k + 1 116 } 117 return pass 118} 119func ag_train(tape: *i64, nb: *i64, out: *i64) -> i64 { 120 let wt: i64 = ag_q(3,2) 121 let bt: i64 = nx_f32_neg(ag_q(1,2)) 122 let xc: *i64 = sys_mmap(128) as *i64 123 let yc: *i64 = sys_mmap(128) as *i64 124 var i: i64 = 0 125 while i < 8 { xc[i] = ag_q(i, 4); yc[i] = nx_f32_add(nx_f32_mul(wt, xc[i]), bt); i = i + 1 } 126 let lr: i64 = ag_q(1,20) 127 let inv8: i64 = ag_q(1,8) 128 var w: i64 = 0 129 var b: i64 = 0 130 var first: i64 = 0 131 var loss_v: i64 = 0 132 var ep: i64 = 0 133 while ep < 500 { 134 nb[0] = 0 135 let wl: i64 = ag_leaf(tape, nb, w) 136 let bl: i64 = ag_leaf(tape, nb, b) 137 var acc: i64 = ag_leaf(tape, nb, 0) 138 var k: i64 = 0 139 while k < 8 { 140 let xn: i64 = ag_leaf(tape, nb, xc[k]) 141 let yn: i64 = ag_leaf(tape, nb, yc[k]) 142 let e: i64 = ag_sub(tape, nb, ag_add(tape, nb, ag_mul(tape, nb, wl, xn), bl), yn) 143 acc = ag_add(tape, nb, acc, ag_mul(tape, nb, e, e)) 144 k = k + 1 145 } 146 let il: i64 = ag_leaf(tape, nb, inv8) 147 let loss: i64 = ag_mul(tape, nb, acc, il) 148 ag_backward(tape, nb[0], loss) 149 loss_v = tape[loss*5+3] 150 if ep == 0 { first = loss_v } 151 w = nx_f32_sub(w, nx_f32_mul(lr, tape[wl*5+4])) 152 b = nx_f32_sub(b, nx_f32_mul(lr, tape[bl*5+4])) 153 if ep % 100 == 0 { _ag_puts(" epoch=" as *u8); _ag_num(ep); _ag_puts(" loss-milli=" as *u8); _ag_num(ag_milli(loss_v)); _ag_puts("\n" as *u8) } 154 ep = ep + 1 155 } 156 out[0] = w 157 out[1] = b 158 out[2] = loss_v 159 out[3] = first 160 return 0 161} 162func main() -> i64 { 163 _ag_puts("=== BUILDER-AUTHORED AUTOGRAD: L1 training substrate rung 1 (sovereign f32, no randomness) ===\n" as *u8) 164 let tape: *i64 = sys_mmap(65536) as *i64 165 let nb: *i64 = sys_mmap(16) as *i64 166 let pa: i64 = gate_a(tape, nb) 167 if pa == 1 { _ag_puts(" GATE A gradcheck: PASS (analytic == finite difference on every param)\n" as *u8) } else { _ag_puts(" GATE A gradcheck: FAIL\n" as *u8) } 168 let o1: *i64 = sys_mmap(64) as *i64 169 let o2: *i64 = sys_mmap(64) as *i64 170 ag_train(tape, nb, o1) 171 _ag_puts(" run1: w-milli=" as *u8); _ag_num(ag_milli(o1[0])) 172 _ag_puts(" b-milli=" as *u8); _ag_num(ag_milli(o1[1])) 173 _ag_puts(" final-loss-milli=" as *u8); _ag_num(ag_milli(o1[2])) 174 _ag_puts(" first-loss-milli=" as *u8); _ag_num(ag_milli(o1[3])); _ag_puts("\n" as *u8) 175 var pb: i64 = 1 176 if nx_f32_lt(o1[2], ag_q(1,1000)) == 0 { pb = 0 } 177 if nx_f32_lt(nx_f32_abs(nx_f32_sub(o1[0], ag_q(3,2))), ag_q(1,16)) == 0 { pb = 0 } 178 if nx_f32_lt(nx_f32_abs(nx_f32_sub(o1[1], nx_f32_neg(ag_q(1,2)))), ag_q(1,16)) == 0 { pb = 0 } 179 if nx_f32_lt(o1[2], o1[3]) == 0 { pb = 0 } 180 if pb == 1 { _ag_puts(" GATE B learns: PASS (loss < 1/1000, params recovered, loss decreased)\n" as *u8) } else { _ag_puts(" GATE B learns: FAIL\n" as *u8) } 181 ag_train(tape, nb, o2) 182 var pc: i64 = 1 183 if o1[0] != o2[0] { pc = 0 } 184 if o1[1] != o2[1] { pc = 0 } 185 if o1[2] != o2[2] { pc = 0 } 186 if pc == 1 { _ag_puts(" GATE C bit-exact training: PASS (two from-scratch runs -> identical weight BITS; the EXCEED axis)\n" as *u8) } else { _ag_puts(" GATE C bit-exact training: FAIL\n" as *u8) } 187 if pa == 1 { if pb == 1 { if pc == 1 { 188 _ag_puts(" AUTOGRAD RUNG-1 GATE: PASS (the team can compute verified gradients and train, bit-exactly, bits-up)\n" as *u8) 189 sys_exit(0) 190 return 0 191 } } } 192 _ag_puts(" AUTOGRAD RUNG-1 GATE: FAIL\n" as *u8) 193 sys_exit(1) 194 return 1 195}