티스토리 뷰

[업데이트 2018.08.09 10:53] 


열세번째 요약할 논문은 "Generative Adversarial Nets"(http://papers.nips.cc/paper/5423-generative-adversarial-nets.pdf) 입니다. 페이스북 인공지능 연구팀의 리더이자 딥러닝 석학인 얀 르쿤(Yann LeCun) 교수는 최근 10년간 머신러닝 분야에서 가장 혁신적인 아이디어라고 이야기했다고 합니다. 2014년 발행된 해당 GAN 논문을 시작으로 최근까지 많은 GAN 논문들이 쏟아지고 있습니다. 대부분의 딥러닝 분야 논문들이 지도학습을 기반으로 연구되었던 것에 반해 GAN은 비지도학습 모델입니다. GAN이후 deep convolutional network가 적용된 DCGAN 등 CNN을 비지도학습에 적용하여 좋은 성과를 내는 논문들도 나오게 됩니다.


GAN은 Generative Adversarial Network의 약자로 두가지 약자를 통해 어떤 모델인지 유추해볼 수 있습니다. 첫째, 입력된 학습 데이터로부터 어떤 새로운 데이터를 생성(Generative)하는 모델입니다. 주어진 학습 데이터와 거의 유사한 데이터를 생성하게 하는 것이 목표입니다. 둘째, Adversarial 단어에서 알 수 있듯이 주어진 학습데이터와 유사한 데이터를 생성하기 위해 두 모델을 서로 적대적으로 경쟁시키는 모델임을 알 수 있습니다. 해당 논문의 저자인 Ian Goodfellow는 위조지폐범과 경찰을 가지고 쉽게 설명하고 있습니다. 앞서 말한 적대적으로 서로 경쟁하며, 학습을 하는 두 가지 모델은 Discriminator(이하 D)와 Generator(이하 G)입니다. 여기서 경찰이 Discriminator, 위조지폐범이 Generator로 예를 들어 설명하고 있습니다.


위조지폐범(Generator)은 위조지폐를 진짜 지폐와 구분 못할정도로 비슷하게 만들어 경찰을 최대한 속이는 것을 목표로 하며, 경찰(Discriminator)은 최대한 위조지폐를 감별하는 것 목표로 합니다. 이 두 모델이 경쟁적으로 학습을 하여 결국 진짜 지폐와 위조 지폐를 구분하지 못하는 상황에 이르게 됩니다. 


GAN의 기본 아이디어는 minimax two-player game 또는 minimax problem 입니다.. 결국 min max problem에서 최종 솔루션을 얻기 위해 논문에서는 아래와 같이 D와 G로 이루어진 value function을 정의하고 있습니다.



또한 본 논문에서는 Global Optimality(유일해 존재여부)와 Convergence(유일해를 찾기 위해 수렴하는지)를 위의 value function으로부터 수학적으로 증명하는 부분이 있는데, 나중에 추가적으로 분석해볼 예정입니다.


아래의 이미지는 NIPS 2016 Tutorial: Generative Adversarial Networks에서 D와 G의 역할에 대해 설명한 도식입니다. 먼저 D를 살펴보면 학습 데이터로부터 샘플링한 데이터 x를 입력으로 하여 미분가능한 함수 D(x) = 1이 되도록 즉, 최대한 위조지폐를 감별하도록 학습합니다. G의 경우 noise distribution을 통해 랜덤하게 샘플링한 z 데이터를 입력으로 하는 미분가능한 함수 G(z)에 대해 D(G(z)) = 1이 되도록, 즉 최대한 위조지폐를 진짜 지폐와 감별되지 않도록 학습합니다. 결국 D는 D(G(z)) = 0이 되도록,  G는 D(G(z)) = 1이 되도록 서로 경쟁하며 학습을 진행하게 되며, D(x) = 1/2이 되면서 Discriminator는 위조지폐와 진짜지폐를 구별하지 못하는 상태가 됩니다.



실제 코드로 구현시 어떤식으로 동작하는지 분석하기 위해 참고 [6] https://github.com/aymericdamien/TensorFlow-Examples/blob/master/examples/3_NeuralNetworks/gan.py의 GAN 소스 코드를 확인하였습니다. 해당 소스코드의 경우 MNIST 학습 데이터셋을 가지고 GAN을 구현하였습니다. x와 z는 아래의 코드와 같이 입력 shape로 초기화후 입력으로 받고 있습니다. shape를 보면 z의 경우 [batch size x 100]로 입력 데이터를 랜덤 초기화를 하여 사용합니다. (random uniform을 통해 초기화) x의 경우는 [batch size x 784]로 입력  데이터를 받습니다. (MNIST 데이터 28x28x1=784, 흑백이미지 이므로 channel size는 1)

image_dim = 784 # 28*28 pixels
noise_dim = 100 # Noise data points
gen_input = tf.placeholder(tf.float32, shape=[None, noise_dim], name='input_noise')
disc_input = tf.placeholder(tf.float32, shape=[None, image_dim], name='disc_input')
z = np.random.uniform(-1., 1., size=[batch_size, noise_dim])

위의 V(D,G) value function의 정의와 NIPS 2016 Tutorial: Generative Adversarial Networks에 대해 실제 코드 구현시에는 다음과 같습니다. D와 G 모델은 MLP(Multi Layer Perceptron)로 정의하며, G 모델에 입력으로 위에서 초기화 했던 z값 입력하며, D의 경우는 x 데이터에 대한 입력과 z 데이터에 대한 입력으로 구성됩니다. 


이제 이렇게 구성된 모델로부터 D와 G에 대한 loss function을 정의합니다. 


위의 설명처럼, 


1. G의 경우 D(G(z)) = 1 되도록 학습되어야 하므로, 아래와 같이 loss function을 정의합니다. disc_fake가 1이 되면 결국 log(1) = 0이므로 loss가 최소화 되도록 학습을 수행할 것임을 예상할 수 있습니다.

gen_loss = -tf.reduce_mean(tf.log(disc_fake))

2. D는 D(G(z)) = 0이 되도록, D(x) = 1이 되도록 학습해야 하므로, 아래와 같이 loss function을 정의합니다. 만약 disc_fake가 0이 되면 두번째 텀은 log(1) = 0이 되며, 첫번째 텀 또한 disc_real은 1이 될 것이므로 log(1) = 0이 나와 disc_loss가 최소화 되도록 학습을 수행할 것임을 예상할 수 있습니다.

disc_loss = -tf.reduce_mean(tf.log(disc_real) + tf.log(1. - disc_fake))

<G와 D 모델 정의 및 Loss Function 정의>

# Generator
def generator(x):
hidden_layer = tf.matmul(x, weights['gen_hidden1'])
hidden_layer = tf.add(hidden_layer, biases['gen_hidden1'])
hidden_layer = tf.nn.relu(hidden_layer)
out_layer = tf.matmul(hidden_layer, weights['gen_out'])
out_layer = tf.add(out_layer, biases['gen_out'])
out_layer = tf.nn.sigmoid(out_layer)
return out_layer


# Discriminator
def discriminator(x):
hidden_layer = tf.matmul(x, weights['disc_hidden1'])
hidden_layer = tf.add(hidden_layer, biases['disc_hidden1'])
hidden_layer = tf.nn.relu(hidden_layer)
out_layer = tf.matmul(hidden_layer, weights['disc_out'])
out_layer = tf.add(out_layer, biases['disc_out'])
out_layer = tf.nn.sigmoid(out_layer)
return out_layer
# Build Generator Network
gen_sample = generator(gen_input)

# Build 2 Discriminator Networks (one from noise input, one from generated samples)
disc_real = discriminator(disc_input)
disc_fake = discriminator(gen_sample)

# Build Loss
gen_loss = -tf.reduce_mean(tf.log(disc_fake))
disc_loss = -tf.reduce_mean(tf.log(disc_real) + tf.log(1. - disc_fake))

아래의 그림은 각 데이터셋별로 GAN 모델을 통해 생성한 이미지를 시각화 한 것입니다. 가장 오른쪽 컬럼은 학습 데이터 이미지인데, 해당 컬럼과 인접한 샘플 이미지(GAN 모델 생성)와 비교해보면 상당히 유사함을 알 수 있습니다.




 * 참고 

[1] http://papers.nips.cc/paper/5423-generative-adversarial-nets.pdf

[2] http://jaejunyoo.blogspot.com/2017/01/generative-adversarial-nets-1.html

[3] https://dreamgonfly.github.io/2018/03/17/gan-explained.html

[4] https://arxiv.org/pdf/1701.00160.pdf

[5] https://ko.wikipedia.org/wiki/%EA%B8%B0%EB%8C%93%EA%B0%92

[6] https://github.com/aymericdamien/TensorFlow-Examples/blob/master/examples/3_NeuralNetworks/gan.py

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함