--- license: apache-2.0 library_name: openvino tags: - realesrgan - super-resolution - openvino - nncf - int4 - quantization - image-to-image pipeline_tag: image-to-image --- # Real-ESRGAN → OpenVINO INT4 把 [Real-ESRGAN](https://github.com/xinntao/Real-ESRGAN) 的 `RealESRGAN_x4plus` (RRDBNet,23 個 RRDB block,16.7 M 參數)轉成 **OpenVINO IR**,並用 NNCF 做成 **INT4 / INT8 / FP16** 多種精度版本。所有模型都是純 OpenVINO 推論, **執行時不需要 PyTorch**,只要 `openvino + opencv + numpy`(首次使用會自動從本 repo 下載權重)。 | 模型 key | 檔案 | 精度 | 大小 (xml+bin) | 說明 | |---|---|---|---|---| | `int4` | `models/realesrgan_x4plus_int4_w4a16.*` | **W4A16**(權重 `u4` per-channel asym,activation FP16) | **11.0 MB** | 純 4-bit,351 個 conv 全部 4-bit,體積最小 | | `int4-mixed` | `models/realesrgan_x4plus_int4_mixed_w4a16.*` | W4/W8 混合 | 15.2 MB | 約一半權重 4-bit、最敏感的一批保留 INT8,畫質明顯較好 | | `int4-w4a8` | `models/realesrgan_x4plus_int4_w4a8.*` | **W4A8**(權重 4-bit、activation INT8) | 11.8 MB | 純 4-bit 權重 + INT8 計算路徑 | | `int8` | `models/realesrgan_x4plus_int8_w8a8.*` | **W8A8** | 19.5 MB | CPU 上**最快**,畫質/速度最佳平衡點 | | `fp16` | `models/realesrgan_x4plus_fp16.*` | FP16 | 35.1 MB | 幾乎無損(對 FP32 約 48 dB),當作 reference 基準 | | `fp32` | 用 `export_openvino_int4.py` 產生 | FP32 | 66.8 MB | 未壓縮,僅供對照/量測 PSNR 用 | > 原始 PyTorch 權重檔:`RealESRGAN_x4plus.pth`(67 MB,來自 Real-ESRGAN v0.1.0 release), > checkpoint 內的 key 是 `params_ema`。本 repo 的轉換管線已驗證 **與 BasicSR `RRDBNet` 逐 bit 相同** > (`max|diff| = 0.0`)。 --- ## 1. 實測結果 測試機:Intel Xeon Platinum 8559C(Emerald Rapids,16 vCPU,含 AMX-INT8 / AVX512-VNNI / AVX512-FP16)、 OpenVINO 2026.4.1、tile=128、tile_pad=16。 **畫質**(3 張 `inputs/` 測試圖,PSNR / SSIM 對 `fp16` 版本;`fp16` 與 PyTorch FP32 差異 < 0.3 dB): | 模型 | 大小 | PSNR ↑ | SSIM ↑ | PSNR vs. 原圖 ↑(bicubic LR 輸入) | |---|---|---|---|---| | `fp16` | 35.1 MB | 基準 | 1.0000 | 18.90 dB | | `int8` (W8A8) | 19.5 MB | **29.62 dB** | **0.927** | **19.25 dB** | | `int4-mixed` | 15.2 MB | 24.73 dB | 0.897 | 17.77 dB | | `int4` (W4A16) | 11.0 MB | 18.41 dB | 0.679 | 16.83 dB | | `int4-w4a8` | 11.8 MB | 18.72 dB | 0.618 | 16.95 dB | **速度**(合成 512×256 輸入、tile=128、取 3 次最佳): | 模型 | 秒 / 張 | 輸入 MPix/s | 備註 | |---|---|---|---| | `int8` (W8A8) | **1.30 s** | **0.10** | AMX/VNNI INT8 路徑,比 FP32 快約 1.9× | | `fp16` | 2.48 s | 0.05 | | | `int4-mixed` | 2.28 s | 0.06 | | | `int4` (W4A16) | 2.32 s | 0.06 | | | `int4-w4a8` | 2.49 s | 0.05 | INT8 quantize/dequantize 節點反而稍慢 | ### 為什麼 INT4 沒有比較快? OpenVINO CPU plugin 執行 `u4` 權重時會在 runtime **解壓回 FP32/FP16** 再做卷積, 所以 4-bit 的收益是 **模型體積 / 記憶體(4×)而不是速度**;要速度請用 `int8`(W8A8)。 4-bit 權重大多數時候適合「記憶體受限 / 想把模型塞進邊緣裝置 / 減少下載量」的場景。 ### 為什麼 INT4 畫質掉得比較多? Real-ESRGAN 是純卷積的深層殘差網路(23 個 RRDB,每層輸出 `x*0.2 + conv(x)`), 誤差會沿 351 層累積。4-bit 每層權重 SQNR 只有 ~17 dB,累積後 PSNR 掉到 ~18 dB。 因此本 repo 同時提供: * `int4-mixed`:由 NNCF 敏感度分析挑出「最不能壓」的層保留 INT8,其餘 4-bit → **幾乎無損的畫質**(SSIM 0.90+),大小只多 38%。 * `int8`:想要又快又準就用這個。 --- ## 1.5 效果對比(同一張圖:原始 PyTorch vs 各個 OpenVINO 版本) 測試照片是 NASA 肯尼迪太空中心的**公有領域**白頭海雕照片 ([KSC-20230425-PH-JBS02_0003](https://images.nasa.gov/details/KSC-20230425-PH-JBS02_0003)), 裁切 1024×768 當 Ground Truth,bicubic 降 4 倍成 256×192 餵進模型, 所有模型都用 tile=128 推論成 768×1024。 細節並排比較(左上 bicubic、右上原始 PyTorch FP32、中上 FP16、左下 INT8、下中 INT4 混合、右下純 INT4): ![detail montage](samples/eagle_4x/10_detail_montage.jpg) | 模型 | 大小 | PSNR vs PyTorch FP32 ↑ | SSIM ↑ | PSNR vs 原圖 ↑ | 推論時間 | |---|---|---|---|---|---| | `pytorch_fp32`(原始 PyTorch,基準) | 67.0 MB | 基準 | 1.0000 | 20.12 dB | 4.46 s | | bicubic x4(對照) | – | 22.54 dB | 0.7049 | **21.70 dB** | – | | [`openvino_fp16.jpg`](samples/eagle_4x/openvino_fp16.jpg) | 35.1 MB | **48.38 dB** | **0.9981** | 20.14 dB | 0.60 s | | [`openvino_int8_w8a8.jpg`](samples/eagle_4x/openvino_int8_w8a8.jpg) | 19.5 MB | 27.76 dB | 0.8675 | 20.39 dB | **0.39 s** | | [`openvino_int4_mixed_w4a16.jpg`](samples/eagle_4x/openvino_int4_mixed_w4a16.jpg) | 15.2 MB | 22.84 dB | 0.8160 | 18.68 dB | 0.61 s | | [`openvino_int4_w4a16.jpg`](samples/eagle_4x/openvino_int4_w4a16.jpg) | 11.0 MB | 18.02 dB | 0.4879 | 17.19 dB | 0.60 s | | [`openvino_int4_w4a8.jpg`](samples/eagle_4x/openvino_int4_w4a8.jpg) | 11.8 MB | 17.89 dB | 0.4624 | 17.09 dB | 0.69 s | 重現方式、完整檔案清單與說明見 **[`samples/eagle_4x/README.md`](samples/eagle_4x/README.md)**, 照片授權為 NASA 公有領域(Public Domain)。 --- ## 1.6 影片對比(放大前 vs 各個量化版本,repo 內可直接播放) 除了靜態圖,repo 也放了一段**公有領域**的 NASA 影片(ISS 氣輝夜景,`GSFC_20181022_ICON_m12902_Airglow`), 用**原始 PyTorch 模型**與**所有 OpenVINO 版本**做 640×360 → 2560×1440 的 4 倍放大,逐影格記錄時間與畫質。 ### ① 放大前(模型輸入,640×360,1.5 s / 45 影格)

