데이터 준비하기

1. 다운받은 데이터 내 PC에서 구글 드라이브에 업로드

In [0]:
from google.colab import files 

uploaded = files.upload()

for fn in uploaded.keys():
  print('User uploaded file "{name}" with length {length} bytes'.format(
      name=fn, length=len(uploaded[fn]))) 
Upload widget is only available when the cell has been executed in the current browser session. Please rerun this cell to enable.
Saving data_3000.zip to data_3000 (1).zip
User uploaded file "data_3000.zip" with length 3309996 bytes

2. 구글 드라이브와 Colab 연동

In [0]:
from google.colab import drive
drive.mount('/gdrive')
Drive already mounted at /gdrive; to attempt to forcibly remount, call drive.mount("/gdrive", force_remount=True).

3. 구글 드라이브에 업로드한 데이터 압축 풀기

In [0]:
!mkdir -p ./data_3000
!unzip data_3000.zip -d data_3000

라이브러리 읽어들이기

In [0]:
%tensorflow_version 2.x

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
import os 
from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
import numpy as np
import os
import PIL
from tensorflow.keras import layers
import time
from tensorflow.keras.utils import plot_model
from IPython import display

print(tf.__version__)
TensorFlow 2.x selected.
2.1.0

데이터 전처리

In [0]:
# 압축해제된 데이터 경로 (데이터 있는 파일 경로 입력)
src = './data_3000/'

#이미지 읽기
def img_read(src,file):
    img = cv.imread(src+file,cv.COLOR_BGR2GRAY)
    return img

#src 경로에 있는 파일 명을 저장 
files = os.listdir(src)

X = []


# 경로와 파일명을 입력으로 넣어 확인하고 
# 데이터를 -1~1사이로 정규화 하여 X 리스트 추가

for file in files:
 
    X.append((img_read(src,file)-127.5)/127.5)

# hyper parameter 설정
img_size = 56       # 이미지 사이즈
BUFFER_SIZE = 3000  # 총 이미지 갯수
BATCH_SIZE = 20     # 배치 사이즈(나눴을때 이미지 갯수에 딱 떨어지게 설정해야 함)

X_train = np.array(X)
X_train = X_train.reshape(X_train.shape[0], 56, 56, 1).astype('float32')
print('X_train Shape:',np.shape(X_train))
# 데이터 배치를 만들고 섞어줌
train_dataset = tf.data.Dataset.from_tensor_slices((X_train)).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)

# image 확인용
plt.imshow(X_train[1, :, :, 0], cmap = plt.cm.bone)
X_train Shape: (3000, 56, 56, 1)
Out[0]:
<matplotlib.image.AxesImage at 0x7f4709d01ac8>

Generator network 구성

In [0]:
def make_generator_model():
    model = tf.keras.Sequential()
   
    model.add(layers.Dense(256, use_bias=False, input_shape=(100,)))
    model.add(layers.LeakyReLU(alpha=0.2))
    model.add(layers.BatchNormalization(momentum=0.8))
    model.add(layers.Dense(512))
    model.add(layers.LeakyReLU(alpha=0.2))
    model.add(layers.BatchNormalization(momentum=0.8))
    model.add(layers.Dense(1024))
    model.add(layers.LeakyReLU(alpha=0.2))
    model.add(layers.BatchNormalization(momentum=0.8))
    model.add(layers.Dense(np.prod(56*56), activation='tanh'))
    model.add(layers.Reshape((56,56,1)))  
   
    return model
