Generative Adversarial Network (GAN)

monzheldΒ·2022λ…„ 4μ›” 4일
0

AIB_4-3) Deep Learning Applications

λͺ©λ‘ 보기
4/4

πŸ— Keyword




πŸ“‘ Concept


GAN(Generative Adversarial Networks)

  • GAN(Generative Adversarial Networks, 생성적 μ λŒ€ 신경망)

  • μ‹€μ œμ™€ μœ μ‚¬ν•œ 데이터λ₯Ό λ§Œλ“€μ–΄λ‚΄λŠ” 생성 λͺ¨λΈ

  • like μœ„μ‘°μ§€ν



μƒμ„±μž(Generator)

  • μ‹€μ œμ™€ λ™μΌν•œ 데이터λ₯Ό μƒμ„±ν•˜λŠ” 것이 λͺ©μ 

  • => 비지도 ν•™μŠ΅

  • μœ„μ‘°μ§€νλ²”

  • G



νŒλ³„μž(Discriminator)

  • μƒμ„±λœ 데이터가 μ§„μ§œ(Real)인지 μ•„λ‹Œμ§€(Fake) νŒλ‹¨

  • => 지도 ν•™μŠ΅

  • Fake / Real둜 ꡬ뢄
    -> 이진 λΆ„λ₯˜

  • like μ§„ν’ˆλͺ…ν’ˆ

  • 탐정

  • D



  • GAN
    => μƒμ„±μžμ™€ νŒλ³„μžκ°€ μ„œλ‘œ κ²½μŸν•˜λ©° μ„±λŠ₯을 κ°œμ„ ν•˜λŠ” λͺ¨λΈ




GAN의 λͺ©μ 

  • '뢄포'λ₯Ό λ§Œλ“œλŠ” λͺ¨λΈμ„ ν•™μŠ΅ν•˜λŠ” 것

  • 뢄포
    => λ°μ΄ν„°μ˜ ν˜•νƒœ, λΆ„μ‚°

  • ex) ν”½μ…€λ“€μ˜ 뢄포에 따라 μ½”, λˆˆμ΄λΌλŠ” 것을 인식.
    λͺ…μ•”μ΄λ‚˜ μ‚¬μ§„μ˜ 전체적인 μ±„λ„μ™€λŠ” 큰 상관 X.
    -> 뢄포λ₯Ό λ§Œλ“€μ–΄λ‚Έλ‹€λŠ” 것은, λ‹¨μˆœνžˆ 결과값을 λ„μΆœν•΄λ‚΄λŠ” ν•¨μˆ˜λ₯Ό λ§Œλ“œλŠ” 것을 λ„˜μ–΄ 'μ‹€μ œμ μΈ ν˜•νƒœ' λ₯Ό κ°–μΆ˜ 데이터λ₯Ό λ§Œλ“€μ–΄λ‚Έλ‹€λŠ” 것

  • ν•™μŠ΅μ„ 잘 마친 GAN λͺ¨λΈμ—μ„œ μƒμ„±μžλŠ” μ‹€μ œμ™€ μœ μ‚¬ν•œ 이미지λ₯Ό 생성
    ->
    νŒλ³„μžκ°€ μ‹€μ œ(Real)와 κ°€μ§œ(Fake)λ₯Ό 잘 ꡬ뢄해내지 λͺ»ν•˜κ²Œ 됨
    => Accuracy β‰ˆ\approx 0.5
    -> (이진 λΆ„λ₯˜λ‹ˆκΉŒ ν™•λ₯ μ΄ 1/2 μ΄λΌμ„œ)




GAN의 ν•™μŠ΅ 방법

GAN λͺ¨λΈμ˜ 이해와 κ΅¬ν˜„




βͺ Review


  • GAN

    • λΉ„μœ λ₯Ό λ“€μ–΄ μ„€λͺ…
    • μƒμ„±μž(Generator)λŠ” 무엇을 μž…λ ₯λ°›μ•„ 무엇을 좜λ ₯?
    • νŒλ³„μž(Discriminator)λŠ” 무엇을 μž…λ ₯λ°›μ•„ 무엇을 좜λ ₯?

  • CycleGAN

    • CycleGAN 이 κΈ°μ‘΄ Pix2Pix 에 λΉ„ν•΄ κ°–λŠ” μž₯점은?
    • μ™œ A와 Bκ°€ μˆœν™˜λ˜λŠ” ν˜•νƒœλ‘œ λͺ¨λΈμ΄ ꡬ성?




