시내 이미지 해상도화 모니터

개요


이것은 Solafune에서 개최하는'시가지 초해상도화#MScup'경연의 기선이다.이 기사는 Public Score 0.790 정도의 기본선을 소개합니다.경기에 관한 상세한 상황은 홈페이지를 참조하시오.

초해상도 이미지 맵

⚠️cf. @solafune(https://solafune.com)
コンテストの参加以外を目的とした利用及び商用利用は禁止されています。 
商用利用・その他当コンテスト以外で利用したい場合はお問い合わせください。(https://solafune.com)

알고리즘 정보


이번에 사용된 알고리즘은 ESPCN 알고리즘입니다.이 알고리즘을 설명하기 위해서는 먼저 단일 이미지 초해상도에서 심층 학습을 이용하는 것을 간단하게 설명한다.

SRCNN


이 알고리즘은 이름과 같이 초해상도 작업에 CNN을 적용하는 알고리즘입니다.저해상도 이미지를 고해상도 이미지와 같은 크기로 조정해 3~5층 CNN을 통해 해상도를 높이는 알고리즘이다.

source: https://arxiv.org/pdf/1501.00092.pdf

FSRCNN


이 알고리즘은 상기 SRCNN 개발자가 고안한 것으로, SRCNN의 속도를 높이기 위해 개발됐다.SRCNN은 저해상도 이미지의 크기를 미리 조정했지만 이 부분은 속도의 병목이다.따라서 FSCNN에서는 크기를 먼저 조절하는 것이 아니라 네트워크의 마지막 층에서 디콘볼루션함으로써 해상도를 높인다.

source: https://arxiv.org/pdf/1608.00367.pdf

ESPCN


위의 FSCNN은 해상도를 높일 때 Deconvolution을 사용하지만 생성된 이미지를 보면 점박이 모양의 도안이 나타난다.이 문제를 개선하기 위해 ESPCN은 Deconvolution 대신 Sub-Pixel Convolution(Pixel Shuffle) 알고리즘을 사용합니다.

source: https://arxiv.org/pdf/1609.05158.pdf
이 Sub-Pixel Convolution은 향후 개발될 SRResnet 등의 알고리즘에 적용돼 향후 알고리즘 개발에 큰 영향을 미쳤다.

베이스라인


라이선스


게재된 프로그램은 Apache License 2.0입니다.
참고로 ESPCN도 아파치 라이센스 2.0에 공개됐다.
Copyright 2021 @Solafune

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

디렉토리 구조


┣━ train
┃  ┗━ train_*.tif
┣━ evaluation
┃  ┗━ evaluation_*.tif
┣━ output
┃  ┗━ test_*.tif
┗━ ESPCN_sample.py

개발 환경

  • PC 사양
  • CPU: Intel Core i5-6500
  • RAM: 8GB
  • GPU: Geforce GTX 1070
  • 개발 환경
  • Docker를 통해 환경을 구축했습니다.Docker file은 다음과 같습니다.
  • FROM tensorflow/tensorflow:latest-gpu
    RUN pip install Pillow
    
  • Google Colabratry에서도 동작을 확인했다.파일 경로를 변경하거나 추가하거나 Google Drive와 같은 코드를 설치해야 합니다.
  • 코드 설명


    libraries


    필요한 라이브러리 그룹을 Import로 만듭니다.
    import os
    
    os.environ["TF_FORCE_GPU_ALLOW_GROWTH"]= "true"
    
    import tensorflow as tf
    import tensorflow.keras.layers as kl
    from tensorflow.python.keras import backend as K
    import numpy as np
    from PIL import Image
    

    model


    이번에 사용된 ESPCN의 모델을 정의합니다.
    ESPCN에서는 픽셀 셔플을 사용해 샘플링을 진행하지만, 텐소플로우는 표준 탑재가 없어 자체 설치가 필요하다.
    # ESPCN
    class ESPCN(tf.keras.Model):
        def __init__(self, input_shapes):
            super().__init__()
    
            self.input_shape_lm = ( None, input_shapes[0], input_shapes[1], 3)
            self.upsampling_scale = 4
    
            self.conv_0 = kl.Conv2D(64, 5, padding="same", activation="relu", input_shape=self.input_shape_lm)
            self.conv_1 = kl.Conv2D(32, 3, padding="same", activation="relu")
            self.pixel_shuffle = Pixel_shuffler(self.upsampling_scale, input_shapes)
    
        def call(self, x):
            conv2d_0 = self.conv_0(x)
            conv2d_1 = self.conv_1(conv2d_0)
            model = self.pixel_shuffle(conv2d_1)
            return model
    
    
    # Pixel Shuffle
    class Pixel_shuffler(tf.keras.Model):
        def __init__(self, upscale, input_shape):
            super().__init__()
    				
    				self.upscale = upscale
            self.conv = kl.Conv2D(self.upscale**2 * 3, kernel_size=3, padding="same")
            self.act = kl.Activation(tf.nn.relu)
    
        # forward proc
        def call(self, x):
    
            d1 = self.conv(x)
            d2 = self.act(tf.nn.depth_to_space(d1, self.upscale))
    
            return d2
    

    배우다


    공부하는 부분이에요.
    Optimzer는 Adam을, 손실 함수는 MSE를 사용합니다.
    # 学習
    class trainer(object):
        def __init__(self, lr_shape, trained_model=""):
            self.model = ESPCN  ( lr_shape)
            self.model.compile(optimizer=tf.keras.optimizers.Adam(),
                      loss=tf.keras.losses.MeanSquaredError(),
                      metrics=[self.ssim])
    
            if trained_model != "":
              self.model.load_weights(trained_model)
    
        def train(self, lr_imgs, hr_imgs, out_path, batch_size, epochs):
    
            cp_callback = tf.keras.callbacks.ModelCheckpoint(out_path,
                                                     save_weights_only=True,
                                                     verbose=10)
            # 学習
            his = self.model.fit(lr_imgs, hr_imgs, batch_size=batch_size, epochs=epochs, callbacks=[cp_callback])
    
            print("___Training finished\n\n")
    
            # パラメータ保存
            print("___Saving parameter...")
            self.model.save_weights(out_path)
            print("___Successfully completed\n\n")
    
            return his, self.model
    
        # SSIM
        def ssim(self, h3, hr_imgs):
            return tf.image.ssim( h3, hr_imgs, max_val=1.0)
    

    데이터 읽기


    이미지 데이터를 불러옵니다.
    읽는 데이터는 학습을 위해 정규화된 것이다.
    또 데이터 증가로 교사 데이터로 상하좌우로 반전하는 이미지도 생성했다.
    # Dataset creation
    def create_dataset():
    
        print("\n___Creating a dataset...")
        prc = ['/', '-', '\\', '|']
        cnt = 0
        training_data =[]
    
        for i in range(60):
            d = "./train/"
    
            # High-resolution image
            img = Image.open(d+"train_{}_high.tif".format(i))
            flip_img = np.array(ImageOps.flip(img))
            mirror_img = np.array(ImageOps.mirror(img))
            img = np.array(img)
            img = (tf.convert_to_tensor(img, np.float32)) / 255.0
            flip_img = (tf.convert_to_tensor(flip_img, np.float32)) / 255.0
            mirror_img = (tf.convert_to_tensor( mirror_img, np.float32)) / 255.0
    
            # Low-resolution image
            low_img = Image.open(d+"train_{}_low.tif".format(i))
            low_flip_img = np.array(ImageOps.flip(low_img))
            low_mirror_img = np.array(ImageOps.mirror(low_img))
            low_img = np.array( low_img)
            low_img = (tf.convert_to_tensor( low_img, np.float32)) / 255.0
            low_flip_img = (tf.convert_to_tensor(   low_flip_img, np.float32)) / 255.0
            low_mirror_img = (tf.convert_to_tensor( low_mirror_img, np.float32)) / 255.0
    
            training_data.append([img,low_img])
            training_data.append([flip_img,low_flip_img])
            training_data.append([mirror_img,low_mirror_img])
    
            cnt += 1
    
            print("\rLoading a LR-images and HR-images...{}    ({} / {})".format(prc[cnt%4], cnt, 60), end='')
    
        print("\rLoading a LR-images and HR-images...Done    ({} / {})".format(cnt, 60), end='')
        print("\n___Successfully completed\n")
    
        random.shuffle(training_data)   
        lr_imgs = []
        hr_imgs = []
    
        for hr, lr in training_data:
          lr_imgs.append(lr)
          hr_imgs.append(hr)
    
        return np.array(lr_imgs), np.array(hr_imgs)
    

    실행


    위에서 정의한 함수류를 사용하여 실제 학습을 진행한다.
    이번 배치 처리 건수는 15건, Epoc 건수는 1천400건이다.배치 수량의 경우 환경에 따라 변경됩니다.
    # データセットの読み込み
    lr_imgs, hr_imgs = create_dataset()
    
    print("___Start training...")
    Trainer = trainer(lr_imgs[0].shape)
    his, model = Trainer.train(lr_imgs, hr_imgs, out_path="espcn_model_weight" , batch_size=15, epochs=1400)
    

    추론


    상술한 학습의 모형을 이용하여 추론을 진행하다.
    추론에 사용되는 이미지는 데이터를 읽을 때와 마찬가지로 귀일화됩니다.
    같은 추론 결과의 이미지도 귀일화되어 원시 이미지와 같은 형식으로 조정되었다.
    for i in range(40):
        d = "./evaluation/"
    
        # Low-resolution image
        img = np.array(Image.open(d+"test_{}_low.tif".format(i)))
        img = (tf.convert_to_tensor( img, np.float32)) / 255.0
        img = img[np.newaxis, :, :, :]
    
        re = model.predict(img)
        re = np.reshape(re, (1200, 1500, 3))
        re = re * 255.0
        re = np.clip(re, 0.0, 255.0)
        sr_img = Image.fromarray(np.uint8(re))
    
        sr_img.save("./output/test_{}_answer.tif".format(i))
        print("Saved ./output/test_{}_answer.tif".format(i))
    

    총결산


    이번 베이스라인은 ESPCN 알고리즘을 사용해 초해상 기술을 시도했다.
    환경에 따라 공부하는 데 몇 시간~1일 정도 걸렸다.
    이번 대회에서 사용된 고해상도 이미지의 크기가 크고 네트워크를 구축할 때 비교적 큰 메모리가 필요한 알고리즘도 많아 시도할 수 없다.
    또 손실 함수, 최적화 방법, 학습 계수 등 부분의 변경이 개선될 여지가 있을 수 있다.
    반드시 이곳의 밑바닥을 참고하여 시합에 참가하세요.
    참가는 이쪽에서 →"시가지 초해상도화#MScup"
    Japan Solafune Developers Community
    Solafune Global Developers Coomunity

    좋은 웹페이지 즐겨찾기