code wiki / (root) / nx_nn_train.nx

nx_nn_train.nx source

↩ module page · 55 lines · 2563 B

1// nx_nn_train.nx -- sovereign FIXED-POINT TRAINING (batch gradient descent), the final piece of the neural-audio 2// moonshot machinery. Together with nx_nn (the forward pass) this makes a net LEARNABLE entirely in integer arithmetic: 3// no FPU, no GPU, no third-party autograd -- so a learned PLC / RVQ-codebook predictor can be trained sovereignly on 4// affordable hardware. MSE loss, analytic gradient of a linear layer (dL/dW = (pred - target) . input), Q-scale step. 5// lr_shift sets the learning rate (bigger = smaller, more stable steps). Composes the same matmul as nx_nn. license_tier: ORIGINAL 6 7// one BATCH GD step on a linear layer W[O x I] over T samples X[T x I], targets Y[T x O]. Q-scale fixed-point. 8// Qshift = the pred descale (W's Q-scale plus X's, e.g. W in Q16 . X in Q8 -> pred = acc>>16, so Qshift here would be 9// X's Q... actually pred = (W.X)>>Qshift where Qshift = W's fractional bits). update_shift = the learning rate (W -= 10// grad>>update_shift, applied in W's OWN Q-scale). Keeping W in high precision (Q16) lets the sub-unit GD steps 11// ACCUMULATE -- the fix for the fixed-point "step rounds to 0" trap. grad[O*I] + pred[O] are caller scratch. 12func nnt_step(X: *i64, Y: *i64, T: i64, W: *i64, I: i64, O: i64, Qshift: i64, update_shift: i64, grad: *i64, pred: *i64) -> i64 { 13 var g: i64 = 0 14 while g < O*I { grad[g] = 0; g = g + 1 } 15 var t: i64 = 0 16 while t < T { 17 var o: i64 = 0 18 while o < O { 19 var acc: i64 = 0 20 var i: i64 = 0 21 while i < I { acc = acc + W[o*I + i] * X[t*I + i]; i = i + 1 } 22 pred[o] = acc >> Qshift 23 o = o + 1 24 } 25 o = 0 26 while o < O { 27 let err: i64 = pred[o] - Y[t*O + o] 28 var i: i64 = 0 29 while i < I { grad[o*I + i] = grad[o*I + i] + err * X[t*I + i]; i = i + 1 } 30 o = o + 1 31 } 32 t = t + 1 33 } 34 var k: i64 = 0 35 while k < O*I { W[k] = W[k] - (grad[k] >> update_shift); k = k + 1 } 36 return 0 37} 38// total MSE loss (sum of squared errors) of the linear layer over the T samples 39func nnt_loss(X: *i64, Y: *i64, T: i64, W: *i64, I: i64, O: i64, Qshift: i64) -> i64 { 40 var s: i64 = 0 41 var t: i64 = 0 42 while t < T { 43 var o: i64 = 0 44 while o < O { 45 var acc: i64 = 0 46 var i: i64 = 0 47 while i < I { acc = acc + W[o*I + i] * X[t*I + i]; i = i + 1 } 48 let e: i64 = (acc >> Qshift) - Y[t*O + o] 49 s = s + e*e 50 o = o + 1 51 } 52 t = t + 1 53 } 54 return s 55}