基本的なSRの使用プロセス

        最近、BasicSR超解像の様々なモデルを研究しているため、様々な実験を行っているうちに多くの問題が発生したので、その解決策をいくつか紹介します。例えば、今回の問題のように、入力される画像データが特に小さい場合はどうすればよいでしょうか。この記事では、モデルの使用とモデルの比較のために BasicSR を使用する際の注意点として、インストール、使用、および実装の部分的な説明のみを提供します。

 1. インストール

インストールチュートリアルはWang Xintao氏のドキュメントに記載されていますが、多くの学生は公式ドキュメントをダウンロードして読むことを好まないかもしれないので、ここでインストール手順を再記述します。これら 2 つのインストール方法の長所と短所について説明します。

BasicSR は、pytorch 深層学習フレームワークに基づいて開発されています。したがって、tensorflow しか見たことがない学生には、pytorch の API インターフェイスのドキュメント ( PyTorch ドキュメント — PyTorch 1.13 ドキュメント)を参照することをお勧めします。GPU で実行する場合は、事前にコンピュータに対応する CUDA 環境を設定する必要があります。ただし、私のコンピューターにはGPUが搭載されていないため、サーバー上で構築された環境を使用します。CUDA を設定するためのチュートリアルを Google で検索できますが、ここでは面倒ではありません。

ローカル クローン コードのインストール (複数のモデルをローカルでテストし、ソース コードを研究および変更したい学生に推奨)

1. プロジェクトのクローンを作成します:
        git clone https://github.com/XPixelGroup/BasicSR.git

2. 依存関係パッケージをインストールします。

        この環境の依存パッケージのバージョン要件は、requirements.txt にコンパイルされています。

cd BasicSR
pip install -r requirements.txt

3. BasicSR のルート ディレクトリに BasicSR をインストールします。

python setup.py develop

インストール中に CUDA パスを指定する場合は、次のコマンドを使用できます (もちろん、プログラムの実行中に手動で指定することもできるため、この手順はオプションです)。

CUDA_HOME=/usr/local/cuda \
CUDNN_INCLUDE_DIR=/usr/local/cuda \
CUDNN_LIB_DIR=/usr/local/cuda \
python setup.py develop

pip経由でインストール

pip を使用して BasicSR をインストールするには、ターミナルで次のコマンドを実行するだけです。

pip install basicsr

インストール中に CUDA パスを指定する場合は、次のコマンドを使用できます。

CUDA_HOME=/usr/local/cuda \
CUDNN_INCLUDE_DIR=/usr/local/cuda \
CUDNN_LIB_DIR=/usr/local/cuda \
pip install basicsr

BasicSR が正常にインストールされていることを確認します

 この時点でエラーが報告されない場合は、BasicSR が正常にインストールされたことを意味し、BasicSR に基づいて開発できるようになります~~~

 2. カタログの基本的な解釈

王欣濤が書いたこの部分は非常に詳細です。ここでは、ここ数日の私の理解と使用状況をもとに、皆さんが使用する際に注意すべき点を記載します。

赤は、実験の実行に直接関連するファイル、つまり、通常最も頻繁に扱うファイルを示します。

青は、 BasicSR に強く関連する他のコード ファイルを示します。

黒はプロフィールを表します。

BasicSR リポジトリでは、コア コードは Basicsr フォルダーにあります。この部分には主に、ネットワーク構造、損失関数、データ読み込みなど、深層学習モデルで一般的に使用されるコード ファイルが含まれています。具体的なディレクトリは次のとおりです。

このうち、赤色は開発中に主に修正したファイルを示します。

 

(なぜですか? ここで注意してください。なぜなら、上記の赤いファイルは確かに変更できる場所ですが、そのコードには画像のサイズに関する厳しい要件があります。そのため、変更するときは注意する必要があります。必ず変更してください。注意してください。したがって、変更するときは注意してください! )

データの前処理やインジケーターの計算など、アルゴリズムの設計と開発にもいくつかのスクリプトが必要となるため、関連するファイルはスクリプト内に配置されており、ディレクトリは次のとおりです。

 上記のスクリプトは基本的にデータの準備であり、データと多くのデータ モデルをダウンロードできます。しかし、問題の 1 つは、事前トレーニングされたデータ モデルの一部が中国ではアクセスできない可能性があることです。壁を乗り越える必要があるので、他のリソースを見つける必要があります。

ただし、このスクリプトには実際に対処したい問題を解決できない問題が多数含まれている可能性があるため、処理段階のデータ スクリプトを自分で作成することができます。

3. データの前処理

今回使用した画像は小さすぎたので、ここで彼のESRGAN超解像度モデルを直接使用するとサイズの問題が発生しました。したがって、ここでは現在の小さいサイズのデータ​​のみをサイズ変更できます。

