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에서 해결 방법을 소개했다. 미니배치를 써라! 구별망이 한번에 여러 샘플을 보게 하라는 내용이다. 그 외에도 몇 가지 방법이 있는데 실제로 써본적이 없으므로 원문을 참고하면 된다.

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




------

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

6 comments:

  1. 이해하기 쉬운 번역 감사합니다.

    ReplyDelete
  2. "두번째 항 E[log(1-D(g(z)))]은 가짜 데이터 (G(z)), 즉 생성망이 만들어낸 그림이 들어가있다. 그리고 arg max D인데 항 내부는 1-D(G(z))이다. 다시 말해 둘째 항의 극대화는 D(G(z))의 극소화다."

    이 문구에서, D가 G(Z)를 보고 이놈은 가짜야라고 판단해서 return하는 값이 0 일 텐데요. 그럴려면 D(G(z))가 극대화 되어야 하는 것 아닌가요??

    ReplyDelete
    Replies
    1. "D가 G(Z)를 보고 이놈은 가짜야라고 판단해서 return하는 값이 0 일 텐데요." : 맞습니다.
      그러므로 D(G(z))를 극소화 ([0, 1] 범위 내에서 0에 가깝게) 하는것이죠.

      Log(1-x)는 monotonically 감소 함수이므로 D(G(z))의 극소화가 Log(1-D(G(z)))의 극대화가 되구요.

      Delete
  3. This comment has been removed by the author.

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete