upscaler比較　かんたんにいろんなモデルを試せるspandrelで

spandrelはチェックポイントファイル(pth)のみからpytorchモデルを復元/実行できるライブラリ。
Super Resolution のupscalerもたくさんある。Stable Diffusion WebUIで使われているやつ。

https://github.com/chaiNNer-org/spandrel

モデルはこのリポジトリとか

https://github.com/Phhofm/models?tab=readme-ov-file#released-sorted-by-new

このWebページにたくさんあります。

https://openmodeldb.info/

今回はこの256*238の画像で試します。

![handshake.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/bbe6ffa9-791e-72e1-53c0-658bd8d5af19.jpeg)

単純に4倍リサイズすると、
![handshakeのコピー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/854c48cf-0a9e-ab0b-9081-33710a5de4ec.jpeg)

**4xRealWebPhoto_v3_atd.pth 4倍** t4実行時間5秒
![hand4xRealWebPhoto_v3_atd.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/d63f6d23-ad51-fb48-126c-eb8979a30caa.png)

**4xTextures_GTAV_rgt-s.pth** t4実行時間4秒
![hand4xTextures_GTAV_rgt-s.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/0ff8cf33-bc7c-4aef-09f2-9a8017da19f0.png)

**4xRealWebPhoto_v4_drct-l.pth** t4実行時間11秒
![hand4xRealWebPhoto_v4_drct-l.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/4c6e25e0-96d8-ffc9-47b7-d6dfff28a0c9.png)

**4xRealWebPhoto_v4_dat2.pth** t4実行時間
![hand4xRealWebPhoto_v4_dat2.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/099898ad-53c7-333c-2562-38da71abe252.png)

**4xRealWebPhoto_v2_rtg_s.pth** t4実行時間6秒
![hand4xRealWebPhoto_v2_rtg_s.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/4a4c6393-6ab0-0884-4551-05c0e4b77bfd.png)

**4x_UniversalUpscalerV2-Sharp_101000_G.pth** t4実行時間0.6秒
![hand4x_UniversalUpscalerV2-Sharp_101000_G.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/000c3cfe-4d40-c015-49ae-9fd0e26d8333.png)

**4xLexicaDAT2_otf.pth** t4実行時間4秒
![hand4xLexicaDAT2_otf.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/a9c7d2f3-9ee5-882e-2d43-71cb59d1a52c.png)

**4x_foolhardy_Remacri.pth** t4実行時間0.7秒

![hand4x_foolhardy_Remacri.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/7f334f12-5ac3-e9bf-c090-1c6fe9b473cd.png)

**4x-UltraSharp.pth** t4実行時間0.6秒
![hand4x-UltraSharp.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/62b312fe-9667-aa90-196f-06ce1d6509c7.png)

**8x_NMKD-Superscale_150000_G.pth** t4実行時間1秒
![hand8x_NMKD-Superscale_150000_G.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/aa592543-6392-04c5-7d48-8398b9d27b48.png)

**4x_NMKD-Siax_200k.pth** t4実行時間0.7秒
![hand4x_NMKD-Siax_200k.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/7c49cf0c-027f-6cbc-d413-462141df9189.png)

**Swin2SR_RealworldSR_X4_64_BSRGAN_PSNR.pth** t4実行時間2秒
![handSwin2SR_RealworldSR_X4_64_BSRGAN_PSNR.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/734b9df0-2f70-dfdb-6f59-556a0598a940.png)

**4xNickelbackFS_72000_G.pth** t4実行時間0.6秒
![hand4xNickelbackFS_72000_G.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/19474c5d-a827-7a21-e5a6-fde2950b246c.png)

**4x_Valar_v1.pth** t4実行時間0.6秒
![hand4x_Valar_v1.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/5b78fa14-f93f-517a-bfbb-1f300db21f96.png)

**4xNomos8kSC.pth** t4実行時間0.6秒
![hand4xNomos8kSC.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/5dc2cd8c-e39b-b4ff-e82a-5f451c1ac4d4.png)

**4xNomos8k_span_otf_medium.pth** t4実行時間秒
![hand4xNomos8k_span_otf_medium.pth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235259/a7e6514a-f38f-4c0c-65e0-cff57458e43b.png)

# spandrelの使い方

spandrel をインストール

```shell
pip install spandrel
```

モデル初期化

```python
from spandrel import ImageModelDescriptor, ModelLoader
import torch
model_name = "your_model.pth"
# load a model from disk
model = ModelLoader().load_from_file(model_name)

# make sure it's an image to image model
assert isinstance(model, ImageModelDescriptor)

# send it to the GPU and put it in inference mode
model.cuda().eval()
```

推論と画像前処理/後処理の関数

```python
from PIL import Image
import numpy as np

def pil_image_to_torch_bgr(img: Image.Image) -> torch.Tensor:
    img = np.array(img.convert("RGB"))
    img = img[:, :, ::-1]  # flip RGB to BGR
    img = np.transpose(img, (2, 0, 1))  # HWC to CHW
    img = np.ascontiguousarray(img) / 255  # Rescale to [0, 1]
    return torch.from_numpy(img).unsqueeze(0).float().cuda()

def torch_bgr_to_pil_image(tensor: torch.Tensor) -> Image.Image:
    if tensor.ndim == 4:
        # If we're given a tensor with a batch dimension, squeeze it out
        # (but only if it's a batch of size 1).
        if tensor.shape[0] != 1:
            raise ValueError(f"{tensor.shape} does not describe a BCHW tensor")
        tensor = tensor.squeeze(0)
    assert tensor.ndim == 3, f"{tensor.shape} does not describe a CHW tensor"
    # TODO: is `tensor.float().cpu()...numpy()` the most efficient idiom?
    arr = tensor.float().cpu().clamp_(0, 1).numpy()  # clamp
    arr = 255.0 * np.moveaxis(arr, 0, 2)  # CHW to HWC, rescale
    arr = arr.round().astype(np.uint8)
    arr = arr[:, :, ::-1]  # flip BGR to RGB
    return Image.fromarray(arr, "RGB")

def process(image: torch.Tensor) -> torch.Tensor:
    with torch.no_grad():
        return model(image)
```

推論

```python
image = pil_image_to_torch_bgr(Image.open("input.jpg"))
image = process(image)
image = torch_bgr_to_pil_image(image)
image.save("output.png")
```

はい、かんたん。

🐣
****
フリーランスエンジニアです。
AIについて色々記事を書いていますのでよかったらプロフィールを見てみてください。

もし以下のようなご要望をお持ちでしたらお気軽にご相談ください。
AIサービスを開発したい、ビジネスにAIを組み込んで効率化したい、AIを使ったスマホアプリを開発したい、
ARを使ったアプリケーションを作りたい、スマホアプリを作りたいけどどこに相談したらいいかわからない…

いずれも中間コストを省いたリーズナブルな価格でお請けできます。

お仕事のご相談はこちらまで
rockyshikoku@gmail.com

機械学習やAR技術を使ったアプリケーションを作っています。
機械学習／AR関連の情報を発信しています。

[X](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
[GitHub](https://github.com/john-rocky)