学生の中には、「サイズを変更しても画像の精度は失われないのですか?」と言う人もいるかもしれません。はい。私も当時この問題を抱えていたので、実験してみました。ここでは、私がどのようにテストを行ったかについて簡単に説明しますので、私のアイデアを参照してください。彼の写真を拡大して使用しました

        1. バイキュービック (バイキュービック補間) は画像をスケールします (なぜバイキュービック差分を使用するのでしょうか? 便宜上、バイキュービック補間アルゴリズムを含め、その利点と欠点を以下にリストしました)

        2. cv2のresize()を使用して、1の拡大画像を拡大縮小します。

        3. PSNRとSSIMの値を比較して効果を判断します。

   

 

# 双三次插值算法    img:图像,dstH:目标图像的高 dstW: 目的图像的宽
def BiCubic_interpolation(img, dstH, dstW):
    scrH, scrW, _= img.shape
    retimg = np.zeros((dstH, dstW, 3), dtype=np.uint8)
    for i in range(dstH):
        for j in range(dstW):
            scrx = i*(scrH/dstH)
            scry = j*(scrW/dstW)
            x = math.floor(scrx)    # floor向下取整
            y = math.floor(scry)
            u = scrx-x
            v = scry-y
            tmp = 0
            for ii in range(-1, 2):
                for jj in range(-1, 2):
                    if x+ii < 0 or y+jj < 0 or x+ii >= scrH or y+jj >= scrW:
                        continue
                    tmp += img[x+ii, y+jj] * BiBubic(ii-u) * BiBubic(jj-v)
            retimg[i, j] = np.clip(tmp, 0, 255)
    return retimg

ここでは、何が最も効果的か、そして私がどのようにそれを行ったかについて簡単に説明します。王欣濤氏は人物やその他の高精細な画像を対象にこの部分を書いているため、ここで例に挙げた画像や通常の画像を使用しても問題ありません。なぜなら、彼が ESR 構成モデルで指定した構成ファイルでは、画像のトリミング サイズとして 128 が使用されているからです。なぜ彼はこんなことをするのでしょうか?提供される画像やテスト用に毎日使用する画像は一般に比較的大きな解像度を持っており、このモデルが提供するデータ セットは 2048x1024 です。問題は見つかりましたか? はい、指定されたデータは比較的大きいです。それで、彼がなぜそれをカットしたかったのかがわかります。トレーニングする場合、多くの場合、それほど大きくする必要はありません (一般的なのは 128×128 または 192×192 のトレーニング パッチです)。そのため、最初に 2K 画像をオーバーラップのある 480×480 のサブ画像ブロックに切り抜きます。次に、データローダーは、この 480×480 サブイメージ ブロックから 128×128 (ESR) または 192×192 (EDSR) のトレーニング パッチをランダムに切り出します。

上記の説明で私と同じ理解があるかもしれませんが、彼の実験を行わずに彼のプロセスを完全に理解する方法はありません。それから、それが本当に表現したいことを現地語で説明しましょう。彼の基本的な意味は、実際には、比較的大きな画像を入力するときに、ビデオ メモリに過度の負荷を与えないようにするにはどうすればよいかを表現することです。パズルのピースのように、まず彼女の画像を複数の画像に切り分けます。毎回扱うピースは 1 つだけです。切り取るということは、画像の縦と横が異なる場合があるということですよね? ? では、この問題にどう対処すればよいのでしょうか? それは、上で述べた重複部分です。したがって、それらが重なっていても問題ありません。したがって、gt_size をイメージ全体に分割しても問題ありません。次に、彼のサブ写真にも同じ戦略を使用しました。

最後の部分では、私が今直面している問題、つまり冒頭で遭遇した状況についてお話します。ところで、皆さんに警告をしておきます。入力した画像が一般的な画像サイズではなく、セグメント化された非常に小さな画像を扱う場合、サイズはわずか数 KB、ピクセルはわずか 72x28、36x63 などと小さいです。したがって、彼のモデルでは ESRGAN ネットワーク モデルを直接使用することはできませんが、実際、彼の名前から、彼が挙げた例では 2K データ セットを使用して操作していることがわかります。では、この問題にどう対処すればよいでしょうか? このパートをやる時は山を動かすくらいの気持ちでやりました!とにかく、私のデータが間違っていないなら、私はそれを変更しません。私は彼のコードを変更し、それから私は彼の Basicsr ディレクトリに行き、彼のモデルを変更します。私のサイズに適応するために、私は多くのことを変更しました. . しかし、一部の変更が成功したとしても、最終的には非常に小さな画像がいくつか残り、依然として最小の画像を達成することができませんでした。そこで、彼女のトリミング機能を削除できないかと考えました。それでまた焦ったのですが、結果は明らかで失敗でした(私は割と得意なんですが、今回実はフレームワークのTODOにもその部分の書き方があまり良くないと書かれていたので、どうすることもできませんでした)その時点で短期的には、それを変えるためのより良い方法を彼に与えてください)。その結果、横になることが多くなり、精神状態があまり良くありませんでした。ついに転機が訪れました————————最後に、メンターが私にアイデアを与えてくれて、私は突然悟りを開きました。

