code wiki / (root) / nx_f32_conv2d_backward_gate.nx

nx_f32_conv2d_backward_gate.nx source

↩ module page · 78 lines · 4638 B

1// nx_f32_conv2d_backward_gate.nx -- EXACT gradient check of nx_f32_conv2d_backward. Integer-valued inputs/weights 2// make every gradient an exact small integer, so the analytic backward is checked BIT-EXACT (nx_i32_to_f32 canonical 3// f32, ==) with NO numerical tolerance -- a stronger proof than finite-difference. Toy conv: C_in=1 H=3 W=3 4// input=[1..9], C_out=1 KH=KW=2 stride=1 pad=0 (OH=OW=2), weight=[10,20,30,40]. 5// dOut=all-ones -> dW=[12,16,24,28], dBias=4, dIn(0,0)=10, dIn(1,1 center)=100 (verified by hand) 6// dOut=[1,2,3,4] -> dW[0,0]=37, dBias=10 (general dOut weighting) 7// stride=0 -> ERR_BAD_ARGS (guard) 8// expect_exit: 0 9import "nx_syscalls.nx" 10import "nx_f32_cvt.nx" 11import "nx_f32_conv2d_backward.nx" 12 13func gp(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return sys_write(1, s, n) } 14func gn(v: i64) -> i64 { 15 let bb: *u8 = sys_mmap(28); var m: i64 = v 16 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 17 let t: *u8 = sys_mmap(28); var k: i64 = 0 18 if m == 0 { t[0] = 48 as u8; k = 1 } 19 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 20 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 21 return sys_write(1, bb, k) 22} 23 24func main(argc: i64, argv: *i64) -> i64 { 25 var pass: i64 = 0 26 let input: *i64 = sys_mmap(8 * 16) as *i64 27 let weight: *i64 = sys_mmap(8 * 16) as *i64 28 let dout: *i64 = sys_mmap(8 * 16) as *i64 29 let dinput: *i64 = sys_mmap(8 * 16) as *i64 30 let dweight: *i64 = sys_mmap(8 * 16) as *i64 31 let dbias: *i64 = sys_mmap(8) as *i64 32 33 // input = 1..9 (row-major 3x3) 34 var i: i64 = 0; while i < 9 { input[i] = nx_i32_to_f32(i + 1); i = i + 1 } 35 // weight 2x2 = [10,20,30,40] 36 weight[0] = nx_i32_to_f32(10); weight[1] = nx_i32_to_f32(20) 37 weight[2] = nx_i32_to_f32(30); weight[3] = nx_i32_to_f32(40) 38 39 // ===== run 1: dOut = all ones ===== 40 i = 0; while i < 4 { dout[i] = nx_i32_to_f32(1); i = i + 1 } 41 var r1: i64 = nx_f32_conv2d_backward(input, 1, 1, 3, 3, weight, 1, 2, 2, 1, 0, dout, dinput, dweight, dbias) 42 43 // CB1 dWeight exact = [12,16,24,28] 44 if dweight[0] == nx_i32_to_f32(12) { if dweight[1] == nx_i32_to_f32(16) { if dweight[2] == nx_i32_to_f32(24) { if dweight[3] == nx_i32_to_f32(28) { 45 pass = pass + 1; gp("CB1 dWeight=[12,16,24,28] exact OK\n" as *u8) 46 } } } } 47 if dweight[0] != nx_i32_to_f32(12) { gp("CB1 FAIL dW0 bits=" as *u8); gn(dweight[0]); gp(" want=" as *u8); gn(nx_i32_to_f32(12)); gp("\n" as *u8) } 48 49 // CB2 dBias exact = 4 (OH*OW) 50 if dbias[0] == nx_i32_to_f32(4) { pass = pass + 1; gp("CB2 dBias=4 exact OK\n" as *u8) } 51 if dbias[0] != nx_i32_to_f32(4) { gp("CB2 FAIL dBias bits=" as *u8); gn(dbias[0]); gp("\n" as *u8) } 52 53 // CB3 dInput exact: corner (0,0)=10, center (1,1)=input idx 4 =100 54 if dinput[0] == nx_i32_to_f32(10) { if dinput[4] == nx_i32_to_f32(100) { 55 pass = pass + 1; gp("CB3 dInput corner=10, center=100 exact OK\n" as *u8) 56 } } 57 if dinput[4] != nx_i32_to_f32(100) { gp("CB3 FAIL dIn0=" as *u8); gn(dinput[0]); gp(" dIn4=" as *u8); gn(dinput[4]); gp(" want100=" as *u8); gn(nx_i32_to_f32(100)); gp("\n" as *u8) } 58 59 // ===== run 2: dOut = [1,2,3,4] (general weighting) ===== 60 dout[0] = nx_i32_to_f32(1); dout[1] = nx_i32_to_f32(2); dout[2] = nx_i32_to_f32(3); dout[3] = nx_i32_to_f32(4) 61 var r2: i64 = nx_f32_conv2d_backward(input, 1, 1, 3, 3, weight, 1, 2, 2, 1, 0, dout, dinput, dweight, dbias) 62 63 // CB4 dW[0,0] = 1*1+2*2+3*4+4*5 = 37 ; dBias = 1+2+3+4 = 10 64 if dweight[0] == nx_i32_to_f32(37) { if dbias[0] == nx_i32_to_f32(10) { 65 pass = pass + 1; gp("CB4 general dOut -> dW[0,0]=37, dBias=10 exact OK\n" as *u8) 66 } } 67 if dweight[0] != nx_i32_to_f32(37) { gp("CB4 FAIL dW0=" as *u8); gn(dweight[0]); gp(" want37=" as *u8); gn(nx_i32_to_f32(37)); gp("\n" as *u8) } 68 69 // CB5 guard: stride 0 -> ERR_BAD_ARGS (4). (r1,r2 should have been 0.) 70 var r3: i64 = nx_f32_conv2d_backward(input, 1, 1, 3, 3, weight, 1, 2, 2, 0, 0, dout, dinput, dweight, dbias) 71 if r1 == 0 { if r2 == 0 { if r3 == 4 { pass = pass + 1; gp("CB5 rc ok (fwd=0,0; stride0=ERR) OK\n" as *u8) } } } 72 if r3 != 4 { gp("CB5 FAIL r1=" as *u8); gn(r1); gp(" r2=" as *u8); gn(r2); gp(" r3=" as *u8); gn(r3); gp("\n" as *u8) } 73 74 gp("CONV-BWD-GATE pass=" as *u8); gn(pass); gp("/5\n" as *u8) 75 if pass == 5 { gp("CONV-BWD-GATE GREEN 5/5 (dWeight + dBias + dInput exact + general dOut + guard) -- conv is now trainable\n" as *u8); sys_exit(0) } 76 sys_exit(1) 77 return 0 78}