본문 바로가기
Visual Intelligence/Generative Model

[Generative Model] GAN (MNIST)

by goatlab 2022. 12. 9.
728x90
반응형
SMALL

데이터 로드

 

import os
import numpy as np
import matplotlib.pyplot as plt
from tqdm import tqdm
from keras.layers import Input
from keras.models import Model, Sequential
from keras.layers.core import Dense, Dropout
from keras.layers import LeakyReLU
from keras.datasets import mnist
from keras.optimizers import Adam
from keras import initializers

# Keras 가 Tensorflow를 벡엔드로 사용할 수 있도록 설정
os.environ["KERAS_BACKEND"] = "tensorflow"

# 실험을 재현하고 동일한 결과를 얻을 수 있는지 확인하기 위해 seed를 설정
np.random.seed(10)

# 랜덤 노이즈 벡터의 차원을 설정
random_dim = 100

def load_minst_data():
  # 데이터를 로드
  (x_train, y_train), (x_test, y_test) = mnist.load_data()
  
  # 데이터를 -1 ~ 1 사이 값으로 normalize
  x_train = (x_train.astype(np.float32) - 127.5)/127.5
  
  # x_train의 shape를 (60000, 28, 28)에서 (60000, 784)로 바꿈
  x_train = x_train.reshape(60000, 784)
  
  return (x_train, y_train, x_test, y_test)

 

Generator

 

def get_generator(optimizer):
  generator = Sequential()
  generator.add(Dense(256, input_dim=random_dim, kernel_initializer=initializers.RandomNormal(stddev=0.02)))
  generator.add(LeakyReLU(0.2))
  generator.add(Dense(512))
  generator.add(LeakyReLU(0.2))
  generator.add(Dense(1024))
  generator.add(LeakyReLU(0.2))
  generator.add(Dense(784, activation='tanh'))
  generator.compile(loss='binary_crossentropy', optimizer=optimizer)
  
  return generator

 

Discriminator

 

def get_discriminator(optimizer):
  discriminator = Sequential()
  discriminator.add(Dense(1024, input_dim=784, kernel_initializer=initializers.RandomNormal(stddev=0.02)))
  discriminator.add(LeakyReLU(0.2))
  discriminator.add(Dropout(0.3))
  discriminator.add(Dense(512))
  discriminator.add(LeakyReLU(0.2))
  discriminator.add(Dropout(0.3))
  discriminator.add(Dense(256))
  discriminator.add(LeakyReLU(0.2))
  discriminator.add(Dropout(0.3))
  discriminator.add(Dense(1, activation='sigmoid'))
  discriminator.compile(loss='binary_crossentropy', optimizer=optimizer)
  
  return discriminator

def get_gan_network(discriminator, random_dim, generator, optimizer):
  # Generator와 Discriminator를 동시에 학습시키고 싶을 때 trainable을 False로 설정
  discriminator.trainable = False
  
  # GAN 입력 (노이즈)은 위에서 100 차원으로 설정
  gan_input = Input(shape=(random_dim,))
  
  # Generator의 결과는 이미지
  x = generator(gan_input)
  
  # Discriminator의 결과는 이미지가 진짜인지 가짜인지에 대한 확률이다.
  gan_output = discriminator(x)
  gan = Model(inputs=gan_input, outputs=gan_output)
  gan.compile(loss='binary_crossentropy', optimizer=optimizer)
  
  return gan

 

그 다음은 두 모델을 합쳐 하나의 GAN 모델을 만들어준다. 이때, 판별자 모델의 weight을 고정시켜준다. 판별자 모델의 구조는 다음과 같다. 모델을 요약하면 다음과 같다.

 

 

이진 교차 엔트로피 (binary cross entropy)를 훈련하는 동안 최소화할 손실 함수로 사용한다. 이진 교차 엔트로피는 두 개의 클래스만 있는 예측에서 계산된 확률과 진짜 확률 사이의 차이를 측정한다. 교차 엔트로피 손실이 클수록 예측이 정답 레이블과 차이가 크다.

 

# 생성된 MNIST 이미지를 보여주는 함수
def plot_generated_images(epoch, generator, examples=100, dim=(10, 10), figsize=(10, 10)):
  noise = np.random.normal(0, 1, size=[examples, random_dim])
  generated_images = generator.predict(noise)
  generated_images = generated_images.reshape(examples, 28, 28)
  plt.figure(figsize=figsize)
  
  for i in range(generated_images.shape[0]):
    plt.subplot(dim[0], dim[1], i+1)
    plt.imshow(generated_images[i], interpolation='nearest', cmap='gray_r')
    plt.axis('off')
    
  plt.tight_layout()
  plt.savefig('gan_generated_image_epoch_%d.png' % epoch)
epochs=400
batch_size=128

# train 데이터와 test 데이터를 가져옴
x_train, y_train, x_test, y_test = load_minst_data()

# train 데이터를 128 사이즈의 batch로 나눔
batch_count = x_train.shape[0] // batch_size
adam = Adam(lr=0.0002, beta_1=0.5)
generator = get_generator(adam)
discriminator = get_discriminator(adam)
gan = get_gan_network(discriminator, random_dim, generator, adam)

for e in range(1, epochs+1):
  print('-'*15, 'Epoch %d' % e, '-'*15)

  for _ in tqdm(range(batch_count)):
    # 입력으로 사용할 random 노이즈와 이미지를 가져옴
    noise = np.random.normal(0, 1, size=[batch_size, random_dim])
    image_batch = x_train[np.random.randint(0, x_train.shape[0], size=batch_size)]
    generated_images = generator.predict(noise)
    X = np.concatenate([image_batch, generated_images])
    y_dis = np.zeros(2*batch_size)
    y_dis[:batch_size] = 0.9
    
  # Discriminator를 학습
  discriminator.trainable = True
  discriminator.train_on_batch(X, y_dis)
  
  # Generator를 학습
  noise = np.random.normal(0, 1, size=[batch_size, random_dim])
  y_gen = np.ones(batch_size)
  discriminator.trainable = False
  gan.train_on_batch(noise, y_gen)
  
  if e == 1 or e % 20 == 0:
    plot_generated_images(e, generator)

728x90
반응형
LIST