๋ชฉํ
- ์ง์ง ๊ฐ์ ์๊ธ์จ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ GAN model ๋ง๋ค๊ธฐ
- 16๊ฐ ์ด๋ฏธ์ง ์ค์ 8๊ฐ ์ด์์ด ์ธ์๊ฐ๋ฅํ ์ซ์๋ฅผ ํฌํจํ๊ณ ์์ผ๋ฉด ๋๋ค.
ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ import
import tensorflow as tf
import glob
import imageio
import matplotlib.pyplot as plt
import numpy as np
import os
import PIL
from tensorflow.keras import layers
import time
MNIST dataset ๋ก๋
(train_images, train_labels), (_, _) = tf.keras.datasets.mnist.load_data()
train_images = train_images.reshape(train_images.shape[0], 28, 28, 1).astype('float32')
train_images = (train_images - 127.5) / 127.5
BUFFER_SIZE = 60000
BATCH_SIZE = 256
train_dataset = tf.data.Dataset.from_tensor_slices(train_images).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)
ํ๋ จ ์ด๋ฏธ์ง์ ํํ ๋ณํ ๋ฐ ์ ๊ทํ
- ํ๋ จ ์ด๋ฏธ์ง๋ฅผ ๋จ์ผ ์ฑ๋ ์ฐจ์(28x28x1)์ ํฌํจํ๋๋ก ๋ณํํ๋ค. MNIST ๋ฐ์ดํฐ์ ์ grayscale ์ด๋ฏ๋ก ํ๋์ ์ฑ๋์ด ํ์ํ๋ค.
- (train_images - 127.5) / 127.5 ๋ฅผ ํตํด ํฝ์ ๊ฐ์ [0, 255] ๋ฒ์์์ [-1, 1] ๋ฒ์๋ก ์ค์ผ์ผํ์ฌ ์ ๊ทํํ๋ค.
TensorFlow ๋ฐ์ดํฐ์ ์์ฑ
- tf.data.Dataset.from_tensor_slices(train_images): ํ๋ จ ์ด๋ฏธ์ง์ numpy ๋ฐฐ์ด์ tf.data.Dataset ๊ฐ์ฒด๋ก ๋ณํํ๋ค.
- shuffle(BUFFER_SIZE): ๋ฐ์ดํฐ์ ์ 60,000 (ํ๋ จ ์ด๋ฏธ์ง์ ์) ํฌ๊ธฐ์ ๋ฒํผ๋ก ์ ํํ๋ค. ์ ํ๋ง์ ํ๋ จ ์ค ๋ฐ์ดํฐ๊ฐ ์ ์์ด๋๋ก ๋์ ๋ชจ๋ธ ์ฑ๋ฅ์ ํฅ์์ํฌ ์ ์๋ค.
- batch(BATCH_SIZE): ๋ฐ์ดํฐ์ ์ 256 ํฌ๊ธฐ์ ๋ฐฐ์น๋ก ๋๋๋ค.
Generator model Architecture
๋ค์๊ณผ ๊ฐ์ architecture๋ฅผ ์ง๋ Generator ๋ชจ๋ธ์ ๋ง๋ค ๊ฒ์ด๋ค.
ํฌ๊ธฐ๊ฐ 100์ธ ์ด๊ธฐ ๋ ธ์ด์ฆ๋ก๋ถํฐ ์ต์ข 28x28x1 ํฌ๊ธฐ์ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ฉด ๋๋ค.
def make_generator_model():
model = tf.keras.Sequential()
model.add(layers.Dense(7*7*256, 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) # ๋ชจ๋ธ์ด 7x7x256 ํฌ๊ธฐ์ ์ถ๋ ฅ์ ๋ด๋๋๋ก ๊ฒ์ฆ
model.add(layers.Conv2DTranspose(
filters=128, # ํํฐ ์
kernel_size=(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(
filters=64, # ํํฐ ์
kernel_size=(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(
filters=1, # ํํฐ ์
kernel_size=(5, 5), # ์ปค๋ ํฌ๊ธฐ
strides=(2, 2), # ์คํธ๋ผ์ด๋
padding='SAME', # ํจ๋ฉ ๋ฐฉ์
))
return model
- Dense layer ์ input_shape ๋ (ํ,์ด,์ฑ๋) ์์๋๋ก ๋ง์ถ์ด ๋ฃ์ด์ค๋ค. ์์ฑ๋๋ noise ๋ ์ดํฌ๊ธฐ๊ฐ 100์ด๋ฏ๋ก (100, ) ์ผ๋ก ํ๊ธฐํด์ค๋ค.
- n x n ํฌ๊ธฐ์ Conv layer ๋ฅผ ์ ์ฉํ๊ธฐ ์ํด์๋ Dense layer ๋ฅผ ๊ฑฐ์ณ 1์ฐจ์ ํํ์ธ ์ ๋ ฅ๊ฐ์ n x n ์ด์์ผ๋ก reshape ํด์ฃผ์ด์ผํ๋ค.
Dense layer ์ ํฌ๊ธฐ๋ฅผ ๊ณ ๋ คํ์ฌ ์ ์ ํ 7x7x256 ๋ก reshape ํด์ค๋ค.
- Conv2DTranspose ๋ ์ด์ด๋ ์ ๋ ฅ์ ์ ์ํ๋งํ์ฌ ์ถ๋ ฅ์ ์์ฑํ๋ค. ๋ฐ๋ผ์ ์คํธ๋ผ์ด๋ ๋งํผ ์ ๋ ฅ ํฌ๊ธฐ๊ฐ ๋ฐฐ๋ก ์ ์ํ๋ง๋์ด ์ปค๋์ ์ ์ฉํ์ฌ ์ถ๋ ฅ์ด ์์ฑ๋๋ค.
ex) 7x7x128 ์ธ ์ ๋ ฅ ์ํ์ 2x2 strides 5x5x62 Conv layer ์ ๋ฃ์ผ๋ฉด ์คํธ๋ผ์ด๋๊ฐ (2, 2)๋ก ์ค์ ๋์ด ์์ผ๋ฏ๋ก ์ถ๋ ฅ์ ๋์ด์ ๋๋น๋ ์ ๋ ฅ์ 2๋ฐฐ๊ฐ ๋์ด ๊ฒฐ๊ณผ๋ 14x14x62 ๊ฐ ๋๋ค.
Image generated from the untrained generator
์ ๋ชจ๋ธ์ ํตํด ์ด๊ธฐ ๋ ธ์ด์ฆ๋ก๋ถํฐ ๋๋คํ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ ์ ์๋ค.
generator = make_generator_model()
noise = tf.random.normal([1, 100])
generated_image = generator(noise, training=False)
plt.imshow(generated_image[0, :, :, 0], cmap='gray')
(์์ง ํ๋ จ์ด ๋์ง์์) ์์ฑ์๋ฅผ ์ด์ฉํด ์ด๋ฏธ์ง๋ฅผ ์์ฑํ ๊ฒฐ๊ณผ์ด๋ค.
Discriminator model Architecture
๋ค์๊ณผ ๊ฐ์ architecture๋ฅผ ์ง๋ Discriminator ๋ชจ๋ธ์ ๋ง๋ค ๊ฒ์ด๋ค.
Initial decision on the image
(์์ง๊น์ง ํ๋ จ์ด ๋์ง ์์) ๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ, ์์ฑ๋ ์ด๋ฏธ์ง๊ฐ ์ง์ง์ธ์ง ๊ฐ์ง์ธ์ง ํ๋ณํ๋ค. ๋ชจ๋ธ์ ์ง์ง ์ด๋ฏธ์ง์๋ ์์์ ๊ฐ (positive values)์, ๊ฐ์ง ์ด๋ฏธ์ง์๋ ์์์ ๊ฐ (negative values)์ ์ถ๋ ฅํ๋๋ก ํ๋ จ๋์ด์ง๋ค.
discriminator = make_discriminator_model()
decision = discriminator(generated_image)
print (decision)
# ๊ฒฐ๊ณผ : tf.Tensor([[-0.00291351]], shape=(1, 1), dtype=float32)
์์คํจ์์ ์ตํฐ๋ง์ด์ ์ ์
์ด ๋ฉ์๋๋ ํฌ๋ก์ค ์ํธ๋กํผ ์์คํจ์ (cross entropy loss)๋ฅผ ๊ณ์ฐํ๊ธฐ ์ํด ํฌํผ (helper) ํจ์๋ฅผ ๋ฐํํ๋ค.
cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)
๐ ํฌ๋ก์ค ์ํธ๋กํผ ์์คํจ์๋?
์ฃผ๋ก ๋ถ๋ฅ ๋ฌธ์ ์์ ์ฌ์ฉ๋๋ ์์ค ํจ์ ์ค ํ๋๋ก ์ ๊ฒฝ๋ง์ด ์์ธกํ ํ๋ฅ ๋ถํฌ์ ์ค์ ๋ ์ด๋ธ์ ๋ถํฌ ๊ฐ์ ์ฐจ์ด๋ฅผ ๊ณ์ฐํ์ฌ ๋ชจ๋ธ์ ํ์ต์ํค๋ ๋ฐ ์ฌ์ฉ๋๋ค.
q: ์ค์ ๋ ์ด๋ธ(0 ๋๋ 1)
p: ๋ชจ๋ธ์ด ์์ธกํ ํ๋ฅ
์๋ฅผ ๋ค์ด, ๋ชจ๋ธ์ด ๊ฐ๋ฅผ ์์ธกํ ํ๋ฅ ์ด 0.8์ด๊ณ ์ค์ ๋ก ๊ฐ์ผ ๊ฒฝ์ฐ q=1์ด๋ผ๊ณ ํ์.
์ด ๊ฒฝ์ฐ ํฌ๋ก์ค ์ํธ๋กํผ๋ ๋ค์๊ณผ ๊ฐ์ด ๊ณ์ฐ๋๋ค.
Cross-Entropy(1,0.8)=−(1⋅logโก(0.8)+(1−1)⋅logโก(1−0.8))Cross-Entropy(1,0.8)
=−(1⋅log(0.8)+(1−1)⋅log(1−0.8))
=−(1⋅(−0.223)+0⋅(−1.609))
=−(−0.223)
=0.223
์ด ๊ฐ์ ๋ชจ๋ธ์ ์์ธก์ด ์ค์ ๋ ์ด๋ธ๊ณผ ์ผ๋ง๋ ์ ์ผ์นํ๋์ง๋ฅผ ๋ํ๋ธ๋ค.
์ด ๊ฐ์ด ์์์๋ก ๋ชจ๋ธ์ ์์ธก์ด ์ค์ ์ ๊ฐ๊น๋ค๊ณ ๋ณผ ์ ์๋ค.
Discriminator์ loss function
real_output ์ discriminator๊ฐ ์ง์ง ์ด๋ฏธ์ง๋ค์ ๋ํด ํ๋ณํ ๊ฒฐ๊ณผ์ด๋ค.
ex) [-1,1,-1,1]
fake_output ์ discriminator๊ฐ ์์ฑ๋ ๊ฐ์ง ์ด๋ฏธ์ง๋ค์ ๋ํด ํ๋ณํ ๊ฒฐ๊ณผ์ด๋ค.
ex) [0.3,-0.3,1,0.1]
์ด ๋ ๊ฒฐ๊ณผ ๊ฐ์ ์ฐจ์ด๋ฅผ ๊ตฌํ๊ธฐ ์ํด์ ํฌ๋ก์ค ์ํธ๋กํผ ์์คํจ์ (cross entropy loss)๋ฅผ ์ด์ฉํด์ค๋ค.
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
์ด ๋ฉ์๋๋ ๊ฐ๋ณ์๊ฐ ๊ฐ์ง ์ด๋ฏธ์ง์์ ์ผ๋ง๋ ์ง์ง ์ด๋ฏธ์ง๋ฅผ ์ ํ๋ณํ๋์ง ์์นํํ๋ค. ์ง์ง ์ด๋ฏธ์ง์ ๋ํ ๊ฐ๋ณ์์ ์์ธก๊ณผ 1๋ก ์ด๋ฃจ์ด์ง ํ๋ ฌ์ ๋น๊ตํ๊ณ ,๊ฐ์ง (์์ฑ๋) ์ด๋ฏธ์ง์ ๋ํ ๊ฐ๋ณ์์ ์์ธก๊ณผ 0์ผ๋ก ์ด๋ฃจ์ด์ง ํ๋ ฌ์ ๋น๊ตํ๋ค. 1์ผ๋ก ์ด๋ฃจ์ด์ง ํ๋ ฌ์ ๋ง๋ค๊ธฐ ์ํด์ tf.ones_like() ํจ์๋ ์
๋ ฅ ํ
์์ ๋์ผํ ๋ชจ์(shape) ๋ฐ ๋ฐ์ดํฐ ํ์
(dtype)์ ๊ฐ๋ ๋ชจ๋ ์์๊ฐ 1๋ก ์ฑ์์ง ํ
์๋ฅผ ์์ฑํ๋ค. 0๋ํ ๋ง์ฐฌ๊ฐ์ง์ด๋ค.
1์ผ๋ก ์ด๋ฃจ์ด์ง ํ๋ ฌ๊ณผ 0์ผ๋ก ์ด๋ฃจ์ด์ง ํ๋ ฌ ๊ฐ๊ฐ์ด ์ ๋ต ๋ผ๋ฒจ ์ญํ ์ ํด์ฃผ๋ ๊ฒ์ด๋ค.
๋ฐ๋ผ์ ์ง์ง ์ด๋ฏธ์ง๋ ์ง์ง ์ด๋ฏธ์ง๋ ์์ธก๋๋๋ก ๋๊ณ , ๊ฐ์ง ์ด๋ฏธ์ง๋ ๊ฐ์ง ์ด๋ฏธ์ง๋ก ์์ธก๋๋๋ก ํ์ต๋๋ค.
๊ฒฐ๊ณผ์ ์ผ๋ก discriminator ์ ์ด loss = ์ง์ง๋ฅผ ์ง์ง๋ผ๊ณ ํ๋จํ๋ loss + ๊ฐ์ง๋ฅผ ๊ฐ์ง๋ผ๊ณ ํ๋จํ๋ loss ๊ฐ ๋๋ค.
Generator ์ loss function
Generaotr ๋ fake_output์ด ์ด ์ง์ง๋ผ๊ณ ํ๋จ๋ ์ ์๋๋ก ํ์ต๋์ด์ผํ๋ค.
๋ฐ๋ผ์ ์์ฑ์์ ์์คํจ์๋ ๊ฐ๋ณ์๋ฅผ ์ผ๋ง๋ ์ ์์๋์ง์ ๋ํด ์์นํ๋ฅผ ํ๋ค. ์ง๊ด์ ์ผ๋ก ์์ฑ์๊ฐ ์ํํ ์ํ๋๊ณ ์๋ค๋ฉด, ๊ฐ๋ณ์๋ ๊ฐ์ง ์ด๋ฏธ์ง๋ฅผ ์ง์ง (๋๋ 1)๋ก ๋ถ๋ฅ๋ฅผ ํ ๊ฒ์ ๋๋ค. ์ฌ๊ธฐ์ ์ฐ๋ฆฌ๋ ์์ฑ๋ ์ด๋ฏธ์ง์ ๋ํ ๊ฐ๋ณ์์ ๊ฒฐ์ ์ 1๋ก ์ด๋ฃจ์ด์ง ํ๋ ฌ๊ณผ ๋น๊ต๋ฅผ ํ ๊ฒ์ด๋ค.
def generator_loss(fake_output):
loss = cross_entropy(tf.ones_like(fake_output), fake_output)
return loss
Optimizer ์ ์ฉ
๊ฐ๋ณ์์ ์์ฑ์๋ ๋ฐ๋ก ํ๋ จ๋๊ธฐ ๋๋ฌธ์, ๊ฐ๋ณ์์ ์์ฑ์์ ์ตํฐ๋ง์ด์ ๋ ๋ค๋ฅด๋ค.
generator_optimizer = tf.keras.optimizers.Adam(1e-4)
discriminator_optimizer = tf.keras.optimizers.Adam(1e-4)
Training loop
ํ๋ จ ๋ฃจํ๋ ์์ฑ์๊ฐ ์ ๋ ฅ์ผ๋ก ๋๋ค์๋๋ฅผ ๋ฐ๋ ๊ฒ์ผ๋ก๋ถํฐ ์์๋๋ค. ๊ทธ ์๋๊ฐ์ ์ฌ์ฉํ์ฌ ์ด๋ฏธ์ง๋ฅผ ์์ฑํ๋ค. ๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ (ํ๋ จ ์ธํธ์์ ๊ฐ๊ณ ์จ) ์ง์ง ์ด๋ฏธ์ง์ (์์ฑ์๊ฐ ์์ฑํด๋ธ) ๊ฐ์ง์ด๋ฏธ์ง๋ฅผ ๋ถ๋ฅํ๋ค. ๊ฐ ๋ชจ๋ธ์ ์์ค์ ๊ณ์ฐํ๊ณ , ๊ทธ๋๋์ธํธ (gradients)๋ฅผ ์ฌ์ฉํด ์์ฑ์์ ๊ฐ๋ณ์๋ฅผ ์ ๋ฐ์ดํธํ๋ค.
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):
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 train(dataset, epochs):
for epoch in range(epochs):
start = time.time()
for image_batch in dataset:
train_step(image_batch)
print ('Time for epoch {} is {} sec'.format(epoch + 1, time.time()-start))
๐@tf.function
๐ฌGPT
๋ฐ์ฝ๋ ์ดํฐ๋ TensorFlow์์ ์ฑ๋ฅ์ ํฅ์์ํค๊ธฐ ์ํด ์ฌ์ฉ๋๋ ๊ธฐ๋ฅ ์ค ํ๋์ ๋๋ค. ์ด ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ํจ์์ ์ ์ฉํ๋ฉด TensorFlow์์ ํจ์๋ฅผ ๊ทธ๋ํ๋ก ๋ณํํ์ฌ ์คํ ์๋๋ฅผ ๋์ผ ์ ์์ต๋๋ค. ์ด๋ฌํ ๋ณํ ๊ณผ์ ์ ํตํด TensorFlow๋ ๊ทธ๋ํ ์คํ ์ต์ ํ ๊ธฐ๋ฒ์ ์ฌ์ฉํ์ฌ ์ฐ์ฐ์ ํจ์จ์ ์ผ๋ก ์ํํ ์ ์์ต๋๋ค.
train_step ํจ์์ @tf.function ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ ์ฉํ๋ฉด TensorFlow๋ ์ด ํจ์๋ฅผ ๊ทธ๋ํ๋ก ๋ณํํ์ฌ ์ต์ ํํฉ๋๋ค. ๊ทธ ๊ฒฐ๊ณผ, train_step ํจ์๊ฐ ํธ์ถ๋ ๋๋ง๋ค ๊ทธ๋ํ๊ฐ ๋ค์ ์์ฑ๋๋ ๊ฒ์ด ์๋๋ผ, ํ ๋ฒ ์์ฑ๋ ๊ทธ๋ํ๊ฐ ์ฌ์ฌ์ฉ๋ฉ๋๋ค. ์ด๋ ๋ฐ๋ณต์ ์ผ๋ก ํธ์ถ๋๋ ํจ์์ ์คํ ์๋๋ฅผ ํฅ์์ํค๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
๋ฐ๋ผ์ @tf.function ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ฉด TensorFlow ์ฝ๋์ ์คํ ์๋๋ฅผ ํฅ์์ํฌ ์ ์์ผ๋ฉฐ, ํนํ ๋ฐ๋ณต์ ์ผ๋ก ํธ์ถ๋๋ ํจ์์ ๋ํด ์ด์ ์ ์ป์ ์ ์์ต๋๋ค.
Do train
train(train_dataset, EPOCHS)
Final images
predictions = generator(seed, 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.png')
plt.show()
'CS > ์ธ๊ณต์ง๋ฅ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
SVM ์ ํ์ฉํ ์คํธ ๋ถ๋ฅ๊ธฐ ( Spam Classification via SVM ) (1) | 2024.10.17 |
---|---|
๋์ด๋ธ ๋ฒ ์ด์ฆ๋ฅผ ์ฌ์ฉํ ์คํธ ๋ฉ์ผ ๋ถ๋ฅ๊ธฐ (Spam Classification via Naรฏve Bayes) (3) | 2024.10.17 |
[Tensorflow keras] image generation using Stable Diffusion (0) | 2024.06.24 |
Simple Diffusion Image generate Model (0) | 2024.06.21 |
Generative Adversarial Network (1) | 2024.05.28 |