code wiki / _hdl_build / nx_nn_train_gate.nx

nx_nn_train_gate.nx source

↩ module page · 52 lines · 3108 B

1// nx_nn_train_gate.nx -- proves sovereign fixed-point training (nx_nn_train): batch gradient descent on a linear layer, 2// starting from zero weights, learns a known target mapping -- the MSE loss collapses and the learned weights converge 3// to the target. This is the training pipeline the neural PLC / RVQ-codebook needs, all integer, no FPU/GPU/autograd. 4import "nx_syscalls.nx" 5import "nx_gate_emit_lib.nx" 6import "nx_nn_train.nx" 7import "nx_gate_verdict.nx" 8 9func g_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v } 10 11func main() -> i64 { 12 g_puts("nx_nn_train gate (sovereign fixed-point gradient descent learns a target, MEASURED)\n" as *u8) 13 var pass: i64 = 0; var total: i64 = 0 14 let I: i64 = 2; let O: i64 = 1; let T: i64 = 4; let Q: i64 = 16 // weights in Q16 so sub-unit GD steps accumulate 15 16 // target mapping W* = [1.0, -0.5] in Q16 17 let Wt: *i64 = sys_mmap(2*8) as *i64; Wt[0]=65536; Wt[1]=0-32768 18 // training inputs X[T x I] (Q8) and targets Y = (W* . X) >> Q 19 let X: *i64 = sys_mmap(T*I*8) as *i64 20 let Y: *i64 = sys_mmap(T*O*8) as *i64 21 X[0]=256; X[1]=256; X[2]=512; X[3]=128; X[4]=128; X[5]=512; X[6]=384; X[7]=256 22 var t: i64 = 0 23 while t < T { let acc: i64 = Wt[0]*X[t*I] + Wt[1]*X[t*I+1]; Y[t] = acc >> Q; t = t + 1 } 24 25 // learn from ZERO weights 26 let W: *i64 = sys_mmap(2*8) as *i64; W[0]=0; W[1]=0 27 let grad: *i64 = sys_mmap(O*I*8) as *i64 28 let pred: *i64 = sys_mmap(O*8) as *i64 29 30 let loss0: i64 = nnt_loss(X, Y, T, W, I, O, Q) 31 var it: i64 = 0 32 while it < 15000 { nnt_step(X, Y, T, W, I, O, Q, 13, grad, pred); it = it + 1 } // update_shift 13 = the learning rate 33 let lossN: i64 = nnt_loss(X, Y, T, W, I, O, Q) 34 35 g_puts(" [measure] loss: start=" as *u8); g_pn(loss0); g_puts(" after 15000 GD steps=" as *u8); g_pn(lossN) 36 g_puts(" learned W=[" as *u8); g_pn(W[0]); g_puts("," as *u8); g_pn(W[1]); g_puts("] vs target [65536,-32768] (Q16; exact convergence is fixed-point-floor-limited)\n" as *u8) 37 38 pass = pass + g_check("training collapses the loss (>= 95% reduction = it learned the mapping)" as *u8, lossN * 20 <= loss0); total=total+1 39 pass = pass + g_check("weights converge substantially toward target with correct sign (>= 60% of the way)" as *u8, (W[0] >= 39322) & (W[1] <= 0-19661)); total=total+1 40 pass = pass + g_check("started genuinely untrained (start loss > 0)" as *u8, loss0 > 0); total=total+1 41 42 g_puts("---- nn_train gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8) 43 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 44 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 45 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 46 let ctr__dry: *i64 = gv_ctr() 47 ctr__dry[0] = pass 48 ctr__dry[1] = total 49 let rc__dry: i64 = gv_verdict("NN-TRAIN-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 50 sys_exit(rc__dry) 51 return rc__dry 52}