πŸ’» Code


GAN μ½”λ“œ 뢄석



Example - DCGAN(Deep Convolution GAN)


GAN을 톡해 MNIST 손글씨 데이터 생성

# ν•„μš”ν•œ 라이브러리 import
from tensorflow.keras import layers
from IPython import display

import glob
import imageio
import os
import PIL
import time

import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
# 데이터셋 뢈러였기
(train_images, train_labels), (_, _) = tf.keras.datasets.mnist.load_data()
# -> Test 데이터셋은 μ‚¬μš©ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— '_' 둜 처리
# 이미지 μ •κ·œν™”
train_images = train_images.reshape(train_images.shape[0], 28, 28, 1).astype('float32')
train_images = (train_images - 127.5) / 127.5 # 이미지λ₯Ό [-1, 1]둜 μ •κ·œν™”
# 이미지λ₯Ό [-1, 1]의 λ²”μœ„λ‘œ μ •κ·œν™”ν•˜λŠ” 이유
# -> ν™œμ„±ν™” ν•¨μˆ˜λ‘œ tanhλ₯Ό μ‚¬μš©ν•΄μ„œ. 
BUFFER_SIZE = 60000
BATCH_SIZE = 256

# 데이터 배치 생성 ν›„ μ„žκΈ°
train_dataset = tf.data.Dataset.from_tensor_slices(train_images).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)



λͺ¨λΈ ꡬ좕


μƒμ„±μž

  • Random Noise λ‘œλΆ€ν„° 이미지λ₯Ό μƒμ„±ν•˜κΈ° μœ„ν•΄ Transpose Convolution 을 μ‚¬μš©ν•΄ Upsampling μˆ˜ν–‰

  • 첫 Dense 측은 Random Noise λ₯Ό μž…λ ₯λ°›μœΌλ©° μ›ν•˜λŠ” 이미지 μ‚¬μ΄μ¦ˆμΈ 28X28 이 λ‚˜μ˜€λ„λ‘ Conv2DTransposeλ₯Ό 겹겹이 μŒ“μŒ

  • 은닉측 ν™œμ„±ν™” ν•¨μˆ˜: ReLU ν•¨μˆ˜μ˜ λ³€ν˜•μΈ LeakyReLU ν•¨μˆ˜ μ‚¬μš©

  • ν™œμ„±ν™” ν•¨μˆ˜ 이전에 배치 μ •κ·œν™”(Batch Normalization) 적용


Leaky ReLU

  • LeakyReLU ν•¨μˆ˜

    • 음의 값이 0이 μ•„λ‹ˆλΌ 음수 κ°’
    • 리킀렐루λ₯Ό μ‚¬μš©ν•œ 이유
      -> 음의 값을 ν‘œν˜„ν•˜κΈ° μœ„ν•΄

def make_generator_model():
    """
    μƒμ„±μž λͺ¨λΈ ꡬ좕 ν•¨μˆ˜
    """
    model = tf.keras.Sequential()
    model.add(layers.Dense(7*7*256, use_bias=False, input_shape=(100,)))
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU())

    model.add(layers.Reshape((7, 7, 256)))
    assert model.output_shape == (None, 7, 7, 256) # λ°°μΉ˜μ‚¬μ΄μ¦ˆλ‘œ None이 주어짐

    model.add(layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False))
    assert model.output_shape == (None, 7, 7, 128)
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU())

    model.add(layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False))
    assert model.output_shape == (None, 14, 14, 64)
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU())

    model.add(layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))
    assert model.output_shape == (None, 28, 28, 1)

    return model



νŒλ³„μž

  • ν•©μ„±κ³± 신경망(Convolutional Neural Network, CNN) 기반의 이미지 λΆ„λ₯˜κΈ°

  • 은닉측 ν™œμ„±ν™” ν•¨μˆ˜: LeakyReLU ν•¨μˆ˜

  • λ“œλ‘­μ•„μ›ƒ(Dropout) 적용


