Tiles are fixed-shape, so fused compilation applies the same as full-frame.
Forcing compile=False in the tiled branch left performance on the table:
measured on the same 12-frame 2048px green-screen set (alpha output
bit-identical, IoU 0.9316):
M3 Ultra: 3.64 -> 2.48 s/frame (1.47x)
M1 Ultra: 4.65 -> 4.19 s/frame (1.11x)
Peak memory unchanged (~2.3 GB).
PIL bicubic vs MLX cubic diff too large (0.22-0.59) — resize stays
on CPU. Only normalize+concat moved to MLX. Tiled path unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fold window dim into batch (transpose before reshape), call SDPA,
unfold back. All parity tests pass with 0 regression.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
mx.eval + gc + clear_cache at backbone→decoder and decoder→refiner
boundaries in eager mode. _compiled flag skips GC under mx.compile.
Compilation tests updated to use compile_model() API.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
slim=True returns 4-key dict, engine uses it, pipeline.infer keeps full.
2 new tests: key count + bit-exact match vs full output.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
tile_size/overlap params on CorridorKeyMLXEngine — model loads at
tile_size, input stays full-res, forward uses tiled_inference w/ GC.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
load_model() now defaults to dtype=bf16, fused_decode=True. Both are
free (zero parity regression, bit-exact fused path). Backbone/sigmoid
stay fp32.
Plan updated with benchmark results: tiled+GC = 12x peak memory
reduction at 2048x2048 (27.6GB → 2.3GB), all acceptance criteria met.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PyTorch reference script had wrong concat order (forward) vs the
original nikopueringer/CorridorKey which uses torch.cat([c4,c3,c2,c1]).
Golden fixtures regenerated. Relax 3 tight e2e tolerances for Metal
vs CPU float32 drift.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace mypy with Astral's ty for faster type checking. Fix
Image.BICUBIC deprecation and inline **kwargs for ty compatibility.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Torch decoder concatenates feature projections as [c4,c3,c2,c1] but
MLX was using [c1,c2,c3,c4]. The linear_fuse conv was trained with
the Torch order, producing scrambled features. Verified fix gives
correlation=1.0 against Torch on identical inputs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
preprocess() already calls normalize_rgb() internally; calling it
before passing to preprocess() applied ImageNet normalization twice.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Drop-in MLX backend for main CorridorKey repo. Engine class wraps
existing model/inference with process_frame() API returning alpha,
fg, comp, processed as uint8 numpy arrays. Lowers Python to >=3.11,
removes unused deps, adds smoke script and 16 contract tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Cache nn.Upsample instances in DecoderHead/GreenFormer __init__
(eliminated ~7 allocations per forward pass)
- Add mx.compile() support via load_model(compile=True)
- Benchmark harness: eager vs compiled, multi-resolution, parity checks
- Tiled inference with overlap blending for large images
- Profiling utilities with forced mx.eval for accurate timing
- Reference comparison script (scripts/compare_reference.py)
- 12 new tests (compiled consistency + tiling)
- README performance section with Apple Silicon guidance
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire GreenFormer (backbone + decoders + refiner), add image I/O,
inference pipeline, CLI entry point, and 3 test files (23 new tests).
E2e parity vs PyTorch: max abs err < 1.5e-4 across all outputs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>