File size: 7,565 Bytes
b4ed648 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | ---
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](https://github.com/xinntao/ESRGAN) optimized for edge deployment on ARM devices using [ExecuTorch](https://github.com/pytorch/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](https://huggingface.co/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](https://github.com/xinntao/ESRGAN) β 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
```bash
pip install executorch torch torchvision pillow numpy
```
### Download the model
```python
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
```bash
python example.py
```
Or use the core inference loop directly:
```python
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
1. Load pretrained FP32 RRDBNet with PSNR-oriented weights from HuggingFace (`kadirnar/RRDB_PSNR_x4`)
2. Capture model graph via `torch.export` at fixed 128Γ128 tile size
3. Insert quantization observers (XNNPACKQuantizer, skipping upsampling + first 3 body blocks)
4. Calibrate with 100 Urban100 patches
5. Convert observers to Q/DQ pairs
6. Post-quantization graph surgery (remove spurious Q/DQ pairs from `cat` nodes in FP32 body blocks)
7. Export to ExecuTorch `.pte` with 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**:
1. Convert PIL image to float32 tensor via `ToTensor()` (maps [0, 255] β [0, 1])
2. 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**:
1. Clamp output tensor to [0, 1]
2. For tiled inputs: accumulate tile outputs into a full-resolution canvas, averaging overlapping regions
3. 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 - overlap` with 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
|