The duplicate ports neural/jpegai_hyper.rs and neural/jpegai_mans.rs, which the float decode path ran its front half with, are deleted (O10): that path runs the shared driver since the switch. The direct pieces of the exact decoder leave production, test-only (legacy_int): the crate-root mANS port (jpegai_mans), the hyper-scale network (jpegai_synthesis::decode_hyper_scale and its convolution) and the pipeline's skip_mask, rvs_additive, rvs_likely and sigma_index. The calibration tests that read them require legacy_int. jpegai_mans_golden runs on E8 and the scale graph alone; jpegai_e2e (the float chain against the reference PNG) takes its front half from the driver, still checking the dumped RVS additions, masks and residuals; the byte-equality crate drops the neural port and keeps E8 and the direct port. Co-Authored-By: Claude Opus 5.5 <[email protected]>
73 lines
3.6 KiB
Rust
73 lines
3.6 KiB
Rust
//! Calibration for [`wai::jpegai_pipeline::lsbs_refine`] — the least-significant-bit
|
||
//! scale refinement (`yhat → y_lsbs`, the synthesis input), on the REAL `test256.bin`
|
||
//! data for BOTH planes, against the reference's own dumps.
|
||
//!
|
||
//! ```text
|
||
//! means = yhat − resi
|
||
//! y_lsbs = yhat + (t0[likely]·means + t1[likely]·resi) / 2^13
|
||
//! ```
|
||
//!
|
||
//! Inputs are the reference's `pp{0,1}_{x,residual,likely,out}` dumps, so this is an
|
||
//! exact check of the formula in isolation, independent of upstream PTQ error. The
|
||
//! refinement is float arithmetic (IEEE-754 deterministic), so a machine-precision
|
||
//! match is required.
|
||
//!
|
||
//! `likely` is the shared per-8×8-block scale statistic ([`wai::jpegai_pipeline::rvs_likely`]),
|
||
//! passed in rather than recomputed here. It is the same value the dequant indexes —
|
||
//! verified identical against the reference — and LSBS indexes a 4352-entry table with
|
||
//! it *directly*, so an error in that statistic reads the wrong coefficients rather
|
||
//! than being absorbed by bucketing. `jpegai_e2e_frontend` asserts the derived
|
||
//! statistic drives this stage correctly; here it is supplied so the formula is tested
|
||
//! on its own.
|
||
//!
|
||
//! env: WAI_JPEGAI_LSBS_FIXTURE = lsbs_fixture.json
|
||
//! { t0:[i32], t1:[i32], y|uv: { c, h, w, yhat:[f32], resi:[f32], likely:[i64], y_lsbs:[f32] } }
|
||
#![cfg(all(feature = "neural_int", feature = "legacy_int"))]
|
||
|
||
use wai::jpegai_pipeline::lsbs_refine;
|
||
|
||
#[test]
|
||
fn lsbs_refine_matches_reference() {
|
||
let path = match std::env::var("WAI_JPEGAI_LSBS_FIXTURE") {
|
||
Ok(p) if std::path::Path::new(&p).exists() => p,
|
||
_ => { eprintln!("skip: set WAI_JPEGAI_LSBS_FIXTURE"); return; }
|
||
};
|
||
let v: serde_json::Value = serde_json::from_slice(&std::fs::read(&path).unwrap()).unwrap();
|
||
let i32v = |o: &serde_json::Value, k: &str| o[k].as_array().unwrap().iter()
|
||
.map(|x| x.as_i64().unwrap() as i32).collect::<Vec<i32>>();
|
||
let (t0, t1) = (i32v(&v, "t0"), i32v(&v, "t1"));
|
||
|
||
for plane in ["y", "uv"] {
|
||
let o = &v[plane];
|
||
let f32v = |k: &str| o[k].as_array().unwrap().iter()
|
||
.map(|x| x.as_f64().unwrap() as f32).collect::<Vec<f32>>();
|
||
let (c, h, w) = (
|
||
o["c"].as_u64().unwrap() as usize,
|
||
o["h"].as_u64().unwrap() as usize,
|
||
o["w"].as_u64().unwrap() as usize,
|
||
);
|
||
let yhat = f32v("yhat");
|
||
let resi = f32v("resi");
|
||
let likely: Vec<i64> = o["likely"].as_array().unwrap().iter()
|
||
.map(|x| x.as_i64().unwrap()).collect();
|
||
let reference = f32v("y_lsbs");
|
||
|
||
let got = lsbs_refine(&yhat, &resi, &likely, &t0, &t1, c, h, w);
|
||
assert_eq!(got.len(), reference.len(), "{plane}: y_lsbs size");
|
||
|
||
let exact = got.iter().zip(&reference).filter(|(a, b)| a == b).count();
|
||
let maxd = got.iter().zip(&reference).fold(0f32, |m, (a, b)| m.max((a - b).abs()));
|
||
|
||
// The identity baseline. LSBS is a small correction, so "close to the reference"
|
||
// is not by itself evidence that the refinement happened — passing yhat through
|
||
// unchanged must score materially worse than the real thing, or this test is
|
||
// measuring nothing.
|
||
let id_maxd = yhat.iter().zip(&reference).fold(0f32, |m, (a, b)| m.max((a - b).abs()));
|
||
eprintln!("[{plane}] lsbs_refine: {exact}/{} exact, max|Δ| = {maxd:.3e} \
|
||
(identity baseline max|Δ| = {id_maxd:.3e})", got.len());
|
||
|
||
assert!(maxd <= 1e-6, "{plane}: lsbs_refine max|Δ| {maxd:.3e}");
|
||
assert!(id_maxd > maxd * 100.0,
|
||
"{plane}: identity scores as well as the refinement — test is not discriminating");
|
||
}
|
||
}
|