code wiki / _hdl_build / nx_vcodec_neural_entropy_gate.nx

nx_vcodec_neural_entropy_gate.nx source

↩ module page · 300 lines · 15999 B

1import "nx_gate_base.nx" 2// nx_vcodec_neural_entropy_gate.nx -- THE NEURAL ENTROPY RUNG, measured. Trains a probability model on real 3// coefficient significance and measures its held-out CROSS-ENTROPY (bits) vs the hand-designed context 4// buckets the sig-map coder uses. The range coder already takes an arbitrary probability per bit, so a 5// trained model that predicts P(significant | context) is a drop-in -- this gate proves whether TRAINING 6// beats HAND-RULES (the core neural-codec thesis: learned entropy models beat engineered ones). If the 7// trained model has lower held-out cross-entropy, that fraction of the measured 37% sig-map prize is 8// REALIZABLE by a sovereign integer entropy model. Model: logistic regression p=sigmoid(w.x), analytical 9// BCE gradient (p-y)x, batch GD -- fast, provably trains. Features are causal (available to enc AND dec). 10// GREEN = trained < hand-context < order-0 on HELD-OUT data (learned beats engineered beats none). 11// license_tier: ORIGINAL 12import "nx_syscalls.nx" 13import "nx_dct8.nx" 14import "nx_vcodec.nx" 15import "nx_f32.nx" 16import "nx_f32_exp.nx" 17import "nx_f32_log.nx" 18import "nx_f32_div.nx" 19import "nx_f32_cvt.nx" 20 21const NW: i64 = 576 22const NH: i64 = 1024 23const NFEAT: i64 = 6 // bias, band, left-sig, up-sig, upleft-sig, neighbor-mag 24const MAXSAMP: i64 = 400000 // coefficient samples cap 25 26func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw(" 27" as *u8); return ok } 28func gn(v: i64) -> i64 { 29 let b: *u8=sys_mmap(28); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m} 30 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} 31 var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 } 32func g3(v: i64) -> i64 { gn(v/1000); gw("." as *u8); let f: i64=v%1000; if f<100 { gw("0" as *u8) } if f<10 { gw("0" as *u8) } gn(f); return 0 } 33 34// ---- f32 helpers (ops take/return raw i64 bit patterns) ---- 35let F_ZERO: i64 = 0 36func f_one() -> i64 { return nx_i32_to_f32(1) } 37func f_i(v: i64) -> i64 { return nx_i32_to_f32(v) } 38func f_frac(num: i64, den: i64) -> i64 { return nx_f32_div(nx_i32_to_f32(num), nx_i32_to_f32(den)) } 39// f32 -> i64 truncate toward zero (IEEE-754 decode) 40func f_to_i(raw: i64) -> i64 { 41 let sgn: i64 = (raw >> 31) & 1 42 let e: i64 = ((raw >> 23) & 0xff) - 127 43 if e < 0 { return 0 } 44 let mant: i64 = (raw & 0x7fffff) | 0x800000 45 var v: i64 = 0 46 if e >= 23 { let sh: i64 = e - 23; v = mant << sh } else { let sh2: i64 = 23 - e; v = mant >> sh2 } 47 if sgn == 1 { return 0 - v } 48 return v } 49// sigmoid(x) = 1/(1+exp(-x)) 50func f_sigmoid(x: i64) -> i64 { return nx_f32_div(f_one(), nx_f32_add(f_one(), nx_f32_exp(nx_f32_neg(x)))) } 51// -log2(p) in milli-bits (i64): -log(p)/log(2) * 1000 52func f_neglog2_milli(p: i64) -> i64 { 53 var pp: i64 = p 54 let tiny: i64 = f_frac(1, 100000) // clamp p away from 0 (avoid -inf) 55 if nx_f32_lt(pp, tiny) == (1 as nx_int) { pp = tiny } 56 let ln2: i64 = nx_f32_log(f_i(2)) 57 let nl: i64 = nx_f32_div(nx_f32_neg(nx_f32_log(pp)), ln2) // -log2(p) 58 return f_to_i(nx_f32_mul(nl, f_i(1000))) 59} 60 61// build coefficient samples: features (f32, NFEAT each) + label (0/1) from real frame-diff 8x8 DCT+quant. 62// returns sample count. feats[s*NFEAT+j], labels[s]. sig-map raster order (causal neighbors within block). 63func build_samples(yuv: *u8, f0: i64, f1: i64, qp: i64, M: *i64, scr: *i64, ti: *i64, to: *i64, 64 blk: *i64, sig: *i64, feats: *i64, labels: *i64) -> i64 { 65 let N: i64=NW*NH; let FB: i64=N+N/2 66 var ns: i64 = 0 67 var f: i64 = f0 68 while f <= f1 { 69 let cur: *u8 = ((yuv as i64) + f*FB) as *u8 70 let prv: *u8 = ((yuv as i64) + (f-1)*FB) as *u8 71 var by: i64 = 0 72 while by < NH/8 { var bx: i64 = 0 73 while bx < NW/8 { if ns + 64 <= MAXSAMP { 74 var yy: i64=0 75 while yy < 8 { var xx: i64=0 76 while xx < 8 { let p: i64=(by*8+yy)*NW+(bx*8+xx); blk[yy*8+xx]=(cur[p]&0xff)-(prv[p]&0xff); xx=xx+1 } yy=yy+1 } 77 nx_dct8_forward_2d(M, blk, blk, scr, ti, to) 78 vc_quant8(blk, qp) 79 var i: i64=0; while i<64 { if blk[i]!=0 { sig[i]=1 } else { sig[i]=0 } i=i+1 } 80 // raster scan; causal neighbors L(-1), U(-8), UL(-9) 81 var yb: i64=0 82 while yb < 8 { var xb: i64=0 83 while xb < 8 { 84 let pos: i64 = yb*8+xb 85 var ls: i64=0; var us: i64=0; var uls: i64=0; var lm: i64=0; var um: i64=0 86 if xb>0 { ls=sig[pos-1]; let lv: i64=blk[pos-1]; if lv<0 {lm=0-lv} else {lm=lv} } 87 if yb>0 { us=sig[pos-8]; let uv: i64=blk[pos-8]; if uv<0 {um=0-uv} else {um=uv} } 88 if xb>0 { if yb>0 { uls=sig[pos-9] } } 89 let base: i64 = ns*NFEAT 90 feats[base+0]=f_one() // bias 91 feats[base+1]=f_frac(pos, 63) // position band [0,1] 92 feats[base+2]=f_i(ls) 93 feats[base+3]=f_i(us) 94 feats[base+4]=f_i(uls) 95 var mm: i64 = lm+um; if mm>8 { mm=8 } // neighbor mag, clamped 96 feats[base+5]=f_frac(mm, 8) 97 labels[ns]=sig[pos] 98 ns=ns+1 99 xb=xb+1 } yb=yb+1 } 100 } bx=bx+1 } by=by+1 } 101 f=f+1 102 } 103 return ns } 104 105// held-out cross-entropy in milli-bits for the trained logistic model over samples [0,ns) 106func eval_model(w: *i64, feats: *i64, labels: *i64, ns: i64) -> i64 { 107 var bits: i64 = 0 108 var s: i64 = 0 109 while s < ns { 110 let base: i64 = s*NFEAT 111 var z: i64 = F_ZERO; var j: i64=0 112 while j < NFEAT { z = nx_f32_add(z, nx_f32_mul(w[j], feats[base+j])); j=j+1 } 113 let p: i64 = f_sigmoid(z) 114 if labels[s]==1 { bits = bits + f_neglog2_milli(p) } 115 else { bits = bits + f_neglog2_milli(nx_f32_sub(f_one(), p)) } 116 s=s+1 117 } 118 return bits } 119 120func main() -> i64 { 121 gw("=== nx_vcodec_neural_entropy_gate: TRAINED sig model vs hand-context (held-out cross-entropy) ===\n" as *u8) 122 let box: *i64 = sys_mmap(16) as *i64 123 let yuv: *u8 = sys_read_file("/mnt/c/Users/elder/nishi-core/nxc2/knowledge/staging/media/bframe_test_decoded.yuv" as *u8, box) 124 if (yuv as i64) == 0 { gw("cannot read yuv -> RED\n" as *u8); return 1 } 125 if box[0] < 12*(NW*NH+NW*NH/2) { gw("file too small -> RED\n" as *u8); return 1 } 126 let M: *i64 = sys_mmap(64*8) as *i64; nx_dct8_init(M) 127 let scr: *i64 = sys_mmap(64*8) as *i64; let ti: *i64 = sys_mmap(8*8) as *i64; let to: *i64 = sys_mmap(8*8) as *i64 128 let blk: *i64 = sys_mmap(64*8) as *i64; let sig: *i64 = sys_mmap(64*8) as *i64 129 let qp: i64 = 28 130 131 // TRAIN samples (frames 6..9) and TEST samples (10..11), separate arenas 132 let trF: *i64 = sys_mmap(MAXSAMP*NFEAT*8) as *i64; let trL: *i64 = sys_mmap(MAXSAMP*8) as *i64 133 let teF: *i64 = sys_mmap(MAXSAMP*NFEAT*8) as *i64; let teL: *i64 = sys_mmap(MAXSAMP*8) as *i64 134 let ntr: i64 = build_samples(yuv, 6, 9, qp, M, scr, ti, to, blk, sig, trF, trL) 135 let nte: i64 = build_samples(yuv, 10, 11, qp, M, scr, ti, to, blk, sig, teF, teL) 136 gw(" train samples=" as *u8); gn(ntr); gw(" test samples=" as *u8); gn(nte); gw("\n" as *u8) 137 138 // ---- TRAIN logistic regression: batch GD, analytical BCE gradient (p-y)*x ---- 139 // Init the BIAS to the base-rate logit ln(pos/neg) so training STARTS at order-0 calibration and can 140 // only improve (a diverging-from-zero start with high lr produced confidently-wrong predictions worse 141 // than no-context). Low lr = stable batch GD on 400k imbalanced samples. 142 let w: *i64 = sys_mmap(NFEAT*8) as *i64 143 let g: *i64 = sys_mmap(NFEAT*8) as *i64 144 var j: i64=0; while j<NFEAT { w[j]=F_ZERO; j=j+1 } 145 var bpos: i64=0; var s0: i64=0; while s0<ntr { if trL[s0]==1 { bpos=bpos+1 } s0=s0+1 } 146 let bneg: i64 = ntr - bpos 147 if bpos > 0 { if bneg > 0 { w[0] = nx_f32_log(f_frac(bpos, bneg)) } } // bias = logit(base rate) 148 let lr: i64 = f_frac(5, 100) // learning rate 0.05 149 let invn: i64 = nx_f32_div(f_one(), f_i(ntr)) 150 var ep: i64=0 151 while ep < 120 { 152 j=0; while j<NFEAT { g[j]=F_ZERO; j=j+1 } 153 var s: i64=0 154 while s < ntr { 155 let base: i64 = s*NFEAT 156 var z: i64=F_ZERO; j=0 157 while j<NFEAT { z=nx_f32_add(z, nx_f32_mul(w[j], trF[base+j])); j=j+1 } 158 let p: i64 = f_sigmoid(z) 159 let err: i64 = nx_f32_sub(p, f_i(trL[s])) // p - y 160 j=0; while j<NFEAT { g[j]=nx_f32_add(g[j], nx_f32_mul(err, trF[base+j])); j=j+1 } 161 s=s+1 162 } 163 j=0; while j<NFEAT { w[j]=nx_f32_sub(w[j], nx_f32_mul(lr, nx_f32_mul(g[j], invn))); j=j+1 } 164 ep=ep+1 165 } 166 167 // ---- HAND-CONTEXT model: empirical P(sig) per (band4 x neighborcount4) bucket, learned from TRAIN ---- 168 let hc1: *i64 = sys_mmap(16*8) as *i64 // count sig 169 let hc0: *i64 = sys_mmap(16*8) as *i64 // count total 170 var b: i64=0; while b<16 { hc1[b]=0; hc0[b]=0; b=b+1 } 171 // recompute bucket from features: band = round(feat1*3), nbcount = feat2+feat3+feat4 (0..3) 172 var s2: i64=0 173 while s2 < ntr { 174 let base: i64 = s2*NFEAT 175 let band: i64 = f_to_i(nx_f32_mul(trF[base+1], f_i(3))) // 0..3 176 let nb: i64 = f_to_i(trF[base+2]) + f_to_i(trF[base+3]) + f_to_i(trF[base+4]) // 0..3 177 var bk: i64 = band*4+nb; if bk<0 {bk=0} if bk>15 {bk=15} 178 hc0[bk]=hc0[bk]+1; if trL[s2]==1 { hc1[bk]=hc1[bk]+1 } 179 s2=s2+1 180 } 181 // order-0 global freq 182 var g1: i64=0; var g0: i64=0 183 s2=0; while s2<ntr { g0=g0+1; if trL[s2]==1 { g1=g1+1 } s2=s2+1 } 184 185 // ---- EVAL all three on HELD-OUT (milli-bits) ---- 186 let bTrained: i64 = eval_model(w, teF, teL, nte) 187 var bHand: i64=0; var bOrd0: i64=0 188 let ordp: i64 = f_frac(g1, g0) 189 var s3: i64=0 190 while s3 < nte { 191 let base: i64 = s3*NFEAT 192 let band: i64 = f_to_i(nx_f32_mul(teF[base+1], f_i(3))) 193 let nb: i64 = f_to_i(teF[base+2]) + f_to_i(teF[base+3]) + f_to_i(teF[base+4]) 194 var bk: i64 = band*4+nb; if bk<0 {bk=0} if bk>15 {bk=15} 195 var pb: i64 = f_frac(1,2); if hc0[bk]>0 { pb=f_frac(hc1[bk], hc0[bk]) } 196 if teL[s3]==1 { bHand=bHand+f_neglog2_milli(pb); bOrd0=bOrd0+f_neglog2_milli(ordp) } 197 else { bHand=bHand+f_neglog2_milli(nx_f32_sub(f_one(),pb)); bOrd0=bOrd0+f_neglog2_milli(nx_f32_sub(f_one(),ordp)) } 198 s3=s3+1 199 } 200 201 // ---- MLP (6 -> H ReLU -> 1 sigmoid): the NONLINEAR trained model -- the real test of whether a learned 202 // model can beat the hand-context BUCKETS (which are themselves a coarse nonlinear lookup). Batch GD, 203 // mixed-sign hidden-bias init (ReLU needs negative-bias units), lr 0.1 (the XOR-MLP recipe). Subsample 204 // train to 100k for speed; eval on the full held-out set. ---- 205 let H: i64 = 8 206 let W1: *i64 = sys_mmap(H*NFEAT*8) as *i64; let b1: *i64 = sys_mmap(H*8) as *i64 207 let W2: *i64 = sys_mmap(H*8) as *i64; let b2p: *i64 = sys_mmap(8) as *i64 208 let gW1: *i64 = sys_mmap(H*NFEAT*8) as *i64; let gb1: *i64 = sys_mmap(H*8) as *i64 209 let gW2: *i64 = sys_mmap(H*8) as *i64; let gb2: *i64 = sys_mmap(8) as *i64 210 let hpre: *i64 = sys_mmap(H*8) as *i64; let hact: *i64 = sys_mmap(H*8) as *i64 211 var k: i64=0 212 while k < H { 213 var i2: i64=0; while i2 < NFEAT { W1[k*NFEAT+i2] = f_frac(((k*7+i2*13)%11)-5, 40); i2=i2+1 } // small deterministic spread 214 b1[k] = f_frac((k%3)-1, 4) // mixed-sign hidden bias {-0.25,0,0.25} 215 W2[k] = f_frac((k%5)-2, 20) 216 k=k+1 217 } 218 b2p[0] = F_ZERO; if bpos>0 { if bneg>0 { b2p[0]=nx_f32_log(f_frac(bpos,bneg)) } } 219 let lrM: i64 = f_frac(1,10) 220 let sub: i64 = ntr/100000; var subS: i64 = sub; if subS<1 { subS=1 } 221 var nsub: i64 = 0; var cc: i64=0; while cc<ntr { nsub=nsub+1; cc=cc+subS } 222 let invM: i64 = nx_f32_div(f_one(), f_i(nsub)) 223 var em: i64=0 224 while em < 60 { 225 k=0; while k<H { var i3: i64=0; while i3<NFEAT { gW1[k*NFEAT+i3]=F_ZERO; i3=i3+1 } gb1[k]=F_ZERO; gW2[k]=F_ZERO; k=k+1 } 226 gb2[0]=F_ZERO 227 var s: i64=0 228 while s < ntr { 229 let base: i64 = s*NFEAT 230 // forward 231 var opre: i64 = b2p[0] 232 k=0 233 while k < H { 234 var pre: i64 = b1[k]; var i4: i64=0 235 while i4 < NFEAT { pre=nx_f32_add(pre, nx_f32_mul(W1[k*NFEAT+i4], trF[base+i4])); i4=i4+1 } 236 hpre[k]=pre 237 var a: i64 = pre; if nx_f32_lt(pre, F_ZERO)==(1 as nx_int) { a=F_ZERO } // relu 238 hact[k]=a 239 opre=nx_f32_add(opre, nx_f32_mul(W2[k], a)) 240 k=k+1 241 } 242 let p: i64 = f_sigmoid(opre) 243 let dout: i64 = nx_f32_sub(p, f_i(trL[s])) // BCE+sigmoid combined 244 gb2[0]=nx_f32_add(gb2[0], dout) 245 k=0 246 while k < H { 247 gW2[k]=nx_f32_add(gW2[k], nx_f32_mul(dout, hact[k])) 248 var dh: i64 = nx_f32_mul(dout, W2[k]) 249 if nx_f32_lt(hpre[k], F_ZERO)==(1 as nx_int) { dh=F_ZERO } // relu' 250 gb1[k]=nx_f32_add(gb1[k], dh) 251 var i5: i64=0; while i5<NFEAT { gW1[k*NFEAT+i5]=nx_f32_add(gW1[k*NFEAT+i5], nx_f32_mul(dh, trF[base+i5])); i5=i5+1 } 252 k=k+1 253 } 254 s=s+subS 255 } 256 // update 257 k=0 258 while k < H { 259 var i6: i64=0; while i6<NFEAT { W1[k*NFEAT+i6]=nx_f32_sub(W1[k*NFEAT+i6], nx_f32_mul(lrM, nx_f32_mul(gW1[k*NFEAT+i6], invM))); i6=i6+1 } 260 b1[k]=nx_f32_sub(b1[k], nx_f32_mul(lrM, nx_f32_mul(gb1[k], invM))) 261 W2[k]=nx_f32_sub(W2[k], nx_f32_mul(lrM, nx_f32_mul(gW2[k], invM))) 262 k=k+1 263 } 264 b2p[0]=nx_f32_sub(b2p[0], nx_f32_mul(lrM, nx_f32_mul(gb2[0], invM))) 265 em=em+1 266 } 267 // eval MLP on held-out 268 var bMLP: i64=0 269 var sm: i64=0 270 while sm < nte { 271 let base: i64 = sm*NFEAT 272 var opre: i64=b2p[0] 273 k=0 274 while k<H { 275 var pre: i64=b1[k]; var i7: i64=0 276 while i7<NFEAT { pre=nx_f32_add(pre, nx_f32_mul(W1[k*NFEAT+i7], teF[base+i7])); i7=i7+1 } 277 var a: i64=pre; if nx_f32_lt(pre,F_ZERO)==(1 as nx_int) { a=F_ZERO } 278 opre=nx_f32_add(opre, nx_f32_mul(W2[k], a)) 279 k=k+1 280 } 281 let p: i64=f_sigmoid(opre) 282 if teL[sm]==1 { bMLP=bMLP+f_neglog2_milli(p) } else { bMLP=bMLP+f_neglog2_milli(nx_f32_sub(f_one(),p)) } 283 sm=sm+1 284 } 285 286 gw(" held-out cross-entropy (bits): order0=" as *u8); g3(bOrd0/1000) 287 gw(" hand-context=" as *u8); g3(bHand/1000) 288 gw(" logistic=" as *u8); g3(bTrained/1000) 289 gw(" MLP=" as *u8); g3(bMLP/1000); gw("\n" as *u8) 290 let impH: i64 = (bHand-bMLP)*1000/bHand 291 gw(" hand beats order0 by " as *u8); gn((bOrd0-bHand)*1000/bOrd0) 292 gw("permille; MLP beats hand by " as *u8); gn(impH); gw("permille\n" as *u8) 293 294 var pass: i64=0; var tot: i64=0 295 tot=tot+1; if bHand < bOrd0 { pass=pass+1 } // hand-rules beat no-context (sanity) 296 tot=tot+1; if bMLP < bHand { pass=pass+1 } // the TRAINED NONLINEAR model beats hand-rules (the neural win) 297 tot=tot+1; if nte > 50000 { pass=pass+1 } // measured on real substantial held-out data 298 gw("NEURAL-ENTROPY: " as *u8); gn(pass); gw("/" as *u8); gn(tot) 299 if pass==tot { gw(" GREEN -- a TRAINED NONLINEAR entropy model beats hand-rules on held-out data (neural rung REAL)\n" as *u8); return 0 } 300 gw(" RED -- trained model does NOT beat hand-context (entropy-on-DCT near ceiling; SOTA needs learned representation)\n" as *u8); return 1 }