14.gan

GAN

GANGenerative Adversarial Network

  • 서로 대립adversarial하는 두 신경망을 경쟁시켜가며 결과물 생성 방법을 학습

GAN을 제안한 Ian Goodfellow가 논문에서 제시한 비유를 사용

  • 위조지폐범(생성자)과 경찰(구분자)로 나눈 후
  • 위조지폐범은 경찰을 취대한 속이려 하고, 경찰을 위조지폐를 최대한 감별하려 노력

이처럼 위조지폐범을 만들고 감별하려는 경쟁을 통해 서로의 능력이 바전하게 되고, 결국 위조지폐범은 진짜와 거의 구분할 수 없을 정도로
진짜 같은 위조지폐를 만듬

In [1]:
import tensorflow as tf
import numpy as np
In [3]:
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("./mnist/data/", one_hot=True)
Extracting ./mnist/data/train-images-idx3-ubyte.gz
Extracting ./mnist/data/train-labels-idx1-ubyte.gz
Extracting ./mnist/data/t10k-images-idx3-ubyte.gz
Extracting ./mnist/data/t10k-labels-idx1-ubyte.gz


setting hyper-parameter

In [4]:
total_epoch   = 100
batch_size    = 100
learning_rate = 0.0001
n_hidden      = 256
n_input       = 28*28
n_noise       = 128


  • GAN도 비지도 학습이므로 Y를 사용하지 않음
  • 구분자에 넣을 이미지가 실제 이미지와 생성한 가짜 이미지 두 개이고
  • 가짜 이미지는 노이즈에서 생성할 것이므로 노이즈를 입력할 placeholder Z를 추가
In [5]:
X = tf.placeholder(tf.float32, [None, n_input])
Z = tf.placeholder(tf.float32, [None, n_noise])


setting Generator

  • 첫 번째 가중치와 bias는 hidden layer로 출력하기 위한 변수
  • 두 번째 가중치와 bias는 export layer로 사용할 변수들
  • 두 번째 가중치의 변수 크기는 실제 이미지 크기와 같아야 함
In [6]:
with tf.name_scope("Generator_W1"):
    G_W1 = tf.Variable(tf.random_normal([n_noise, n_hidden], stddev=0.01))
    
with tf.name_scope("Generator_b1"):
    G_b1 = tf.Variable(tf.zeros([n_hidden]))
    
with tf.name_scope("Generator_W2"):
    G_W2 = tf.Variable(tf.random_normal([n_hidden, n_input], stddev=0.01))
    
with tf.name_scope("Generator_b2"):
    G_b2 = tf.Variable(tf.zeros([n_input]))


setting discriminator

  • hidden layer는 Generrator와 동일하게 구성
  • discriminator는 진짜와 얼마나 가까운지를 판단하는 값으로 0~1사이의 값을 구성
  • 출력값은 하나의 scalar

    • 실제 이미지를 판별하는 구분자 신경망과 생성한 이미지를 판별하는 구분자 신경망은 같은 변수를 사용해야함
    • 같은 신경망으로 구분을 시켜와 진짜 이미지와 가짜 이미지를 구변하는 특징들을 잡아낼 수 있기 때문
In [7]:
with tf.name_scope("discriminator_W1"):
    D_W1 = tf.Variable(tf.random_normal([n_input, n_hidden], stddev=0.01))
    
with tf.name_scope("discriminator_b1"):
    D_b1 = tf.Variable(tf.zeros([n_hidden]))
    
with tf.name_scope("discriminator_W2"):
    D_W2 = tf.Variable(tf.random_normal([n_hidden, 1], stddev=0.01))
    
with tf.name_scope("discriminator_b2"):
    D_b2 = tf.Variable(tf.zeros([1]))


setting neural network

In [8]:
def generator(noise_z):
    hidden = tf.nn.relu(tf.add(tf.matmul(noise_z, G_W1), G_b1))
    output = tf.nn.sigmoid(tf.add(tf.matmul(hidden, G_W2), G_b2))
    
    return output

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

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


noiseZ를 이용해 가짜 이미지를 만들 생성자 G를 만들고 이 G가 만든 가짜 이미지와 진짜 이미지 X를 각각 구분자에 넣어 입력한 이미지가 진짜인지를 판별

In [9]:
G = generator(Z)
D_gene = discriminator(G)
D_real = discriminator(X)


