Friday, December 30, 2016

번역 - Generative Adversarial Network (GAN) 설명


오랜만에 설명 자료 하나 번역합니다. 주로 http://blog.aylien.com/introduction-generative-adversarial-networks-code-tensorflow/ 를 보고 번역합니다만 적당히 편집과 내용추가가 있어서 1:1 번역은 아닙니다.

GAN?

시선을 끌기위해 예제부터 뽑아오자. 아래 예제가 GAN으로 만든 - 요즘 신문기사처럼 표현하면 "인공지능이 그린" 그림이다. 








서문

최근에 GAN: Generative Adversarial Network가 무지무지 인기를 끌고있다. GAN은 Ian Goodfellow가 https://arxiv.org/abs/1406.2661 등에서 제안한 것이다. 참고로 2014, 2015년에 Adversarial example 등 용어가 범람하면서 다소 개념이 애매한 부분이 있는데, 이는 Ian Goodfellow의 Quora답변을 참고하자. 아무튼 위대한 Yann LeCun이 꼽은 중요한 기술 1위 GAN이라는게 뭔지 한번 알아보겠다.

Discriminative vs. Generative 구별 대 생성 모델

간단하게 구별 모델과 생성 모델을 짚고 넘어가자.
  • 구별 모델은 입력-->출력의 관계를 알아내는 것이 목적이다. 즉, 조건부 확률 p(y|x)을 추정하자는 것.
  • 생성 모델은 더 일반적인 입력과 출력의 관계를 알아내려는 모델이다. 즉 p(x, y)을 추정하자는 것. p(x, y)를 알면 당연히 p(y|x)도 알아낼 수 있을 뿐만 아니라 더 재밌는 일을 할 수 있다. 예를 들어 새로운 (x, y) 데이터를 생성할 수 있고, 그래서 이름이 생성 모델이다. 더 강력한 정보를 필요로 하는 만큼 더 어렵다.

Generative Adversarial Networks


(그림 출처: https://ishmaelbelghazi.github.io 라고 나오는데 이 블로그가 사라짐..)

위의 그림이 GAN의 구조다. 간단하지요! 그야 간단히 그렸으니까 그렇고, 저기에서 보통 discriminator (구별망)와 generator (생성망)가 여러 층의 신경망로 이루어진 경우가 대부분이다. 대부분의 연구가 이미지를 다루고 있고, 그래서 두 신경망도 컨브넷인 경우가 많다. 자, 핵심은,
GAN의 핵심은,

  1. 생성망은 최대한 실제 데이터와 비슷한 데이터를 생성해내려고 하고
  2. 구별망은 열심히 그 둘을 구별하려고 한다는 것
이다. 이를 원문에서는 minimax two-player game이라고 표현했다. 

수식으로는 아래처럼 표현한다.



  • arg max D: 여기에서는 목적함수를 극대화하는 분류망 D를 찾는다
    • 첫번째 항 E[Log D(x)]은 실제 데이터 (x), 예를 들어 진짜 그림을 넣었을 때의 목적함수의 값이다. 
    • 두번째 항 E[log(1-D(g(z)))]은 가짜 데이터 (G(z)), 즉 생성망이 만들어낸 그림이 들어가있다. 그리고 arg max D인데 항 내부는 1-D(G(z))이다. 다시 말해 둘째 항의 극대화는 D(G(z))의 극소화다.
    • 결과적으로, 이 두 항의 목적함수를 이용해 
      • 진짜 그림을 넣으면 큰 값을,
      • 가짜 그림을 넣으면 작은 값을
    • ..출력하도록 구별망 D를 열심히 학습시키자는 것이다.
  • arg min G: 이 말은 목적함수를 극소화하는 생성망 G를 찾자는 이야기다.
    • G는 두번째 항에만 포함되어있다.
    • 전체 함수를 극소화하는 G는,  둘째 항을 극소화하는 G이고, 결국 D(G(z))를 극대화하는 G이다.
    • 결과적으로, 구별망을 속이는 생성망 G를 열심히 학습시켜보자는 이야기다.

코드

예제 (깃헙 저장소 원문)의 일부를 간단히 소개하겠다. 코드는 텐서플로우로 되어있다.


 def generator(input, hidden_size):  
   h0 = tf.nn.softplus(linear(input, hidden_size, 'g0'))  
   h1 = linear(h0, 1, 'g1')  
   return h1  

 def discriminator(input, hidden_size):  
   h0 = tf.tanh(linear(input, hidden_size * 2, 'd0'))  
   h1 = tf.tanh(linear(h0, hidden_size * 2, 'd1'))  
   h2 = tf.tanh(linear(h1, hidden_size * 2, 'd2'))  
   h3 = tf.sigmoid(linear(h2, 1, 'd3'))  
   return h3  


각각 생성망과 구별망이다. 여기에서 중요한 내용이 언급되었다. 생성망보다 복잡하게 구별망을 짜야한다!

사실은 아래 코드가 핵심이다.

 with tf.variable_scope('G'):  
   z = tf.placeholder(tf.float32, shape=(None, 1))  
   G = generator(z, hidden_size)  
 with tf.variable_scope('D') as scope:  
   x = tf.placeholder(tf.float32, shape=(None, 1))  
   D1 = discriminator(x, hidden_size)  
   scope.reuse_variables()  
   D2 = discriminator(G, hidden_size)  
 loss_d = tf.reduce_mean(-tf.log(D1) - tf.log(1 - D2))  
 loss_g = tf.reduce_mean(-tf.log(D2))  

아래 두 줄이 각각 구별망과 생성망에 arg max D, arg min G를 구현한 부분이다. loss를 감소하도록 학습되기 때문에 loss_d는 위에서 소개한 식과 부호가 반대다.

결과




보강

위의 영상을 보면 결과가 조금 아쉬운데, 이에 대해 https://arxiv.org/abs/1606.03498에서 해결 방법을 소개했다. 미니배치를 써라! 구별망이 한번에 여러 샘플을 보게 하라는 내용이다. 그 외에도 몇 가지 방법이 있는데 실제로 써본적이 없으므로 원문을 참고하면 된다.

그 결과는? 아래처럼 더 잘된다.




------

번역은 여기까지입니다. 우리모두 열공!

No comments:

Post a Comment