Real-ESRGAN General x4v3 β€” LiteRT (CompiledModel GPU)

Real-ESRGAN x4 β€” 128px input vs bicubic vs on-device x4 output (LiteRT GPU)

Real-ESRGAN realesr-general-x4v3 (SRVGGNetCompact, ~1.2M params, BSD-3-Clause) re-authored to a GPU-native LiteRT .tflite via the official litert_torch path. Γ—4 real-world super-resolution. FP16, 3.5 MB, input 128Γ—128 β†’ output 512Γ—512 (NHWC, RGB, 0–1).

Verified on a Pixel 8a: the whole graph runs on the GPU delegate (full LITERT_CL residency, 211/211 nodes, 1 partition) in ~1 ms, and the GPU output matches the CPU/PyTorch reference (corr β‰ˆ 0.995).

Why this is GPU-clean

A pure CNN, but the stock conversion isn't GPU-clean: PReLU lowers to GREATER+SELECT+MUL and PixelShuffle lowers to a >4-D reshape β€” both GPU-rejected. Here:

  • PReLU β†’ relu(x) βˆ’ aΒ·relu(βˆ’x) (per-channel a): exact, only RELU/MUL/SUB.
  • PixelShuffle(4) β†’ a one-hot ConvTranspose(stride 4) β†’ ZeroStuffConvT (zero-stuff nearest + Conv2d): exact, no TRANSPOSE_CONV, no >4-D tensors.

Result: zero GATHER/SELECT/TopK/Cast, no >4-D tensors β€” full GPU residency. Re-authored vs original: corr 1.000000.

I/O

  • Input [1, 128, 128, 3] NHWC, RGB, 0–1 float (no mean/std). Tile larger images into 128Γ—128 patches.
  • Output [1, 3, 512, 512] NCHW, RGB, 0–1 (clamp to [0,1]). Γ—4 upscale β€” note the input is NHWC but the output tensor is NCHW.

Minimal usage

Android (Kotlin, CompiledModel GPU)

val model = CompiledModel.create(context.assets, "realesr_general_x4v3.tflite",
    CompiledModel.Options(Accelerator.GPU), null)
val inputs = model.createInputBuffers()
val outputs = model.createOutputBuffers()
inputs[0].writeFloat(nhwc)            // [1,128,128,3] RGB in [0,1], NHWC
model.run(inputs, outputs)
val up = outputs[0].readFloat()    // [1,3,512,512] NCHW in [0,1] (x4)

Python (desktop verification)

import numpy as np
from PIL import Image
from ai_edge_litert.interpreter import Interpreter

img = Image.open("small.png").convert("RGB").resize((128, 128))  # tile larger images
x = (np.asarray(img, np.float32) / 255.0)[None]                  # [1,128,128,3] NHWC

it = Interpreter(model_path="realesr_general_x4v3.tflite"); it.allocate_tensors()
it.set_tensor(it.get_input_details()[0]["index"], x); it.invoke()
y = it.get_tensor(it.get_output_details()[0]["index"])[0]        # [3,512,512] NCHW, [0,1]
Image.fromarray((y.transpose(1, 2, 0).clip(0, 1) * 255).astype(np.uint8)).save("x4.png")

Training data & PII

realesr-general-x4v3 was trained by the Real-ESRGAN authors on public super-resolution datasets (DIV2K / Flickr2K / OST and a synthetic high-order degradation pipeline). The model upscales image pixels only β€” no faces, identities, or other personal attributes are detected, recognized, or output. No additional or private data was used; weights are the official release, only the op graph was re-authored for GPU.

Sample app + conversion script

Android sample (CompiledModel GPU, before/after compare) and the litert_torch conversion script: https://github.com/google-ai-edge/litert-samples (compiled_model_api/super_resolution)

Downloads last month
114
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Collection including litert-community/real-esrgan-x4v3-litert