cost

  • cost는 2개가 필요
  • 생성자가 만든 이미지를 구분자가 가짜라고 판단하도록 하는 손실값(경찰 학습용)
  • 진짜라고 판단하도록 하는 손실값(위조지폐범 학습용)

  • 경찰을 학습시키려면 진짜 이미지 판별값 D_real은 1에 가까워야 하고(진짜라고 판별)
  • 가짜 이미지 판별값 D_gene는 0에 가까워야함(가짜라고 판별)
In [10]:
with tf.name_scope("cost"):
    loss_D = tf.reduce_mean(tf.log(D_real) + tf.log(1-D_gene)) # 경찰, 높아야함
    loss_G = tf.reduce_mean(tf.log(D_gene)) # 위조지폐범, 높아야함
    
    tf.summary.scalar("loss_D", loss_D)
    tf.summary.scalar("loss_G", loss_G)


training

  • loss_D를 구할 때는 구분자 신경망에 사용되는 변수들만 사용
  • loss_G를 구할 때는 생성자 신경망에 사용되는 변수들만 사용


  • loss_D를 학습할 때는 생성자가 변하지 않고, loss_G를 학습할때는 구분자가 변하지 않기 때문
In [11]:
D_var_list = [D_W1, D_b1, D_W2, D_b2]
G_var_list = [G_W1, G_b1, G_W2, G_b2]


논문에 의하면 loss를 최대화 해야하지만, minize에 -를 붙여 최대화

In [12]:
train_D = tf.train.AdamOptimizer(learning_rate).minimize(-loss_D, var_list=D_var_list)
train_G = tf.train.AdamOptimizer(learning_rate).minimize(-loss_G, var_list=G_var_list)
In [13]:
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)

merge = tf.summary.merge_all()
writer = tf.summary.FileWriter("./logs/mnist_gan", sess.graph)

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


  • session 설정과 minibatch를 위한 코드를 만들고 loss_D와 loss_G의 결과값을 받을 변수를 지정
  • 구분자는 X값을, 생성자는 노이즈인 Z값을 받으므로 노이즈를 생성해주는 get_noise 함수를 통해 배치 크기만큼 노이즈를 만들고 이를 입력
  • 그리고 구분자와 생성자 신경망을 학습
In [14]:
import matplotlib.pyplot as plt
plt.rcParams["axes.unicode_minus"] = False

loss_val_D_list = []
loss_val_G_list = []
In [15]:
for epoch in range(total_epoch):
    for i in range(total_batch):
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)
        noise = get_noise(batch_size, n_noise)
        
        _, loss_val_D = sess.run([train_D, loss_D], feed_dict={X: batch_xs, Z: noise})
        _, loss_val_G = sess.run([train_G, loss_G], feed_dict={Z: noise})
        
        tot_loss_val_D += -loss_val_D
        tot_loss_val_G += -loss_val_G
        loss_val_D_list.append(tot_loss_val_D)
        loss_val_G_list.append(tot_loss_val_G)
    
    if epoch == 0 or epoch % 20 == 19:
        print("Epoch: {}\tlossD: {:0.4f}\tlossG: {:0.4f}".format(epoch+1, 
                                                                     loss_val_D, 
                                                                     loss_val_G))
    
    if epoch ==0 or (epoch+1) % 20 == 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.show()
        
# plt.show()        
print("\n optimization complete!")
Epoch: 1	lossD: -0.8597	lossG: -1.5412
Epoch: 20	lossD: -0.3039	lossG: -2.4034
Epoch: 40	lossD: -0.5556	lossG: -2.1424
Epoch: 60	lossD: -0.6952	lossG: -2.2227
Epoch: 80	lossD: -0.4060	lossG: -2.4146
Epoch: 100	lossD: -0.4189	lossG: -2.3728
 optimization complete!
In [16]:
_, axe = plt.subplots(1, 2, figsize=(15, 5))
axe[0].set_title("loss_D")
axe[1].set_title("loss_G")
axe[0].plot(loss_val_D_list)
axe[1].plot(loss_val_G_list)
Out[16]:
[<matplotlib.lines.Line2D at 0x7fbf43950eb8>]
In [17]:
import jptensor as jp
tf_graph = tf.get_default_graph().as_graph_def()
jp.show_graph(tf_graph)
In [18]:
from IPython.core.display import HTML, display
display(HTML("<style> .container{width:100% !important;}</style>"))

'Deep_Learning' 카테고리의 다른 글

16.RNN_word_autoComplete  (0) 2018.12.18
15.RNN_mnist  (1) 2018.12.18
13.auto-encoder  (0) 2018.12.15
12.mnist_cnn  (0) 2018.12.12
11.mnist_matplotlib_dropout_tensorgraph  (0) 2018.12.10

+ Recent posts