In [0]:
generator = make_generator_model()
generator.summary()
plot_model(generator, show_shapes=True)
Model: "sequential_4"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_14 (Dense)             (None, 256)               25600     
_________________________________________________________________
leaky_re_lu_10 (LeakyReLU)   (None, 256)               0         
_________________________________________________________________
batch_normalization_6 (Batch (None, 256)               1024      
_________________________________________________________________
dense_15 (Dense)             (None, 512)               131584    
_________________________________________________________________
leaky_re_lu_11 (LeakyReLU)   (None, 512)               0         
_________________________________________________________________
batch_normalization_7 (Batch (None, 512)               2048      
_________________________________________________________________
dense_16 (Dense)             (None, 1024)              525312    
_________________________________________________________________
leaky_re_lu_12 (LeakyReLU)   (None, 1024)              0         
_________________________________________________________________
batch_normalization_8 (Batch (None, 1024)              4096      
_________________________________________________________________
dense_17 (Dense)             (None, 3136)              3214400   
_________________________________________________________________
reshape_2 (Reshape)          (None, 56, 56, 1)         0         
=================================================================
Total params: 3,904,064
Trainable params: 3,900,480
Non-trainable params: 3,584
_________________________________________________________________
Out[0]:

Plotting The Noise (Fake Image)

In [0]:
# 노이즈 만들어서 generator에 넣은 후 나오는 이미지 출력 (확인용)

generator = make_generator_model()
noise = tf.random.uniform([1, 100])
generated_image = generator(noise, training=False)
plt.imshow(generated_image[0, :, :, 0], cmap='gray')
Out[0]:
<matplotlib.image.AxesImage at 0x7f4709a76550>

Discriminator network 구성

In [0]:
def make_discriminator_model():
    model = tf.keras.Sequential()
        
    model.add(layers.Flatten(input_shape=(56, 56, 1)))
    model.add(layers.Dense(512))
    model.add(layers.LeakyReLU(alpha=0.2))
    
    model.add(layers.Dense(256))
    model.add(layers.LeakyReLU(alpha=0.2))
    model.add(layers.Dense(1))
 
    return model
In [0]:
discriminator = make_discriminator_model()
discriminator.summary()
plot_model(discriminator, show_shapes=True)
Model: "sequential_6"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
flatten_2 (Flatten)          (None, 3136)              0         
_________________________________________________________________
dense_22 (Dense)             (None, 512)               1606144   
_________________________________________________________________
leaky_re_lu_16 (LeakyReLU)   (None, 512)               0         
_________________________________________________________________
dense_23 (Dense)             (None, 256)               131328    
_________________________________________________________________
leaky_re_lu_17 (LeakyReLU)   (None, 256)               0         
_________________________________________________________________
dense_24 (Dense)             (None, 1)                 257       
=================================================================
Total params: 1,737,729
Trainable params: 1,737,729
Non-trainable params: 0
_________________________________________________________________
Out[0]:
In [0]:
# image를 discriminator에 넣었을 때 판별값이 나옴 (예시. 확인용)
discriminator = make_discriminator_model()
decision = discriminator(generated_image)
print (decision)
tf.Tensor([[0.08860511]], shape=(1, 1), dtype=float32)

손실함수 정의

In [0]:
# 이 메서드는 크로스 엔트로피 손실함수 (cross entropy loss)를 계산하기 위해 헬퍼 (helper) 함수를 반환
cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)

loss 계산

In [0]:
# discriminator 손실함수 : real image를 넣었을 때 1이 나오게, fake image를 넣었을 때 0이 나오게 학습
def discriminator_loss(real_output, fake_output):
    real_loss = cross_entropy(tf.ones_like(real_output), real_output)
    fake_loss = cross_entropy(tf.zeros_like(fake_output), fake_output)
    total_loss = real_loss + fake_loss
    return total_loss
In [0]:
# generator 손실함수 : fake image를 넣었을 때 1이 나오도록 학습
def generator_loss(fake_output):
    return cross_entropy(tf.ones_like(fake_output), fake_output)

Optimizer

In [0]:
generator_optimizer = tf.keras.optimizers.Adam(1e-4)
discriminator_optimizer = tf.keras.optimizers.Adam(1e-4)
In [0]:
# hyper parameter 설정 
EPOCHS = 300
noise_dim = 100
num_examples_to_generate = 16

# 출력 용도로 random noise 생성
seed = tf.random.uniform([num_examples_to_generate, noise_dim])

Training Functions

In [0]:
# `tf.function` 이 데코레이터는 함수를 "컴파일" 한다.
@tf.function
def train_step(images):
    noise = tf.random.uniform([BATCH_SIZE, noise_dim])
    
    with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
        
        # generator에 noise 넣고 fake image 생성
        generated_images = generator(noise, training=True)
        
        # discriminator에 real image와 fake image 넣고 판별값 리턴
        real_output = discriminator(images, training=True)
        fake_output = discriminator(generated_images, training=True)

        # fake image를 discriminator가 1로 학습 하도록 업데이트
        gen_loss = generator_loss(fake_output)
        # real image loss와 fake image loss 합한 total loss 리턴
        disc_loss = discriminator_loss(real_output, fake_output)
    
    # tape에 기록하며 자동미분 실행
    gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables)
    gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables)
    
    generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables))
    discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables))
In [0]:
def train(dataset, epochs):
  for epoch in range(epochs):
    start = time.time()
    
    # 이미지 넣고 학습 실행. 
    for image_batch in dataset:
      
      train_step(image_batch)
    
    # 이미지를 50 epoch마다 출력

    if epoch % 50 == 0:
        generate_and_save_images(generator,epoch + 1,seed)
        print ('Time for epoch {} is {} sec'.format(epoch + 1, time.time()-start))
  
In [0]:
# noise 넣고 이미지 확인
def generate_and_save_images(model, epoch, test_input):
  # `training`이 False : (배치정규화를 포함하여) 모든 층들이 추론 모드로 실행됨
  predictions = model(test_input, training=False)

  fig = plt.figure(figsize=(4,4))

  for i in range(predictions.shape[0]):
      plt.subplot(4, 4, i+1)
      plt.imshow(predictions[i, :, :, 0] * 127.5 + 127.5 , cmap=plt.cm.bone )
      plt.axis('off')
  # plt.savefig('image_at_epoch_{:04d}.png'.format(epoch))
  # plt.show()

모델 훈련

In [0]:
%%time
train(train_dataset, EPOCHS)
Time for epoch 1 is 10.689568042755127 sec
Time for epoch 51 is 9.033679962158203 sec
Time for epoch 101 is 9.28628659248352 sec
Time for epoch 151 is 9.027594089508057 sec
Time for epoch 201 is 9.034952640533447 sec
Time for epoch 251 is 9.151849746704102 sec
CPU times: user 1h 22min 32s, sys: 2min 42s, total: 1h 25min 14s
Wall time: 43min 59s