小さな写真の解決策: 実際、私は最初に誤解を犯していました。つまり、他人のものを自分のものに合わせて変更することを考えていましたが、実際には、考え方を変え、データセットを変更することで解決する方が簡単です。 。そこで、私は画像データを通常の画像のサイズに変更しました。これは、彼が指定した ESRGAN 設定ファイルの gt_size よりも大きいです。(この gt_size は、むやみに変更すべきではありません。その入力と畳み込みは py でハードコードされており、動的に変更されないため、ステップの 1 つで問題が非常に簡単に発生します。) その後、画像は通常の値に達します。次のステップに進むことができます。画像を拡大すると画像の精度に影響が出るのか気になりますか? 問題ありません。上記で説明したとおりです。そのため、誰もが独自の PSNR または SSIM テストに合格した後、安心して使用できます。この部分以降、データ準備フェーズが正式に完了します。

サブファイルの処理と小さな画像の処理のための彼の公式スクリプトは次のとおりです。



import cv2
import numpy as np
import os
import sys
from multiprocessing import Pool
from os import path as osp
from tqdm import tqdm

from basicsr.utils import scandir


def main():
    """A multi-thread tool to crop large images to sub-images for faster IO.
    It is used for DIV2K dataset.
    Args:
        opt (dict): Configuration dict. It contains:
        n_thread (int): Thread number.
        compression_level (int):  CV_IMWRITE_PNG_COMPRESSION from 0 to 9. A higher value means a smaller size and
            longer compression time. Use 0 for faster CPU decompression. Default: 3, same in cv2.
        input_folder (str): Path to the input folder.
        save_folder (str): Path to save folder.
        crop_size (int): Crop size.
        step (int): Step for overlapped sliding window.
        thresh_size (int): Threshold size. Patches whose size is lower than thresh_size will be dropped.
    Usage:
        For each folder, run this script.
        Typically, there are four folders to be processed for DIV2K dataset.
            * DIV2K_train_HR
            * DIV2K_train_LR_bicubic/X2
            * DIV2K_train_LR_bicubic/X3
            * DIV2K_train_LR_bicubic/X4
        After process, each sub_folder should have the same number of subimages.
        Remember to modify opt configurations according to your settings.
    """

    opt = {}
    opt['n_thread'] = 10
    opt['compression_level'] = 3

    # HR images
    opt['input_folder'] = '../../datasets/example/BSDS100'    # 数据图片的源文件
    opt['save_folder'] = '../../datasets/example/BSDS100_sub'  # 数据图片的压缩之后的文件夹
    opt['crop_size'] = 120
    opt['step'] = 240
    opt['thresh_size'] = 1
    extract_subimages(opt)




def extract_subimages(opt):
    """Crop images to subimages.
    Args:
        opt (dict): Configuration dict. It contains:
        input_folder (str): Path to the input folder.
        save_folder (str): Path to save folder.
        n_thread (int): Thread number.
    """
    input_folder = opt['input_folder']
    save_folder = opt['save_folder']
    if not osp.exists(save_folder):
        os.makedirs(save_folder)
        print(f'mkdir {save_folder} ...')
    else:
        print(f'Folder {save_folder} already exists. Exit.')
        sys.exit(1)

    img_list = list(scandir(input_folder, full_path=True))

    pbar = tqdm(total=len(img_list), unit='image', desc='Extract')
    pool = Pool(opt['n_thread'])
    for path in img_list:
        pool.apply_async(worker, args=(path, opt), callback=lambda arg: pbar.update(1))
    pool.close()
    pool.join()
    pbar.close()
    print('All processes done.')


