AdcSR (CVPR 2025) is the zoo’s first super-resolution
model: a one-step diffusion-GAN ×4 SR. It is the Adversarial Diffusion Compression of
OSEDiff — a pruned Stable Diffusion 2.1 UNet (~456 M params)
plus a half-size VAE decoder, run in a single forward. Diffusion-grade perceptual quality, small
enough for iPhone, and (unlike the ResShift/SinSR family, which are non-commercial) usable
commercially: the code is Apache-2.0 and the SD-2.1-derived weights carry CreativeML Open RAIL++-M
— the same license under which Apple ships SD CoreML. HF: mlboydaisuke/AdcSR-CoreAI.
Net (AdcSR model.py) takes the diffusers SD-2.1 UNet and surgically: deletes time_embedding,
deletes cross-attention (attn2/norm2), prunes every conv/linear/norm to ×0.75 channels, and
swaps in text/time-free My*_SD_forward methods (forward.py). The deployed pipeline is
PixelUnshuffle(2) → pruned UNet → half VAE decoder, image→image, no prompt/noise/timestep.
Exported as ONE static graph: lr [1,3,128,128] in [-1,1] → sr [1,3,512,512] (×4). Only
standard SD ops (conv, group-norm, self-attention Transformer2DModel, PixelUnshuffle) — no swin,
so the coreai-pre-compilation-rewrite SIGSEGV that bit the SinSR swin port does not apply here.
The single op coreai-torch rejected was aten.var.correction from the original color-match’s
.std(); we removed the in-graph color-match entirely (see below). Conversion: conversion/export_adcsr.py.
SuperResolver)The graph outputs the raw SR. Two things are done on the host:
SuperResolver caps the input long side
(maxInputSide=512, so a full phone photo isn’t blown up to a gigapixel result), splits the LR
into overlapping 128-px windows, runs each, and feather-blends.The pruned SD-2.1 UNet is numerically unstable in fp16: attention overflows (the classic SD-2.1
fp16 NaN), and upcast_attention has no effect because the diffusers SDPA processor ignores
it; group-norm of a low-variance tile also divides by ~0. The result is whole tiles → NaN → black/
gray patches on smooth regions. group-norm-fp32 upcast alone did not fix it. fp32 (~1.7 GB) is
the shipped precision — no NaN, output matches the torch reference (cosine 1.000012). With the
512-px input cap + tiling, the per-tile activation is bounded, so fp32 fits iPhone 17 Pro
(~2.7 GB peak < 6 GB).
Note: the Python runtime’s default-options AIModel.load SIGSEGVs in the GPU-delegate JIT
(CompileForDelegates) for fp16; loading with an explicit SpecializationOptions(.gpu) (which the
Swift GraphModel always does) is clean. Irrelevant for fp32, but worth knowing.
CGContext’s actual bytesPerRow (pass bytesPerRow: 0), never assume
width*4 — CG pads non-16-aligned widths, and assuming width*4 shears the image (garbled tiles
on odd-width photos).CGBitmapContext already maps the image’s top to row 0;
adding a scaleBy(1,-1) flip inverts the result vertically.apps/CoreAIUpscale (iOS + macOS, PhotosPicker) and CoreAIKit Examples/UpscaleDemo. Both use
SuperResolver(model: .adcsrX4).upscale(cgImage). Verified on iPhone 17 Pro.