GAN(Generative Adversarial Networks, μμ±μ μ λ μ κ²½λ§)
μ€μ μ μ μ¬ν λ°μ΄ν°λ₯Ό λ§λ€μ΄λ΄λ μμ± λͺ¨λΈ
like μμ‘°μ§ν
μ€μ μ λμΌν λ°μ΄ν°λ₯Ό μμ±νλ κ²μ΄ λͺ©μ
=> λΉμ§λ νμ΅
μμ‘°μ§νλ²
G
μμ±λ λ°μ΄ν°κ° μ§μ§(Real
)μΈμ§ μλμ§(Fake
) νλ¨
=> μ§λ νμ΅
Fake / Realλ‘ κ΅¬λΆ
-> μ΄μ§ λΆλ₯
like μ§νλͺ ν
νμ
D
μμ±μ
μ νλ³μ
κ° μλ‘ κ²½μνλ©° μ±λ₯μ κ°μ νλ λͺ¨λΈ'λΆν¬'λ₯Ό λ§λλ λͺ¨λΈμ νμ΅νλ κ²
λΆν¬
=> λ°μ΄ν°μ νν, λΆμ°
ex) ν½μ
λ€μ λΆν¬μ λ°λΌ μ½, λμ΄λΌλ κ²μ μΈμ.
λͺ
μμ΄λ μ¬μ§μ μ 체μ μΈ μ±λμλ ν° μκ΄ X.
-> λΆν¬λ₯Ό λ§λ€μ΄λΈλ€λ κ²μ, λ¨μν κ²°κ³Όκ°μ λμΆν΄λ΄λ ν¨μλ₯Ό λ§λλ κ²μ λμ΄ 'μ€μ μ μΈ νν' λ₯Ό κ°μΆ λ°μ΄ν°λ₯Ό λ§λ€μ΄λΈλ€λ κ²
νμ΅μ μ λ§μΉ GAN λͺ¨λΈμμ μμ±μ
λ μ€μ μ μ μ¬ν μ΄λ―Έμ§λ₯Ό μμ±
->
νλ³μ
κ° μ€μ (Real)μ κ°μ§(Fake)λ₯Ό μ ꡬλΆν΄λ΄μ§ λͺ»νκ² λ¨
=> Accuracy 0.5
-> (μ΄μ§ λΆλ₯λκΉ νλ₯ μ΄ 1/2 μ΄λΌμ)
GAN λͺ¨λΈμ μ΄ν΄μ ꡬν
GAN
CycleGAN
Pix2Pix
μ λΉν΄ κ°λ μ₯μ μ?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)
μ μ©
LeakyReLU ν¨μ
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
fake_output
μ λΉκ΅ν΄μ ꡬν¨real_loss
μ fake_loss
λ₯Ό λν κ° real_loss
μ fake_loss
λ₯Ό λν¨real_loss
real_output
μ λΉκ΅ν΄μ ꡬν¨fake_loss
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)
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)