← The CLR Journey

The feature ladder — v1.3 → v1.8

My incremental climb from hypothesis baseline to the frozen warp engine, curated from my original research notebooks.

After v1.3 I worked deliberately incrementally: add one feature family at a time, measure the AUC step, and write down why it moved — I was drafting the fundamental analysis for the paper as much as for the model.

The ladder

versionaddedper-tile AUC
v1.3hypothesis baseline only: fragility_rate + cross_residual_corr0.627
v1.4+ local_var (spatial heterogeneity of the residual), + cross_recovery_ratio_mean (symmetry of reconstruction failure across geometric tile pairs)0.688
v1.5constrain to features with confirmed hypothesis direction0.754
v1.6high-pass content isolation (data prep, not a feature)—
v1.7+ 4 seam features (boundary residual + spectral discontinuity)0.761
v1.8+ circ_var_noise, composite_noise → the canonical 100.775
Figure

v1.3: two hypothesis-grounded features, AUC 0.627. Weak — but every point of it is physics, and SHAP shows cross_residual_corr carrying the load.

Figure

The v1.5 feature space that justified the constraint: low recovery + high fragility → real; high recovery + low fragility → generated. The hypothesis's direction, visible as a linear boundary in two dimensions.

v1.6 — the pivot that made the signal honest

Raw residual is contaminated: high-texture tiles produce large residuals regardless of origin, so my early fragility_rate was partly a texture detector. I fixed this in v1.6 with a single preprocessing change: subtract a low-frequency (blurred) copy of the residual from itself, leaving only the high-frequency component.

High-pass filtering strips the low-frequency content component, leaving the PRNU-dominated residual. Every downstream feature is computed on this noise residual. This mattered most for intricate textures — fabrics and fine patterns where content energy would otherwise drown the sensor-noise signal. It is the cleanest single improvement I made in the whole project.

An implementation footnote from v1.7 that I nearly missed: computing the return warp as an exact matrix inverse rather than an independently-fitted reverse transform cost a sliver of AUC (~0.0015) — the exact inverse round-trip is marginally less discriminative than the independently-fit one. Small asymmetries in the probe are information.

The v1.8 engine

Figure

The frozen configuration is a dozen small constants — tile geometry, the differential strength pair, high-pass and seam windows — which I'm withholding here. But the shape of the result matters more than the values: my ablation confirmed they sit on a flat optimum (neighboring tile sizes and high-pass widths differ by < 0.004 AUC; I tested a much smaller tile from my early planning notes and rejected it). Warp strength climbs as a differential pair, and the homographies per strength stay random — consistency across trials is exactly what averaging provides without sacrificing isotropy.

Figure
Figure

One tile through the probe: original → warped → reconstructed → per-pixel error; below, the trial-accumulated residual, its high-passed version, the structured-noise ratio, and residual edge structure. This is the entire hypothesis in one figure.

The ten features, spatially

Figure
Figure
#featurereads
1fragility_rate∂R/∂s — PRNU destruction rate
2local_varspatial heterogeneity of reconstruction failure
3circ_var_noiseincoherence of the residual gradient field
4composite_noisejoint magnitude × coherence
5cross_residual_corrshared physics across diagonally-mirrored tiles
6cross_recovery_ratio_meansymmetry of reconstruction failure
7–8seam_h/v_discboundary residual discontinuity
9–10seam_h/v_spectralboundary spectral discontinuity

circ_var_noise earned its place on the hardest cases — iPhone-based pictures, even downsampled (JPEG-compressed remained a known problem). And an XGBoost on these 10 scalars per tile:

Figure

Per-tile, the signal is deliberately weak (≈0.60 on the harder scaled corpus; 0.775 on the v1.8 dataset) — a single tile is a whisper. circ_var_noise and local_var lead the SHAP ranking. Aggregation is where the whisper becomes a verdict.

Aggregation: center weight and the voting insight

In v1.8 I added texture-, center-, and confidence-weighting to the image-level aggregation over the tile grid. The center bias encodes something I kept seeing: patches containing subject matter have richer texture → stronger PRNU signal (real) or clearer generation artifacts (generated) → more reliable predictions. Edge and background patches with smooth uniform content are noisy voters that dilute the signal.

On the ~15k-image run:

text
real       : maj = 87.1%   wgt = 65.8%
generated  : maj = 94.7%   wgt = 96.1%
overall    : maj = 90.9%   wgt = 80.9%

I closed the chapter in v1.8.2 with an analytic (model-free) scorer probe, confirming that the warp and the features — not the trees — do the discriminative work: a hand-calibrated scorer on the same 10 features approaches the XGBoost, which is exactly what I wanted to be true of a physics claim.

I froze v1.8 there. Everything after it builds around this engine, not inside it — starting with the fusion that broke the warp ceiling.