๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

CS/์ธ๊ณต์ง€๋Šฅ

[TensorFlow Keras] ์†๊ธ€์”จ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๋Š” GAN model ๋งŒ๋“ค๊ธฐ

728x90

 

 

๋ชฉํ‘œ

- ์ง„์งœ ๊ฐ™์€ ์†๊ธ€์”จ ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•˜๋Š” 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')

 

(์•„์ง ํ›ˆ๋ จ์ด ๋˜์ง€์•Š์€) ์ƒ์„ฑ์ž๋ฅผ ์ด์šฉํ•ด ์ด๋ฏธ์ง€๋ฅผ ์ƒ์„ฑํ•œ ๊ฒฐ๊ณผ์ด๋‹ค.

Generator๊ฐ€ ์ƒ์„ฑํ•œ ์ด๋ฏธ์ง€

 

 

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()

 

 

GAN ์œผ๋กœ ์ƒ์„ฑํ•œ ๊ฐ€์งœ ์†๊ธ€์”จ ์ด๋ฏธ์ง€!