잡았다요놈!

GAN(Generative Adversarial Nets) 모델은 대립하는 두개의 신경망을 서로 경쟁시켜 결과물을 생성하는 방법을 학습하게 하는 모델입니다.

“Adversarial”이란 단어의 사전적 의미를 보면 대립하는, 적대하는 란 뜻을 갖습니다. 대립하려면 어찌 되었든 상대가 있어야하니 GAN은 크게 두 부분으로 나누어져 있다는 것을 먼저 직관적으로 알 수 있습니다.



By Tim O’Shea, O’Shea Research.

Some of the generative work done in the past year or two using generative adversarial networks (GANs) has been pretty exciting and demonstrated some very impressive results. The general idea is that you train two models, one (G) to generate some sort of output example given random noise as input, and one (A) to discern generated model examples from real examples. Then, by training A to be an effective discriminator, we can stack G and A to form our GAN, freeze the weights in the adversarial part of the network, and train the generative network weights to push random noisy inputs towards the “real” example class output of the adversarial half.

Fig.00 - GAN 모델을 구성하는 개념도
[출처]: MNIST Generative Adversarial Model in Keras



1.0 점점 지능화 되가는 위조지폐범

GAN 모델을 제안한 이안 굿펠로우(Ian Goodfellow)가 논문에 제시한 비유에 의하면, 위조지폐범(생성자 신경망)과 경찰관(구분자 신경망)을 상호 대립시켜, 경찰은 감별하려고 노력하고, 위조지폐범은 위조방법을 고도화 하는 관계를 통해서 진짜와 구분하기 어려운 고도의 위조지폐를 만들수 있도록 학습 하게 하는 것 입니다.

Fig.00 - GAN 모델을 구성하는 개념도
[출처]: MNIST Generative Adversarial Model in Keras



2.0 MNIST 를 이용한 GAN모델 작성

  • 처음에는 의미를 알 수 없는 노이즈를 발생 시키지만
  • 학습의 단계를 거치면서, 점점 위조모방이 구체화 되어 가는 것을 볼 수 있다.
Fig.01 - 처음 제너레이터는 아무거나, 막던져보는 식.. 그냥, 노이즈 일 뿐!
Fig.02 - 이터레이션이 반복될 수록 모방은 점점 정교해진다.
Fig.03 - 상당히 정교해 졌다.. 이제 겨우 300번 반복 학습
Fig.04 - 이미 1,000회를 넘었을때 정교화 과정은 끝났다.



3.0 원본 EXAMPLE 과 위조 결과물 비교

  • 사실, 여기서 보여주는 손글씨는 MNIST 에 없는 전혀 새로운 모방된 손글씨 데이터다.
  • 세상에 없는 창조 된 데이터!
   
01.원본 이미지 02.위조 이미지



2.0 전체 모방이 진행되는 과정

  • 각, 이미지당 100회의 학습을 거쳐서 교정이 이루어 졌다
  • 약 1,000회를 넘었을때 이미 정교화 과정은 끝난듯~ (품질이 비슷)
Fig.04 - 기계학습, 피드백을 받아 손글씨를 모방하는 과정




3.0 참고자료

  1. MNIST Generative Adversarial Model in Keras
  2. Jaejun Yoo’s Playground: 초짜 대학원생이 이해하는 Generative Adversarial Nets
  3. 골빈해커의 3분 딥러닝 - 텐서플로우 맛 …. ( 한빛미디어 / 김진중 )



CODE PART.01 - 변수정의

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import os
import sys
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np

# '루트'와 '작업'디렉토리 설정 - for 스크립트런
DIRS = os.path.dirname(__file__).partition("deep_MLDL")
ROOT = DIRS[0] + DIRS[1]
sys.path.append(ROOT)

from os.path import dirname, join
WORK_DIR = join(ROOT,'_static','MNIST_data','')


from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets(WORK_DIR, one_hot=True)

# Hyper- Parameter
learning_rate = 2e-4
training_epoches = 100
batch_size = 100

n_hidden = 256
n_input = 28*28             # 784 pix. for 1 letter
n_noise = 128

# placeholder
X = tf.placeholder(tf.float32, [None, n_input])
Z = tf.placeholder(tf.float32, [None, n_noise])

G_W1 = tf.Variable(tf.random_normal([n_noise, n_hidden], stddev=0.01))
G_b1 = tf.Variable(tf.zeros([n_hidden]))

G_W2 = tf.Variable(tf.random_normal([n_hidden, n_input], stddev=0.01))
G_b2 = tf.Variable(tf.zeros([n_input]))

D_W1 = tf.Variable(tf.random_normal([n_input, n_hidden], stddev=0.01))
D_b1 = tf.Variable(tf.zeros([n_hidden]))

D_W2 = tf.Variable(tf.random_normal([n_hidden, 1], stddev=0.01))
D_b2 = tf.Variable(tf.zeros([1]))



CODE PART.0 - 함수정의

1
2
3
4
5
6
7
8
9
10
11
12
def generator(noise_z):
    hidden = tf.nn.relu(tf.matmul(noise_z, G_W1) + G_b1)
    output = tf.nn.sigmoid(tf.matmul(hidden, G_W2) + G_b2)
    return output

def discriminator(inputs):
    hidden = tf.nn.relu(tf.matmul(inputs, D_W1) + D_b1)
    output = tf.nn.sigmoid(tf.matmul(hidden, D_W2) + D_b2)
    return output

def get_noise(batch_size, n_noise):
    return np.random.normal(size=(batch_size, n_noise))



CODE PART.03 - 변수정의

1
2
3
4
5
6
7
8
9
10
11
12
G = generator(Z)
D_gene = discriminator(G)
D_real = discriminator(X)

cost_D = tf.reduce_mean(tf.log(D_real) + tf.log(1-D_gene))
cost_G = tf.reduce_mean(tf.log(D_gene))

D_var_list = [D_W1, D_b1, D_W2, D_b2]
G_var_list = [G_W1, G_b1, G_W2, G_b2]

train_D = tf.train.AdamOptimizer(learning_rate).minimize(-cost_D, var_list=D_var_list)
train_G = tf.train.AdamOptimizer(learning_rate).minimize(-cost_G, var_list=G_var_list)



CODE PART.04 - 그래프 그리기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# Draw Graph - Neural Networ training
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)

total_batch = int(mnist.train.num_examples / batch_size)
loss_val_D, loss_val_G = 0, 0

for epoch in range(training_epoches):
    for i in range(total_batch):
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)
        noise = get_noise(batch_size=batch_size, n_noise=n_noise)

    # calculate train(optimize), cost function as pair
    _, loss_val_D = sess.run([train_D, cost_D], feed_dict={X:batch_xs, Z:noise})
    _, loss_val_G = sess.run([train_G, cost_G], feed_dict={Z:noise})

    if epoch%10 == 0:
        print("Epoch:%3s ___ Cost_D: %.9f"% (epoch, loss_val_D))
        print("          ___ Cost_G: %.9f\n"% (loss_val_G))

    # Check generated image
    if epoch == 0 or (epoch+1)%10 == 0:
        sample_size = 10
        noise = get_noise(sample_size, n_noise)
        samples = sess.run(G, feed_dict={Z:noise})
        fig, ax = plt.subplots(1, sample_size, figsize=(sample_size, 1))

        for i in range(sample_size):
            ax[i].set_axis_off()
            ax[i].imshow(np.reshape(samples[i], (28, 28)))

        plt.savefig(WORK_DIR + '{}.png'.format(
            str(epoch+1).zfill(3)),
            bbox_inches = 'tight')
        plt.close(fig)

print('...optimizing finished ...')