//! Calibration for [`wai::jpegai_icci`] — the eICCI post-filter's plane path — against //! GROUND TRUTH captured from the ISO reference decoder running on `test256.bin`. //! //! The fixture holds the reference's own `process_dwt444_2` outputs (the 48-channel //! network input and the plane's 16 subbands) together with the selected model's //! weights, and the reference's `process_comp` output. Weights arrive with BatchNorm //! already folded (`w·γ/√(σ²+ε)`, `(b−μ)·γ/√(σ²+ε)+β`, ε=1e-5) — the same fold //! [`Conv::fold_bn`] performs. //! //! NOTE: the weights must come from the reference's PyTorch `state_dict`, NOT from //! `post_filters/model_*.onnx` — that graph wraps `forward`, which the decoder never //! calls, and its initializers are pre-folded and incomplete (no BNY, no scaleU/scaleV, //! no per-residual-block scale). //! //! env: WAI_JPEGAI_ICCI_FIXTURE = icci_y_fixture.json #![cfg(feature = "neural_int")] use wai::jpegai_icci::{Conv, IcciPath, ResBlock}; fn f32v(v: &serde_json::Value) -> Vec { v.as_array().unwrap().iter().map(|x| x.as_f64().unwrap() as f32).collect() } fn conv_of(v: &serde_json::Value) -> Conv { let g = |k: &str| v[k].as_u64().unwrap() as usize; Conv { w: f32v(&v["w"]), b: f32v(&v["b"]), cin: g("cin"), cout: g("cout"), kh: g("kh"), kw: g("kw"), ph: g("ph"), pw: g("pw") } } #[test] fn icci_plane_path_matches_reference() { let path = match std::env::var("WAI_JPEGAI_ICCI_FIXTURE") { Ok(p) if std::path::Path::new(&p).exists() => p, _ => { eprintln!("skip: set WAI_JPEGAI_ICCI_FIXTURE to icci_y_fixture.json"); return; } }; let v: serde_json::Value = serde_json::from_slice(&std::fs::read(&path).unwrap()).unwrap(); let (h, w) = (v["h"].as_u64().unwrap() as usize, v["w"].as_u64().unwrap() as usize); let blocks: Vec = v["blocks"].as_array().unwrap().iter().map(|b| ResBlock { conv1: conv_of(&b["c1"]), conv2: conv_of(&b["c2"]), scale: b["scale"].as_f64().unwrap() as f32, }).collect(); assert_eq!(blocks.len(), 2, "the Y path has two residual blocks"); let path_net = IcciPath { conv_first: conv_of(&v["conv_first"]), blocks, conv_last: conv_of(&v["conv_last"]), scale: v["scale"].as_f64().unwrap() as f32, }; let yuv48 = f32v(&v["yuv48"]); let sub16 = f32v(&v["sub16"]); let expected = f32v(&v["expected"]); assert_eq!(yuv48.len(), 48 * h * w, "network input is 48 channels at h×w"); assert_eq!(sub16.len(), 16 * h * w, "plane subbands are 16 channels"); let got = path_net.forward_plane(&yuv48, &sub16, h, w); assert_eq!(got.len(), expected.len(), "output is the full-resolution plane"); let mut maxd = 0f32; for i in 0..got.len() { maxd = maxd.max((got[i] - expected[i]).abs()); } eprintln!("eICCI plane path vs reference process_comp: max|Δ| = {maxd:.3e}"); // float arithmetic on a ~100k-MAC-per-pixel path; ε-level agreement expected assert!(maxd < 1e-4, "eICCI plane path diverged from the reference (max|Δ| = {maxd})"); }