Skip to content

Add EDSR x4 super-resolution sample (CompiledModel GPU) - #212

Open
john-rocky wants to merge 4 commits into
google-ai-edge:mainfrom
john-rocky:edsr-super-resolution-sample
Open

Add EDSR x4 super-resolution sample (CompiledModel GPU)#212
john-rocky wants to merge 4 commits into
google-ai-edge:mainfrom
john-rocky:edsr-super-resolution-sample

Conversation

@john-rocky

Copy link
Copy Markdown
Contributor

EDSR (CVPR 2017 winner, eugenesiow/edsr-base via super-image, Apache-2.0) performs ×4 single-image super-resolution, running fully on the LiteRT CompiledModel GPU at ~23 ms/frame on a Pixel 8a. Tiny at 7.7 MB (bundled in assets).

EDSR is a pure CNN, but its PixelShuffle upsampler lowers to rank-5/6 reshapes the Mali delegate rejects (the classic super-resolution wall). Exact fix: PixelShuffle(r) ≡ a fixed-weight ConvTranspose2d(stride=r) → ZeroStuffConvT2d. Result: 68/68 nodes on the delegate, 1 partition; device corr 0.999946. CPU-exact vs PyTorch (corr 1.0). Input [1,3,128,128] RGB /255, output [1,3,512,512] 0–1.

Model: litert-community/EDSR-x4-LiteRT.

Sample at compiled_model_api/super_resolution/edsr_kotlin_gpu (android app + conversion scripts), with a deterministic bundled-image bicubic-vs-EDSR demo.

EDSR (CVPR 2017 winner, eugenesiow/edsr-base via super-image, Apache-2.0) upscales a low-res image 4x with sharp detail, running fully on the LiteRT CompiledModel GPU at ~23 ms/frame on a Pixel 8a. Tiny at 7.7 MB, so the model is bundled in assets.

EDSR is a pure CNN, but its PixelShuffle upsampler lowers to rank-5/6 reshapes the Mali delegate rejects (the classic super-resolution wall). Exact fix: PixelShuffle(r) equals a fixed-weight ConvTranspose2d(stride=r) -> ZeroStuffConvT2d. Result 68/68 nodes, 1 partition; device corr 0.999946. CPU-exact vs PyTorch (corr 1.0). Input [1,3,128,128] RGB /255, output [1,3,512,512] 0-1.

Sample at compiled_model_api/super_resolution/edsr_kotlin_gpu (android app + conversion scripts), with a deterministic bundled-image bicubic-vs-EDSR demo.
Wrap every line in the conversion scripts to the 80-column limit of the
Google Python Style Guide and add Args/Returns sections to the
module-level function docstrings. No behavior changes.
Restructure the EDSR x4 sample from a single View-based MainActivity into the
canonical Compose + MVVM shape, matching the sibling samples.

- MainActivity.kt is now a thin ComponentActivity that hosts ApplicationTheme
  and SuperResolutionScreen, wires the ViewModel via viewModels {...}, and adds
  a PickVisualMedia gallery picker.
- MainViewModel.kt owns the Upscaler helper, confines model creation and every
  upscale() call to Dispatchers.Default.limitedParallelism(1) (the helper reuses
  native in/out buffers), runs the bundled test_image.jpg on startup, and wraps
  the assets-backed load in try/catch surfacing the throwable as errorMessage.
- The old Activity's render math moves verbatim: EDSR x4 via Upscaler.upscale()
  plus a bicubic x4 baseline (Bitmap.createScaledBitmap to HR), both shown with
  the same '... ms . 128 -> 512' status the old UI displayed.
- Added UiState, ImageUtils (decodeAssetBitmap / loadOrientedBitmap), view/
  (SuperResolutionScreen, Theme, Color), res/values (strings, themes, colors);
  all UI strings live in strings.xml.
- Adopt the shared version catalog (gradle/libs.versions.toml) and root
  build.gradle.kts from the sibling samples; app keeps assets loading (no
  install_to_device.sh) and LiteRT stays pinned at 2.1.5.

The inference helper Upscaler.kt is unchanged (byte-identical).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant