library_name: executorch
display_name: ESRGAN x4 INT8 β ExecuTorch + XNNPACK
license: apache-2.0
base_model: kadirnar/RRDB_PSNR_x4
base_model_relation: quantized
tags:
- image-to-image
- esrgan
- int8
- quantized
- xnnpack
- arm
- executorch
- edge-ai
- urban100
- super-resolution
pipeline_tag: image-to-image
datasets:
- urban100
metrics:
- psnr
model-index:
- name: esrgan-int8-xnnpack-executorch-graviton-g4
results:
- task:
type: image-to-image
name: Super Resolution
dataset:
type: urban100
name: Urban100
split: validation
args:
evaluation_samples: 100
metrics:
- type: psnr
value: 26.81
name: PSNR (dB)
ESRGAN x4 INT8 (ExecuTorch + XNNPACK)
This is an INT8-quantized version of ESRGAN RRDBNet optimized for edge deployment on ARM devices using ExecuTorch with the XNNPACK backend. The model was quantized using PT2E static symmetric per-channel quantization and exported to the .pte format for efficient inference on ARM Cortex-A processors (AWS Graviton, mobile ARM, embedded).
The PSNR-oriented weights (RRDB_PSNR_x4.pth) from kadirnar/RRDB_PSNR_x4 are used β the L1-trained high-PSNR variant whose metrics are directly comparable to standard SR benchmark figures.
Key Highlights
Compared to the FP32 baseline:
- 2.76x smaller β 64.07 MB to 23.18 MB
- 2.44x faster β 1763 ms to 724 ms on AWS Graviton (Neoverse-V2)
- Minimal quality loss β β0.22 dB PSNR on Urban100
Model Details
Model Description
Quantized version of ESRGAN (Enhanced Super-Resolution Generative Adversarial Network) with a 23-block RRDBNet backbone. The model performs 4x bicubic super-resolution on urban scene images, optimized for efficient edge inference via INT8 quantization and the ExecuTorch runtime.
- Developed by: Xintao Wang et al. (ESRGAN), Marvik AI (quantization & optimization)
- Model type: Super Resolution (4x upscaling)
- License: Apache-2.0
- Base model: ESRGAN RRDBNet β quantized, not finetuned
Model Sources
- Repository: https://github.com/xinntao/ESRGAN
- Pretrained weights: https://huggingface.co/kadirnar/RRDB_PSNR_x4
How to Get Started with the Model
Install dependencies
pip install executorch torch torchvision pillow numpy
Download the model
from huggingface_hub import hf_hub_download
model_path = hf_hub_download(
repo_id="Arm/esrgan-int8-xnnpack-executorch-graviton-g4",
filename="esrgan-x4-int8-executorch.pte",
)
Run inference
python example.py
Or use the core inference loop directly:
from executorch.runtime import Runtime
from PIL import Image
from torchvision import transforms
# Load model
runtime = Runtime.get()
program = runtime.load_program("esrgan-x4-int8-executorch.pte")
method = program.load_method("forward")
# Preprocess (no normalization β model expects raw [0, 1] values)
image = Image.open("input.jpg").convert("RGB")
to_tensor = transforms.ToTensor()
input_tensor = to_tensor(image).unsqueeze(0) # [1, 3, H, W]
# Run a single 128x128 tile
tile = input_tensor[:, :, :128, :128]
outputs = method.execute([tile])
# outputs[0] shape: [1, 3, 512, 512] β the 4x super-resolved tile
# See example.py for full tiled inference on arbitrary-size images
Evaluation
Testing Data, Factors & Metrics
Testing Data
Evaluated on 100 images from Urban100 (validation split). Urban100 is a standard super-resolution benchmark consisting of urban scenes with repetitive structures, specifically chosen to challenge SR models on fine detail reconstruction.
Metrics
- PSNR (Peak Signal-to-Noise Ratio, dB) β measures pixel-level fidelity between the super-resolved output and the ground-truth high-resolution image; higher is better
- SSIM (Structural Similarity Index) β measures perceived structural similarity; higher is better
Results
Quality
| Metric | FP32 (Original) | INT8 (Optimized) | Delta |
|---|---|---|---|
| PSNR (dB) | 27.03 | 26.81 | β0.22 dB |
| SSIM | 0.8176 | 0.8109 | β0.007 |
Efficiency
| Metric | FP32 (Original) | INT8 (Optimized) | Improvement |
|---|---|---|---|
| Model Size (.pte) | 64.07 MB | 23.18 MB | 2.76x smaller |
| Graviton Latency (mean) | 1763 ms | 724 ms | 2.44x faster |
| Graviton Latency (p50) | 1763 ms | 704 ms | 2.50x faster |
| Graviton Latency (p90) | 1765 ms | 780 ms | 2.26x faster |
| Graviton Cold Start | 66.3 ms | 36.7 ms | 1.81x faster |
Latency measured on AWS Graviton G4 (Neoverse-V2, 16 cores) with ExecuTorch 1.1.0, XNNPACK + KleidiAI backend, batch size 1, 10 warmup runs + 100 measurement runs.
Technical Specifications
Objective
4x single-image super-resolution from bicubic-degraded low-resolution inputs, targeting urban scenes with repetitive structures.
Quantization
- Method: PT2E Static Quantization via XNNPACKQuantizer
- Precision: INT8 symmetric, per-channel
- Backend: XNNPACK
- Layers kept in FP32: upsampling layers (
upconv1,upconv2,HRconv,conv_last) and the first 3 RRDB body blocks (body.0βbody.2) to preserve output fidelity - Calibration: 100 images from Urban100 (random subset, patch mode)
Export Pipeline
- Load pretrained FP32 RRDBNet with PSNR-oriented weights from HuggingFace (
kadirnar/RRDB_PSNR_x4) - Capture model graph via
torch.exportat fixed 128Γ128 tile size - Insert quantization observers (XNNPACKQuantizer, skipping upsampling + first 3 body blocks)
- Calibrate with 100 Urban100 patches
- Convert observers to Q/DQ pairs
- Post-quantization graph surgery (remove spurious Q/DQ pairs from
catnodes in FP32 body blocks) - Export to ExecuTorch
.ptewith XNNPACK backend
Preprocessing
| Property | Value |
|---|---|
| Input shape | [1, 3, 128, 128] (BCHW, single tile) |
| Data type | float32 |
| Value range | [0.0, 1.0] |
| Color space | RGB |
Steps:
- Convert PIL image to float32 tensor via
ToTensor()(maps [0, 255] β [0, 1]) - For images larger than 128Γ128: split into overlapping 128Γ128 tiles with 8-pixel overlap; each tile is processed independently
Normalization: None required β the model expects raw [0, 1] pixel values.
Postprocessing
| Property | Value |
|---|---|
| Output shape | [1, 3, 512, 512] per tile (4x upscaled) |
| Output format | Float32 RGB tensor, values may exceed [0, 1] before clamping |
Steps:
- Clamp output tensor to [0, 1]
- For tiled inputs: accumulate tile outputs into a full-resolution canvas, averaging overlapping regions
- Convert to uint8 for saving (
* 255, round, cast)
Known Limitations
- Evaluated on 100 images from Urban100 β a benchmark focused on urban/architectural scenes; performance on natural landscapes or faces may differ
- Fixed tile size of 128Γ128: images must be at least 128Γ128; the tiling inference handles arbitrary sizes automatically
- Input images are not aspect-ratio padded β tiles are extracted at stride
tile_size - overlapwith edge tiles placed at the image boundary - XNNPACK operator coverage is approximately 49%: upsampling, LeakyReLU, and some transpose operations fall back to non-XNNPACK kernels; latency figures reflect this mixed execution