def worker(path, opt):
    """Worker for each process.
    Args:
        path (str): Image path.
        opt (dict): Configuration dict. It contains:
        crop_size (int): Crop size.
        step (int): Step for overlapped sliding window.
        thresh_size (int): Threshold size. Patches whose size is lower than thresh_size will be dropped.
        save_folder (str): Path to save folder.
        compression_level (int): for cv2.IMWRITE_PNG_COMPRESSION.
    Returns:
        process_info (str): Process information displayed in progress bar.
    """
    crop_size = opt['crop_size']
    step = opt['step']
    thresh_size = opt['thresh_size']
    img_name, extension = osp.splitext(osp.basename(path))

    # remove the x2, x3, x4 and x8 in the filename for DIV2K
    img_name = img_name.replace('x2', '').replace('x3', '').replace('x4', '').replace('x8', '')

    img = cv2.imread(path, cv2.IMREAD_UNCHANGED)

    h, w = img.shape[0:2]
    h_space = np.arange(0, h - crop_size + 1, step)
    if h - (h_space[-1] + crop_size) > thresh_size:
        h_space = np.append(h_space, h - crop_size)
    w_space = np.arange(0, w - crop_size + 1, step)
    if w - (w_space[-1] + crop_size) > thresh_size:
        w_space = np.append(w_space, w - crop_size)

    index = 0
    for x in h_space:
        for y in w_space:
            index += 1
            cropped_img = img[x:x + crop_size, y:y + crop_size, ...]
            cropped_img = np.ascontiguousarray(cropped_img)
            cv2.imwrite(
                osp.join(opt['save_folder'], f'{img_name}_s{index:03d}{extension}'), cropped_img,
                [cv2.IMWRITE_PNG_COMPRESSION, opt['compression_level']])
    process_info = f'Processing {img_name} ...'
    return process_info


if __name__ == '__main__':
    main()

次に、小さなファイルを処理するためのサブ スクリプトを指定します。

import os
from os import path as osp
import cv2


def scandir(dir_path, suffix=None, recursive=False, full_path=False):
    """Scan a directory to find the interested files.

    Args:
        dir_path (str): Path of the directory.
        suffix (str | tuple(str), optional): File suffix that we are
            interested in. Default: None.
        recursive (bool, optional): If set to True, recursively scan the
            directory. Default: False.
        full_path (bool, optional): If set to True, include the dir_path.
            Default: False.

    Returns:
        A generator for all the interested files with relative paths.
    """

    if (suffix is not None) and not isinstance(suffix, (str, tuple)):
        raise TypeError('"suffix" must be a string or tuple of strings')

    root = dir_path

    def _scandir(dir_path, suffix, recursive):
        for entry in os.scandir(dir_path):
            if not entry.name.startswith('.') and entry.is_file():
                if full_path:
                    return_path = entry.path
                else:
                    return_path = osp.relpath(entry.path, root)

                if suffix is None:
                    yield return_path
                elif return_path.endswith(suffix):
                    yield return_path
            else:
                if recursive:
                    yield from _scandir(entry.path, suffix=suffix, recursive=recursive)
                else:
                    continue

    return _scandir(dir_path, suffix=suffix, recursive=recursive )
pnglist = list(scandir("../../datasets/example/bai_hr", full_path=True))
print(pnglist)

#读取原始图像
for i in pnglist:

    img = cv2.imread(i,1)
    x, y, p = img.shape[0:3]

    #图像向下取样
    r = cv2.pyrDown(img)
    r = cv2.pyrDown(r)
    r = cv2.resize(r, [int(y/4),int(x/4)])    # 为啥是4倍呢 因为ESRGAN的配置文件有一个scale的四倍放大 当然这个地方个人可以根据实际的需求处理 此处的参数并不会影响程序运行

    cv2.imwrite("../../datasets/example/bai_hr_sub/" + str(i).split("/")[-1], r)

 4. トレーニング モデル全体を実行する

        実際、単純なトレーニングやモデルの比較では、基本的にこれで十分ですが、モデルを変更したくない場合、または彼の文章が十分に完璧ではないと感じる場合は、フレームワークの改善を続けたいと考えます。実際、準備は完了しています。次に、トレーニング モデルを直接実行できます。

トレーニング スクリプトを実行するには、フォルダーに移動する必要があります。


cd BasicSR-master

# 已经在第一步设置了cuda的或者对于自己的gpu可以自由支配的可以使用此运行命令
python3 basicsr/train.py -opt options/train/ESRGAN/train_ESRGAN_x4.yml

# 指定我们的gpu来跑训练模型
CUDA_VISIBLE_DEVICES=2 python3 basicsr/train.py -opt options/train/ESRGAN/train_ESRGAN_x4.yml

# 如果不知道自己的gpu信息可以安装一下gpustat 然后在自己的gpu中直接输入就可以看到了
pip install gpustat

 

最終的に以下の画像が表示されたらトレーニングは完了です。

 最後に、トレーニング結果が実験の下で生成されます。

 

最後に、ピーク S/N 比に基づいて効果を判断します。ピーク S/N 比はログで確認できます。ただし、彼の PSNR は私たちの評価基準と最も一致しているわけではない可能性があります。他の損失判定も考慮する必要がある。

仕上げる!

Guess you like

Origin blog.csdn.net/qq_38735174/article/details/127922798