def make_discriminator_model():
    """
    νŒλ³„μž λͺ¨λΈ ꡬ좕 ν•¨μˆ˜
    """
    model = tf.keras.Sequential()
    model.add(layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same', input_shape=[28, 28, 1]))
    model.add(layers.LeakyReLU())
    model.add(layers.Dropout(0.3))

    model.add(layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same'))
    model.add(layers.LeakyReLU())
    model.add(layers.Dropout(0.3))

    model.add(layers.Flatten())
    model.add(layers.Dense(1))

    return model



μ†μ‹€ν•¨μˆ˜

  • μƒμ„±μžμ˜ μ†μ‹€ν•¨μˆ˜
    • 전체가 1인 ν–‰λ ¬κ³Ό fake_output을 λΉ„κ΅ν•΄μ„œ ꡬ함

  • νŒλ³„μžμ˜ μ†μ‹€ν•¨μˆ˜
    • real_loss와 fake_lossλ₯Ό λ”ν•œ κ°’
    • -> Real, Fake λ‘˜ λ‹€λ₯Ό κ°€μ§€λ‘œ 이진 λΆ„λ₯˜ν•˜λŠ” κ±°λΌμ„œ real_loss와 fake_lossλ₯Ό 더함
    • real_loss
      • 전체가 1인 ν–‰λ ¬κ³Ό real_output을 λΉ„κ΅ν•΄μ„œ ꡬ함
    • fake_loss
      • 전체가 0인 ν–‰λ ¬κ³Ό fake_output을 λΉ„κ΅ν•΄μ„œ ꡬ함

cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)


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
  
  
def generator_loss(fake_output):
    """
    μƒμ„±μžμ˜ μ†μ‹€ν•¨μˆ˜ 
    """
    return cross_entropy(tf.ones_like(fake_output), fake_output)
# μ˜΅ν‹°λ§ˆμ΄μ €
# -> μƒμ„±μž, νŒλ³„μž λͺ¨λ‘ Adam 적용
generator_optimizer = tf.keras.optimizers.Adam(1e-4)
discriminator_optimizer = tf.keras.optimizers.Adam(1e-4)
# λͺ¨λΈμ΄ μ €μž₯λ˜λŠ” Checkpoint μ„€μ •
checkpoint_dir = './training_checkpoints'
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
checkpoint = tf.train.Checkpoint(generator_optimizer=generator_optimizer,
                                 discriminator_optimizer=discriminator_optimizer,
                                 generator=generator,
                                 discriminator=discriminator)



ν›ˆλ ¨ 루프 지정

  1. μƒμ„±μžκ°€ μž…λ ₯으둜 Random Noise λ₯Ό μž…λ ₯λ°›μŒ
  2. μž…λ ₯받은 Random Noise λ₯Ό μ‚¬μš©ν•΄ 이미지 생성
  3. νŒλ³„μžλ₯Ό μ‚¬μš©ν•΄ Train λ°μ΄ν„°μ…‹μ˜ μ§„μ§œ 이미지와 μƒμ„±μžκ°€ λ§Œλ“€μ–΄λ‚Έ κ°€μ§œ 이미지λ₯Ό λΆ„λ₯˜
  4. 각 λͺ¨λΈμ˜ 손싀 계산, 경사 ν•˜κ°•λ²•κ³Ό μ—­μ „νŒŒλ₯Ό 톡해 κ°€μ€‘μΉ˜λ₯Ό μ—…λ°μ΄νŠΈ

EPOCHS = 50
noise_dim = 100
num_examples_to_generate = 16

seed = tf.random.normal([num_examples_to_generate, noise_dim])
@tf.function
def train_step(images):
    """
    Iteration λ§ˆλ‹€ μ–΄λ–»κ²Œ 각 λͺ¨λΈμ΄ κ°±μ‹ λ˜λŠ” 지에 λŒ€ν•œ ν•¨μˆ˜

    μœ„μ—μ„œ μ •μ˜ν•œ μ†μ‹€ν•¨μˆ˜λ₯Ό λ°”νƒ•μœΌλ‘œ
    Iteration(=step) λ§ˆλ‹€ κ°€μ€‘μΉ˜ κ°±μ‹ 

    Args:
        images: ν›ˆλ ¨ 데이터셋에 μžˆλŠ” μ‹€μ œ 이미지
    """
    noise = tf.random.normal([BATCH_SIZE, noise_dim])

    with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
        generated_images = generator(noise, training=True)

        real_output = discriminator(images, training=True)
        fake_output = discriminator(generated_images, training=True)

        gen_loss = generator_loss(fake_output)
        disc_loss = discriminator_loss(real_output, fake_output)

    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))