### ② 並排比較影片(bicubic / PyTorch FP32 / FP16 / INT8 / INT4 mixed / INT4,含標籤)

若播放器不支援 HTML video,可直接看這支 GIF: ![side by side gif](samples/video_airglow/22_side_by_side_preview.gif) ### ③ 各個模型的 4x 放大影片(2560×1440) **原始 PyTorch FP32(放大後)**

**OpenVINO FP16**

**OpenVINO INT8(W8A8)**

**OpenVINO INT4 混合精度(W4/W8)**

**OpenVINO 純 INT4(W4A16)**

### ④ 城市燈光帶 1:1 放大比較(最能看出量化差別) ![video zoom](samples/video_airglow/22_poster_detail_zoom.jpg) ### ⑤ 時間與畫質紀錄 | 模型 | 大小 | 45 影格總時間 | ms/影格 | 張/秒 | vs PyTorch PSNR ↑ | SSIM ↑ | 加速比 ↑ | |---|---|---|---|---|---|---|---| | `pytorch_fp32`(原始) | 67.0 MB | 663.5 s | 14745 | 0.07 | 基準 | 1.0000 | 1.0× | | `openvino_fp16` | 35.1 MB | 211.5 s | 4700 | 0.21 | **45.41 dB** | **0.9927** | 3.1× | | `openvino_int8_w8a8` | 19.5 MB | **124.8 s** | **2773** | **0.36** | 36.90 dB | 0.9284 | **5.3×** | | `openvino_int4_mixed_w4a16` | 15.2 MB | 214.6 s | 4769 | 0.21 | 31.31 dB | 0.9344 | 3.1× | | `openvino_int4_w4a16` | 11.0 MB | 246.8 s | 5485 | 0.18 | 25.40 dB | 0.7894 | 2.7× | 直接下載:`samples/video_airglow/00_source_lr.mp4`、`10_pytorch_fp32_4x.mp4`、`11_openvino_fp16_4x.mp4`、 `12_openvino_int8_w8a8_4x.mp4`、`13_openvino_int4_mixed_4x.mp4`、`14_openvino_int4_4x.mp4`、 `20_side_by_side_1920x780.mp4`(完整說明見 [`samples/video_airglow/README.md`](samples/video_airglow/README.md)) 重點結論:**INT8 (W8A8) 在 CPU 上比 PyTorch FP32 快 5.3×** 且畫質僅 36.9 dB / SSIM 0.93; **INT4 在 CPU 上不會更快**(CPU plugin 執行時會把 4-bit 權重解壓回 FP32/FP16), 它的優勢是模型只有 11 MB;若要在 4-bit 尺寸下兼顧畫質,請用 `int4-mixed`。 ### Intel GPU(NPU / AUTO 同理)可以執行嗎? 可以。這些都是**標準 OpenVINO IR**(動態 shape),不綁定 plugin,`-d GPU` / `-d NPU` / `-d AUTO` / `-d HETERO` 都能跑: ```bash python realesrgan_ov.py -i input.jpg -d GPU -m int8 -t 128 # Intel GPU 上推薦 INT8 python realesrgan_ov.py -i input.jpg -d AUTO -m fp16 # 自動挑最快裝置 ``` | 模型 | Intel GPU 支援 | 說明 | |---|---|---| | `fp16` | ✅ | Xe / Arc 上 FP16 有硬體加速;更舊的 UHD/Iris 會以 f32 執行 | | `int8` (W8A8) | ✅ **GPU 上最快** | GPU plugin 對 INT8 卷積有最佳路徑(Xe-LP+ / Arc / Alchemist) | | `int4-mixed` / `int4` / `int4-w4a8` | ⚠️ 可執行、通常不快 | GPU plugin 支援 4-bit 權重,但**卷積**沒有 4-bit 加速路徑,會在 runtime 解壓成 FP16/FP32;收益只有 VRAM。純 4-bit 的模型還多了 dequantize 節點,GPU 上反而變慢 | | `fp32` | ✅ | 相容但最慢,僅供對照 | 若要給 Intel GPU 專用的量化模型(INT8 的 activation 範圍與 SmoothQuant 會依 GPU 特性不同而調整): ```bash python export_openvino_int4.py --weights RealESRGAN_x4plus.pth --target-device gpu \ --a8-bits 8 --a8-name int8_w8a8_gpu --no-w4a16 ``` 備註:本 repo 的模型是在**沒有 GPU 的機器**上驗證的(`available_devices = ['CPU']`), 以上 Intel GPU 的說明是依 OpenVINO plugin 的能力整理,不是本機實測數據。 --- ## 2. 安裝 ```bash pip install openvino opencv-python numpy huggingface_hub # 只有要「自己重新轉換模型」才需要: pip install torch onnx onnxscript nncf ``` `realesrgan_ov.py` 會在第一次執行時自動從本 repo 下載 `*.xml` / `*.bin`, 並快取到 `~/.cache/realesrgan_openvino`(可用環境變數 `REALESRGAN_OV_CACHE` 改位置)。 也可以手動下載後用 `--model-path` / `-m /path/to/model.xml` 指定本機檔案。 --- ## 3. 快速開始:單一 py 檔 下載兩個檔案即可(`realesrgan_ov.py` + `benchmark_models.py`),模型會自動下載。 ```python # quick_start.py import cv2 from realesrgan_ov import RealESRGAN upscaler = RealESRGAN(model='int4') # int4 | int4-mixed | int8 | fp16 | 自訂 .xml 路徑 img = cv2.imread('input.jpg') # BGR uint8 sr, scale = upscaler.enhance(img, tile=128) # 4 倍超解析(記憶體吃太多時用 tile 分塊) cv2.imwrite('output.png', sr) print('output:', sr.shape, 'scale:', scale) ``` `inputs/` 內附 3 張測試圖(來自 Real-ESRGAN 官方 inputs),`samples/` 內附 1 張公有領域照片與 1 段公有領域影片(都已用所有模型跑過),可直接試跑: ```bash python realesrgan_ov.py -i inputs/00003.png -o results/ -m int4-mixed -t 128 ``` ```bash # 命令列 python realesrgan_ov.py -i input.jpg # 4x 超解析,輸出 results/ python realesrgan_ov.py -i ./photos -o out/ -m int8 # 整個資料夾 python realesrgan_ov.py -i clip.mp4 -o clip_4x.mp4 # 影片逐影格 python realesrgan_ov.py -i big.png -t 64 --tile-pad 16 # 大圖分塊(256→1024 這類) python realesrgan_ov.py -i input.jpg --outscale 2 # 只放大 2 倍(先 4x 再 downscale) python realesrgan_ov.py -d GPU -m int8 -i input.jpg # 用 GPU / NPU / AUTO python realesrgan_ov.py --benchmark --images input.jpg # 只測效能 python benchmark_models.py --images a.png b.png # 比較所有版本的畫質/速度 ``` 支援 PNG/BMP/JPG/WEBP(含 alpha 通道,alpha 會用 bicubic 放大)、資料夾遞迴、影片(mp4/avi/mov/mkv)。 --- ## 4. Python API ```python from realesrgan_ov import RealESRGAN up = RealESRGAN( model='int4', # int4 / int4-mixed / int4-w4a8 / int8 / fp16 / '/path/model.xml' device='CPU', # CPU / GPU / NPU / AUTO precision='auto', # auto(預設)/ f32 / f16 / bf16 num_threads=8, # 0 = 使用全部核心 ) sr, scale = up.enhance(img, tile=128, tile_pad=16, pre_pad=0, outscale=4) sr_bgra = up.enhance_alpha(bgra_img, tile=128) # 自動處理 alpha ``` `precision` 說明(**很重要**):新版 OpenVINO CPU 對 FP32 graph 的預設 `INFERENCE_PRECISION_HINT` 是 **bf16**,會讓這個網路的 PSNR 掉約 20 dB。 `realesrgan_ov.py` 的 `auto` 會對 FP32/FP16/INT4(FP16 activation) 的模型自動釘成 `f32`, INT8 graph 不受影響。若你自己用 `ov.Core().compile_model()`,請記得傳 `{'INFERENCE_PRECISION_HINT': 'f32'}`。 --- ## 5. 從 PyTorch 權重重新轉換成 OpenVINO INT4 ```bash python export_openvino_int4.py \ --weights RealESRGAN_x4plus.pth \ --data-dir inputs \ # 校準用的低解析度圖 --out-dir models \ --calib-tile 128 --calib-samples 6 \ --weight-ratio 1.0 \ # 1.0 = 全部 4-bit;0.5 = 一半 4-bit、其餘 INT8 --a8-bits 8 --a8-name int8_w8a8 ``` 流程:`RRDBNet(重建) → strict=True 載入 checkpoint → ONNX(opset17, 動態 H/W) → OpenVINO FP32/FP16 → NNCF 量化 → IR` 這個管線裡有兩個**必須**處理的地方(否則 INT4 會被靜默降級成 INT8): 1. `nncf.compress_weights(mode='int4_*')` 預設只把 **MatMul** 壓成 4-bit,卷積一律落到 INT8 backup → `enable_int4_for_convolutions()` 擴充 `_get_ratio_defining_params`,讓 Conv 也吃 4-bit。 2. NNCF 的 CPU hardware config 只允許 8/16-bit 權重 → `enable_int4_weights_in_cpu_hw_config()` 把 `q4_w` 加進 Convolution 的 qspace,產生 `u4` 常數(OpenVINO CPU plugin 可執行)。 3. `openvino.convert_model()` 預設會把權重壓成 FP16(本模型會掉到 ~27 dB)→ `convert_onnx()` 以 `compress_to_fp16=False` 轉換,得到真正的 FP32 graph。 驗證方式(本 repo 產出的模型都跑過): ```bash python - <<'PY' from openvino import Core m = Core().read_model('models/realesrgan_x4plus_int4_w4a16.xml') print(sorted({str(n.get_element_type()) for n in m.get_ops() if n.get_type_name() == 'Constant'})) PY # 應該看到 '',代表權重真的是 4-bit ``` `export_openvino_int4.py` 也能轉換其他 Real-ESRGAN 權重,只要架構相同(`--stem` 改檔名): * `RealESRGAN_x4plus.pth`(本 repo 使用,num_feat=64 / num_block=23 / num_grow_ch=32) * `RealESRNet_x4plus.pth`、`RealESRGAN_x4plus_anime_6B.pth`、`RealESRGAN_x2plus.pth`(需在 `rrdbnet_arch.py` 對應調整 `scale` / `num_block` / `num_feat`) --- ## 6. 疑難排解 | 症狀 | 原因 / 解決 | |---|---| | 輸出整張有雜訊、幾乎是亂圖 | 用了 `int4`:Real-ESRGAN 對 4-bit 非常敏感,請改用 `int4-mixed` 或 `int8` | | 輸出整體偏色 / 邊緣有雜訊 | 沒有指定 `INFERENCE_PRECISION_HINT='f32'`,CPU 預設跑 bf16。用 `precision='f32'` 或 `-m int8` | | 大圖 OOM | 用 `-t 128`(或 64)分塊,`--tile-pad 16`;不要 `-t 0` | | 分塊後有接縫 | `--tile-pad` 調大到 20~32 | | 下載權重失敗 | `export HF_TOKEN=hf_xxx`(私有 repo)或先手動下載 `models/*.xml *.bin` 後用 `-m` 指定 | | 匯出時 `KeyError: 'input'` | LWC 傳入 dataset 的已知問題,script 預設不傳(`--lwc-dataset` 可開啟 AWQ / scale-estimation) | | 想改輸出的放大倍率 | `--outscale 2`(>4 會再 cubic 放大) | --- ## 7. 出處與授權 * 程式碼/權重出處:[xinntao/Real-ESRGAN](https://github.com/xinntao/Real-ESRGAN)、[XPixelGroup/BasicSR](https://github.com/XPixelGroup/BasicSR)(Apache-2.0) * `rrdbnet_arch.py` 為 BasicSR `RRDBNet` 的獨立重寫(不需安裝 BasicSR),參數名稱與官方 checkpoint 完全一致 * 量化:[OpenVINO NNCF](https://github.com/openvinotoolkit/nncf) * 本 repo 的推論程式、轉換腳本與本說明文檔為本專案新增。 * 樣品照片:NASA Kennedy Space Center(公有領域),見 `samples/eagle_4x/README.md` 的來源與授權說明 * 樣品影片:NASA/Goddard ICON 任務 ISS 氣輝畫面(公有領域),見 `samples/video_airglow/README.md` * License:Apache-2.0(見 `LICENSE`)。