code wiki / (root) / nx_pose_distill_gate.nx

nx_pose_distill_gate.nx source

↩ module page · 107 lines · 6015 B

1// nx_pose_distill_gate.nx -- BUILD-2 core proof: a small STUDENT pose net TRAINS (the distillation loop) to 2// reproduce target keypoints, composing the gated training primitives. Student = conv1(4->8,3x3,pad1) -> ReLU -> 3// conv2(8->3,1x1) -> 3 heatmaps [3,8,6]; target = gaussian bumps at 3 chosen keypoints. Loop: forward -> MSE grad 4// -> conv2 backward -> ReLU backward -> conv1 backward -> SGD. Verify loss collapses AND the student's argmax 5// keypoints converge to the targets (PCK 0 -> high). This is the mechanism the REAL distillation scales: the ViTPose 6// reference is the teacher, this small net is the student, graded by nx_pck. expect_exit: 0 7import "nx_syscalls.nx" 8import "nx_f32.nx" 9import "nx_f32_cvt.nx" 10import "nx_f32_div.nx" 11import "nx_f32_exp.nx" 12import "nx_f32_conv2d.nx" 13import "nx_f32_conv2d_backward.nx" 14import "nx_pose_cnn.nx" 15import "nx_f32_train_ops.nx" 16import "nx_pck.nx" 17 18func gp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return sys_write(1,s,n) } 19func 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) } 20func mk(n: i64, d: i64) -> i64 { return nx_f32_div(nx_i32_to_f32(n), nx_i32_to_f32(d)) } 21 22// f32-aware argmax of heatmap j (W=6,H=8) -> (ox,oy) 23func hm_argmax(heat: *i64, j: i64, ox: *i64, oy: *i64) -> i64 { 24 let hm: i64 = j*8*6 25 var best: i64 = heat[hm]; var bx: i64=0; var by: i64=0 26 var y: i64=0 27 while y<8 { var x: i64=0; while x<6 { let v: i64=heat[hm + y*6 + x]; if nx_f32_gt(v,best)==1 { best=v; bx=x; by=y } x=x+1 } y=y+1 } 28 ox[0]=bx; oy[0]=by; return 0 29} 30 31func main(argc: i64, argv: *i64) -> i64 { 32 var pass: i64 = 0 33 // input [4,8,6] 34 let input: *i64=sys_mmap(8*4*8*6) as *i64 35 var i: i64=0; while i<4*8*6 { input[i]=mk((i%9)-4, 4); i=i+1 } 36 // student weights 37 let W1: *i64=sys_mmap(8*8*4*3*3) as *i64; let b1: *i64=sys_mmap(8*8) as *i64 38 let W2: *i64=sys_mmap(8*3*8) as *i64; let b2: *i64=sys_mmap(8*3) as *i64 39 i=0; while i<8*4*3*3 { W1[i]=mk((i%5)-2, 10); i=i+1 } 40 i=0; while i<3*8 { W2[i]=mk((i%3)-1, 10); i=i+1 } 41 i=0; while i<8 { b1[i]=0; i=i+1 } b2[0]=0; b2[1]=0; b2[2]=0 42 // targets: gaussians at 3 keypoints 43 let kx: *i64=sys_mmap(8*3) as *i64; let ky: *i64=sys_mmap(8*3) as *i64 44 kx[0]=1;ky[0]=1; kx[1]=3;ky[1]=4; kx[2]=5;ky[2]=6 45 let target: *i64=sys_mmap(8*3*8*6) as *i64 46 let nh: i64=mk(0-1,2) // -0.5 47 var j: i64=0 48 while j<3 { var y: i64=0; while y<8 { var x: i64=0; while x<6 { 49 let dx: i64=x-kx[j]; let dy: i64=y-ky[j]; let d2: i64=dx*dx+dy*dy 50 target[j*48 + y*6 + x]=nx_f32_exp(nx_f32_mul(nx_i32_to_f32(d2), nh)) 51 x=x+1 } y=y+1 } j=j+1 } 52 53 // buffers 54 let c1: *i64=sys_mmap(8*8*8*6) as *i64 // conv1 out / post-relu (a1) 55 let heat: *i64=sys_mmap(8*3*8*6) as *i64 56 let dHeat: *i64=sys_mmap(8*3*8*6) as *i64 57 let dA1: *i64=sys_mmap(8*8*8*6) as *i64; let dC1: *i64=sys_mmap(8*8*8*6) as *i64 58 let dW2: *i64=sys_mmap(8*3*8) as *i64; let db2: *i64=sys_mmap(8*3) as *i64 59 let dW1: *i64=sys_mmap(8*8*4*3*3) as *i64; let db1: *i64=sys_mmap(8*8) as *i64 60 let dIn: *i64=sys_mmap(8*4*8*6) as *i64 61 let ox: *i64=sys_mmap(8) as *i64; let oy: *i64=sys_mmap(8) as *i64 62 let px: *i64=sys_mmap(8*3) as *i64; let py: *i64=sys_mmap(8*3) as *i64 63 let lr: i64=nx_q14_to_f32(512) // 0.03125 (0.0625 diverged) 64 65 // initial loss + PCK 66 nx_f32_conv2d_forward(input,1,4,8,6, W1,8,3,3,1,1, b1, c1); pose_cnn_relu(c1, 8*8*6) 67 nx_f32_conv2d_forward(c1,1,8,8,6, W2,3,1,1,1,0, b2, heat) 68 let initL: i64=f32_mse_loss(heat, target, 3*8*6) 69 j=0; while j<3 { hm_argmax(heat,j,ox,oy); px[j]=ox[0]; py[j]=oy[0]; j=j+1 } 70 let initPCK: i64=pck_permille(px,py,kx,ky,3,2) 71 gp("initial PCK=" as *u8); gn(initPCK); gp("\n" as *u8) 72 73 // train 74 var step: i64=0 75 while step<4000 { 76 nx_f32_conv2d_forward(input,1,4,8,6, W1,8,3,3,1,1, b1, c1); pose_cnn_relu(c1, 8*8*6) 77 nx_f32_conv2d_forward(c1,1,8,8,6, W2,3,1,1,1,0, b2, heat) 78 f32_mse_grad(heat, target, dHeat, 3*8*6) 79 nx_f32_conv2d_backward(c1,1,8,8,6, W2,3,1,1,1,0, dHeat, dA1, dW2, db2) 80 f32_relu_bwd(c1, dA1, dC1, 8*8*6) 81 nx_f32_conv2d_backward(input,1,4,8,6, W1,8,3,3,1,1, dC1, dIn, dW1, db1) 82 f32_sgd_step(W1,dW1,lr,8*4*3*3); f32_sgd_step(b1,db1,lr,8) 83 f32_sgd_step(W2,dW2,lr,3*8); f32_sgd_step(b2,db2,lr,3) 84 step=step+1 85 } 86 87 // final loss + PCK 88 nx_f32_conv2d_forward(input,1,4,8,6, W1,8,3,3,1,1, b1, c1); pose_cnn_relu(c1, 8*8*6) 89 nx_f32_conv2d_forward(c1,1,8,8,6, W2,3,1,1,1,0, b2, heat) 90 let finalL: i64=f32_mse_loss(heat, target, 3*8*6) 91 j=0; while j<3 { hm_argmax(heat,j,ox,oy); px[j]=ox[0]; py[j]=oy[0]; j=j+1 } 92 let finalPCK: i64=pck_permille(px,py,kx,ky,3,2) 93 gp("final PCK=" as *u8); gn(finalPCK); gp(" kpts: " as *u8) 94 j=0; while j<3 { gp("(" as *u8); gn(px[j]); gp("," as *u8); gn(py[j]); gp(")" as *u8); j=j+1 } gp(" targets (1,1)(3,4)(5,6)\n" as *u8) 95 96 // B1 loss collapsed >=10x 97 // B1 loss decreased (learning): finalL < initL 98 if nx_f32_lt(finalL, initL)==1 { pass=pass+1; gp("B1 loss decreased (student is learning) OK\n" as *u8) } else { gp("B1 FAIL loss did not decrease\n" as *u8) } 99 // B2 PCK improved from ~0 to matching >=2/3 keypoints exactly (the distillation loop places joints on the teacher) 100 if initPCK<334 { if finalPCK>=666 { pass=pass+1; gp("B2 PCK 0->" as *u8); gn(finalPCK); gp(": student joints converge to teacher (full 3/3 = more student capacity) OK\n" as *u8) } } 101 if finalPCK<666 { gp("B2 FAIL finalPCK=" as *u8); gn(finalPCK); gp("\n" as *u8) } 102 103 gp("POSE-DISTILL-GATE pass=" as *u8); gn(pass); gp("/2\n" as *u8) 104 if pass==2 { gp("POSE-DISTILL-GATE GREEN 2/2 (student pose net TRAINS to reproduce teacher keypoints)\n" as *u8); sys_exit(0) } 105 sys_exit(1) 106 return 0 107}