def generate_and_save_images(model, epoch, test_input):
    """
    λͺ¨λΈμ΄ 이미지λ₯Ό μƒμ„±ν•œ ν›„ μ €μž₯ν•˜λŠ” ν•¨μˆ˜
    (쀑간 κ²°κ³Ό ν™•μΈν•˜κΈ° μœ„ν•΄ μƒμ„±λœ 이미지λ₯Ό 좜λ ₯ν•˜κ³  μ €μž₯ν•˜λŠ” ν•¨μˆ˜)
    
    Args:
        model: 이미지λ₯Ό 생성할 λͺ¨λΈ
        epoch: 진행 쀑인 Epoch 숫자
        test_input: model에 μž…λ ₯λ˜λŠ” 데이터
    """

    # training=False -> λͺ¨λ“  측이 μΆ”λ‘ (inference)λͺ¨λ“œλ‘œ 진행
    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='gray')
        plt.axis('off')

    plt.savefig('image_at_epoch_{:04d}.png'.format(epoch))
    plt.show()
def train(dataset, epochs):
    """
    ν•™μŠ΅ 쀑 μ‹€ν–‰ν•  λ™μž‘μ„ ν•¨μˆ˜λ‘œ μ •μ˜
    
    Args:
        dataset: (ν›ˆλ ¨) 데이터셋
        epochs: μ΅œμ’… ν•™μŠ΅ Epoch
    """
    for epoch in range(epochs):
        start = time.time()

        for image_batch in dataset:
            train_step(image_batch)

        # 이미지λ₯Ό μƒμ„±ν•œ λ’€ μ €μž₯(좔후에 λ§Œλ“€ GIFλ₯Ό μœ„ν•¨)
        display.clear_output(wait=True)
        generate_and_save_images(generator, epoch + 1, seed)

        # 15 에포크가 지날 λ•Œλ§ˆλ‹€ λͺ¨λΈμ„ Checkpoint에 μ €μž₯
        if (epoch + 1) % 15 == 0:
            checkpoint.save(file_prefix = checkpoint_prefix)
        
        # Epoch λ§ˆλ‹€ μ†Œμš” μ‹œκ°„ 좜λ ₯
        print(f'Time for epoch {epoch + 1} is {time.time()-start} sec')

    # λ§ˆμ§€λ§‰ 에포크가 λλ‚œ ν›„ 이미지 생성
    display.clear_output(wait=True)
    generate_and_save_images(generator, epochs, seed)

# ν•¨μˆ˜λ₯Ό μ‹€ν–‰μ‹œμΌœ μ‹€μ œ ν›ˆλ ¨ 진행

%%time
train(train_dataset, EPOCHS)

# λ§ˆμ§€λ§‰ Checkpoint 볡ꡬ
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir))
# gif 생성
def display_image(epoch_no):
    """
    νŠΉμ • Epoch에 μƒμ„±λœ 이미지λ₯Ό λΆˆλŸ¬μ˜€λŠ” ν•¨μˆ˜

    Args:
        epoch_no: νŠΉμ • Epoch에 ν•΄λ‹Ήν•˜λŠ” 숫자
    """
    return PIL.Image.open('image_at_epoch_{:04d}.png'.format(epoch_no))
    
 
 display_image(EPOCHS)
# ν›ˆλ ¨ 쀑에 μ €μž₯된 이미지λ₯Ό 이어뢙여 gif μ• λ‹ˆλ©”μ΄μ…˜ λ§Œλ“€κΈ°

anim_file = 'dcgan.gif'

with imageio.get_writer(anim_file, mode='I') as writer:
    filenames = glob.glob('image*.png')
    filenames = sorted(filenames)
    last = -1
    
    for i,filename in enumerate(filenames):
        frame = 2*(i**0.5)
        if round(frame) > round(last):
            last = frame
        else:
            continue
    
        image = imageio.imread(filename)
        writer.append_data(image)
    
    image = imageio.imread(filename)
    writer.append_data(image)
    
 
import IPython
if IPython.version_info > (6,2,0,''):
  display.Image(filename=anim_file)
# μ• λ‹ˆλ©”μ΄μ…˜ λ‹€μš΄λ°›κΈ°
# -> μ½”λž©μ—μ„œλ§Œ κ°€λŠ₯

try:
    from google.colab import files
except ImportError:
    pass
else:
    files.download(anim_file)

0개의 λŒ“κΈ€