한강 한강 볼 것이 많아 총 5개의 목차로 나누었습니다.
데이터 준비하기
이번에는 앞서 알아본 pix2pix 모델에 대해 직접 구현하고 실험하는 시간을 가져보려합니다.
사용할 데이터셋은 Sketch2Pokemon 이라는 데이터셋으로 아래 링크에서 다운 받을 수 있습니다.
위 출처에는 학습용 데이터셋에 830개의 이미지가 있으며, 각 (256 * 256) 크기의 이미지 쌍이 나란히 붙어 (256 * 512) 크기의 이미지로 구성되어 있습니다.
import os
data_path = "/content/drive/MyDrive/data/conditional_generation/pokemon_pix2pix_dataset/train/"
print("The number of train examples: ", len(os.listdir(data_path)))
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.figure(figsize=(20,15))
for i in range(1, 7):
f = data_path + os.listdir(data_path)[np.random.randint(800)]
img = cv2.imread(f, cv2.IMREAD_COLOR)
plt.subplot(3,2,i)
plt.imshow(img)
하나의 이미지에 포켓몬 스케치와 실제 포켓몬 이미지가 함께 포함되어 있는 것을 확인할 수 있다.
이미지를 하나만 열어서 나란히 붙어 있는 이미지의 크기를 확인해보자.
f = data_path + os.listdir(data_path)[0]
img = cv2.imread(f, cv2.IMREAD_COLOR)
print(img.shape)
(25, 512, 3)으로 확인할 수 있다.
이미지 나누기
모델 학습에 사용할 데이터를 (256, 256, 3) 크기의 2개 이미지로 분할하여 사용해야되서 아래의 코드로 이미지를 나누어봅시다.
import tensorflow as tf
def normalize(x):
x = tf.cast(x, tf.float32)
return (x/127.5) - 1
def denormalize(x):
x = (x+1)*127.5
x = x.numpy()
return x.astype(np.uint8)
def load_img(img_path):
img = tf.io.read_file(img_path)
img = tf.image.decode_image(img, 3)
w = tf.shape(img)[1] // 2
sketch = img[:, :w, :]
sketch = tf.cast(sketch, tf.float32)
colored = img[:, w:, :]
colored = tf.cast(colored, tf.float32)
return normalize(sketch), normalize(colored)
f = data_path + os.listdir(data_path)[1]
sketch, colored = load_img(f)
plt.figure(figsize=(10,7))
plt.subplot(1,2,1); plt.imshow(denormalize(sketch))
plt.subplot(1,2,2); plt.imshow(denormalize(colored))
위의 그림처럼 두 개의 이미지로 나누었다.
첫 번째 스케치를 다음 단계에서 구성할 Pix2Pix 모델에 입력하여 두 번째 그림과 같은 채색된 이미지를 생성하는 것이 이번 단계의 목표입니다.
augmentation 방법
앞서 살펴봤듯이 학습에 사용할 수 있는 데이터의 수는 800개뿐이라, 학습에 사용하는 데이터의 다양성을 높이기 위해 아래 코드와 같이 여러 augmentation 방법을 적용할 필요가 있습니다.
from tensorflow import image
from tensorflow.keras.preprocessing.image import random_rotation
@tf.function() # 빠른 텐서플로 연산을 위해 @tf.function()을 사용합니다.
def apply_augmentation(sketch, colored):
stacked = tf.concat([sketch, colored], axis=-1)
_pad = tf.constant([[30,30],[30,30],[0,0]])
if tf.random.uniform(()) < .5:
padded = tf.pad(stacked, _pad, "REFLECT")
else:
padded = tf.pad(stacked, _pad, "CONSTANT", constant_values=1.)
out = image.random_crop(padded, size=[256, 256, 6])
out = image.random_flip_left_right(out)
out = image.random_flip_up_down(out)
if tf.random.uniform(()) < .5:
degree = tf.random.uniform([], minval=1, maxval=4, dtype=tf.int32)
out = image.rot90(out, k=degree)
return out[...,:3], out[...,3:]
apply_augmentation
함수는 스케치 및 채색된 2개 이미지를 입력으로 받아 여러 가지 연산을 두 이미지에 동일하게 적용 된다.
Question
위에서 정의한 apply_augmentation 함수에 두 이미지가 입력되면 어떠한 과정을 거치는지 순서대로 살펴보자.
1. 두 이미지가 채널 축으로 연결된다. (tf.concat). 두 이미지가 각각 3채널인 경우 6채널이 된다.
2. 1.의 결과에 각 50% 확률로 Refection padding 또는 constant padding이 30픽셀의 pad width 만큼적용된다. (tf.pad)
3. 2.의 결과에서 (256,256,6) 크기를 가진 이미지를 임의로 잘라낸다. (tf.image.random_crop)
4. 3.의 결과를 50% 확률로 가로로 뒤집는다. (tf.image.random_flip_left_right)
5. 4.의 결과를 50% 확률로 세로로 뒤집는다. (tf.image.random_flip_up_down)
6. 5.의 결과를 50% 확률로 회전시킨다. (tf.image.rot90)
위와 같이 구성한 함수를 데이터에 적용해 시각화해보자.
plt.figure(figsize=(15,13))
img_n = 1
for i in range(1, 13, 2):
augmented_sketch, augmented_colored = apply_augmentation(sketch, colored)
plt.subplot(3,4,i)
plt.imshow(denormalize(augmented_sketch)); plt.title(f"Image {img_n}")
plt.subplot(3,4,i+1);
plt.imshow(denormalize(augmented_colored)); plt.title(f"Image {img_n}")
img_n += 1
매우 다양한 이미지가 생성되었다.
여기서 사용한 augmentation 방법 외에 더 많은 방법을 활용한다면 더욱더 다양한 데이터셋을 만들어 좋은 일반화 결과를 기대해 볼 수 있을 것 같다.
데이터 시각화
마지막으로 위 과정들을 학습 데이터에 적용하며, 잘 적용되었는지 하나의 이미지만 시각화하여 확인해 보자.
from tensorflow import data
def get_train(img_path):
sketch, colored = load_img(img_path)
sketch, colored = apply_augmentation(sketch, colored)
return sketch, colored
train_images = data.Dataset.list_files(data_path + "*.jpg")
train_images = train_images.map(get_train).shuffle(100).batch(4)
sample = train_images.take(1)
sample = list(sample.as_numpy_iterator())
sketch, colored = (sample[0][0]+1)*127.5, (sample[0][1]+1)*127.5
plt.figure(figsize=(10,5))
plt.subplot(1,2,1); plt.imshow(sketch[0].astype(np.uint8))
plt.subplot(1,2,2); plt.imshow(colored[0].astype(np.uint8))
다음 투고에서는 Generator을 구성하는 방법에 대해서 알아보는 시간을 가져봅시다. 😀
'인공지능' 카테고리의 다른 글
[Part3]Sketch2Pokemon-UNet Generator|Pix2Pix (0) | 2022.03.23 |
---|---|
[Part2]Sketch2Pokemon-Generator 구성하기|Pix2Pix (0) | 2022.03.23 |
배치 정규화-신경망 훈련 속도 향상|Neural Network (0) | 2022.03.23 |
[Tip]Colab 노트북 바로 열기|Github (0) | 2022.03.22 |
[Part3]난 스케치 넌 채색을... |GAN-Pix2Pix (0) | 2022.03.18 |