nx_conv_bwd_stride_gate.nx source
↩ module page · 46 lines · 2891 B
1// nx_conv_bwd_stride_gate.nx -- EXACT check of nx_f32_conv2d_backward at STRIDE 2 (only stride-1 was gated before;
2// the student-distill collapse pointed here). 4x4 input=[1..16], 2x2 weight, stride 2 pad 0 -> 2x2 out; dOut=all-1
3// -> dW[kh,kw] = sum over the 2x2 output of in(oh*2+kh, ow*2+kw): dW=[24,28,40,44] (hand-computed). expect_exit: 0
4import "nx_syscalls.nx"
5import "nx_f32_cvt.nx"
6import "nx_f32_conv2d.nx"
7import "nx_f32_conv2d_backward.nx"
8
9func gp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return sys_write(1,s,n) }
10func gn(v: i64) -> i64 { let bb:*u8=sys_mmap(28); var m:i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m} let t:*u8=sys_mmap(28); var k:i64=0; if m==0{t[0]=48 as u8;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{bb[i]=t[k-1-i];i=i+1} return sys_write(1,bb,k) }
11
12func main(argc: i64, argv: *i64) -> i64 {
13 var pass: i64 = 0
14 let input: *i64=sys_mmap(8*16) as *i64
15 let W: *i64=sys_mmap(8*4) as *i64
16 let dout: *i64=sys_mmap(8*4) as *i64
17 let dinput: *i64=sys_mmap(8*16) as *i64
18 let dW: *i64=sys_mmap(8*4) as *i64
19 let dB: *i64=sys_mmap(8) as *i64
20 var i: i64=0; while i<16 { input[i]=nx_i32_to_f32(i+1); i=i+1 }
21 W[0]=nx_i32_to_f32(1); W[1]=nx_i32_to_f32(1); W[2]=nx_i32_to_f32(1); W[3]=nx_i32_to_f32(1)
22 i=0; while i<4 { dout[i]=nx_i32_to_f32(1); i=i+1 }
23
24 // stride 2, pad 0: OH=OW=2
25 let rc: i64=nx_f32_conv2d_backward(input,1,1,4,4, W,1,2,2, 2,0, dout, dinput, dW, dB)
26 // S1 dW = [24,28,40,44]
27 if dW[0]==nx_i32_to_f32(24) { if dW[1]==nx_i32_to_f32(28) { if dW[2]==nx_i32_to_f32(40) { if dW[3]==nx_i32_to_f32(44) {
28 pass=pass+1; gp("S1 stride-2 dW=[24,28,40,44] exact OK\n" as *u8)
29 } } } }
30 if dW[0]!=nx_i32_to_f32(24) { gp("S1 FAIL dW=[" as *u8); gn(dW[0]); gp("," as *u8); gn(dW[1]); gp("," as *u8); gn(dW[2]); gp("," as *u8); gn(dW[3]); gp("] want [24,28,40,44]\n" as *u8) }
31
32 // S2 dBias = 4 (OH*OW)
33 if dB[0]==nx_i32_to_f32(4) { pass=pass+1; gp("S2 stride-2 dBias=4 OK\n" as *u8) }
34 if dB[0]!=nx_i32_to_f32(4) { gp("S2 FAIL dB=" as *u8); gn(dB[0]); gp("\n" as *u8) }
35
36 // S3 dInput: with W=all-1 and dOut=all-1, each input cell that's covered gets +1. Stride 2 kernel 2 pad 0 on 4x4
37 // tiles EXACTLY (no overlap, no gap) -> EVERY input cell covered once -> dInput all = 1.
38 var allone: i64=1; i=0; while i<16 { if dinput[i]!=nx_i32_to_f32(1) { allone=0 } i=i+1 }
39 if allone==1 { pass=pass+1; gp("S3 stride-2 dInput all=1 (exact tiling) OK\n" as *u8) }
40 if allone==0 { gp("S3 FAIL dInput[0]=" as *u8); gn(dinput[0]); gp(" dinput[5]=" as *u8); gn(dinput[5]); gp("\n" as *u8) }
41
42 gp("CONV-BWD-STRIDE-GATE pass=" as *u8); gn(pass); gp("/3 rc=" as *u8); gn(rc); gp("\n" as *u8)
43 if pass==3 { gp("CONV-BWD-STRIDE-GATE verdict=GREEN 3/3 (strided backward is correct)\n" as *u8); sys_exit(0) }
44 sys_exit(1)
45 return 0
46}