본문 바로가기
AIML/GANs

[학부생의 딥러닝] GANs | DCGAN : Deep Convolutional GAN

by 하우론 2018. 6. 27.

DCGAN - Tensorflow 구현, PyTorch 구현

기본적인 개념은 Vanilla GAN과 완전히 똑같고 fully connected layer들을 Conv layer로 바꿔주기만 하면 된다. 그래서 Vanilla GAN을 구현했다면 DCGAN도 쉽게 구현할 수 있다. 다만 Generator에서 transposed convolution이라는 기법을 사용해서 이것만 유의하면 될 것 같다. 논문에는 MNIST에 사용된 DCGAN 구조가 나와있지 않아서 LSUN에 사용된 구조에서 끝 부분만 살짝 변형했다. LSUN 등 3채널 데이터셋에 활용하려면 마지막 출력 부분만 3채널로 바꿔주면 된다.

 

학습은 i5-6600, GTX 1060(6GB) ubuntu 18.04 환경에서 15분 걸렸다.

 


기본개념

기본 개념은 GAN과 별 다를게 없으니 전체 모식도와 수식만 후딱 보고 넘어가자. GAN의 기본개념이 잡히지 않았다면 여기를 보고 왔으면 좋겠다.

 

 

 

minGmaxDV(D,G)=Expdata(x)[logD(x)]+Ezpg(z)[log(1D(G(z))]

 

위 식을 최적화시키는 최적의 생성기 G를 찾는 것이 우리의 목표이다.

 

 


Transposed Convolution

이 모델을 구현하는 데에 핵심이라 할 수 있는 기법이다. 일반적인 convolution과 반대로 연산을 하면 이미지가 커진다. 특히 stride를 s를 주면 input보다 s배 큰 feature map을 얻을 수 있다. 왜 이 기법의 이름이 transposed인지, 왜 transposed를 사용 했는지 궁금할 것이다. 하지만 내용이 조금 길어서 시각화와 함께 글을 쓰는 중이다.

 


구조

위에서 말했다시피 LSUN에 사용된 구조의 출력 부분만 수정했다. G의 마지막 층과 D의 첫 번째 층에 BN을 사용하지 않은 것을 주목하자. 이유는 모르겠지만 이 두 층에 BN을 사용하지 않은 것이 효과가 더 좋다!

 

그리고 최근 GAN 계열 sota 논문들의 동향을 살펴봤을 때 G와 D가 대칭을 이루는 것도 하나의 특징이라 할 수 있겠다.

 

원래 MNIST 이미지의 크기는 28 x 28 이지만 64 x 64 로 resize 해서 넣었다. 크기는 네 배 이상 커졌지만 학습은 잘 된다.

 
 

 

 

 

Layer Discriminator Generator
input 64 x 64 x 1 1 x 1 x 100
1 4 x 4 / 2 (32 x 32 x 128), LReLU 4 x 4 / 1 (4 x 4 x 1024), BN, ReLU
2 4 x 4 / 2 (16 x 16 x 256), BN, LReLU 4 x 4 / 2 (8 x 8 x 512), BN, ReLU
3 4 x 4 / 2 (8 x 8 x 512), BN, LReLU 4 x 4 / 2 (16 x 16 x 256), BN, ReLU
4 4 x 4 / 2 (4 x 4 x 1024), BN, LReLU 4 x 4 / 2 (32 x 32 x 128), ReLU
5 4 x 4 / 1 (1 x 1 x 1), Sigmoid 4 x 4 / 2 (64 x 64 x 1), tanh

 

 

 


결과

 

epoch 1

epoch 20

epoch 1 ~ 20

중간에 심각한 mode collapsing이 일어나서 이후 생성물이 망했다.

epoch 6

하지만 이미 1 epoch에서부터 충분히 괜찮은 결과가 보였고 mode collapse 당한 이미지가 더 의미 있을 것 같아서 블로그에 가져왔다.

 


알게 된 사실들

Latent Vector Interpolation

학습을 성공적으로 시키긴 했어도 이 모델이 의미 있는 이미지를 생성하는 건지 학습하면서 본 이미지들을 외워서 보여주는 건지 알 수가 없다. 하지만 이를 간접적으로 알 수 있는 방법이 있다. G의 input인 latent vector z를 서서히 변화시켰을 때 생성되는 이미지도 서서히 변한다면 이미지의 semantic한 요소를 어느 정도 학습 했다고 받아 들일 수 있겠다.

방 안의 모양이 서서히 바뀌는 것을 확인할 수 있다.

그림을 자세히 보면 꽉 막혀 있는 침실에 서서히 대형 창문이 생기는 등 데이터셋의 특징을 잡아내면서 부드럽게 변화하는 것을 볼 수 있다. 영화에서나 잠깐잠깐 보던 영상이라 이 논문을 처음 봤을 당시에는 너무 신기해서 한참 감상했던 기억이 난다.

 

데이터와 데이터 사이의 빈 공간을 그럴싸한 값으로 채워 넣는 것을 interpolation이라 한다. 이렇게 G를 적절히 학습 시키면 latent vector를 서서히 변화시키는 것만으로도 interpolation이 가능하다.


 Latent Vector Arithmetic

interpolation 뿐만 아니라 latent vector끼리의 산술 연산도 가능하다.

각 단어를 뜻하는 이미지를 나타내는 vector를 찾아 평균을 내고 연산(좌변)한 후 나온 vector를 조금씩 interpolate(우변) 했다.

[웃는 여자 - 무표정의 여자 + 무표정의 남자]를 계산하면 뭐가 나올까? 왠지 [웃는 남자]가 나오지 않을까? 생각한 적이 있을 것이다. 실제로도 그런 것을 확인할 수 있다. 이걸 그냥 무식하게 픽셀 단위로 더하면

??

의미 없는 이미지들을 얻게 되는데 확실히 G가 단순히 이미지를 암기한 것이 아님을 확인할 수 있다. 또, 이걸 변환의 관점에서 생각해 봤을 때 생성기 G의 역변환(이 일단 존재한다고 생각하자!)은 각 축이 아무 의미를 가지지 않는 이미지 공간을 어떤 나름의 정돈되고 의미있는 축을 가지는 벡터공간으로 보내는 변환으로 볼 수도 있겠다.

 

단순한 신경망에서 시작해 점점 더 사람들이 원하는 "인공지능"에 가까워지는 것 같다.

 

 


BIAS 외 않써요?

왠지는 잘 모르겠는데 bias를 쓰면 initialize를 어떻게 하건 간에 모델이 걸레짝이 된다.

>> 해답 : BN이 bias를 상쇄시키기 때문이라고 한다. 엄밀히 말하자면 BN안에 bias가 포함되어 있다고 생각하면 되겠다.

 


tf.layers.conv2d의 Default Initializer

glorot_uniform_initializer(Xavier initializer)라고 한다. 앞으로는 그냥 None으로 놔둬도 될 것 같다.

https://stackoverflow.com/questions/43284047/what-is-the-default-kernel-initializer-in-tf-layers-conv2d-and-tf-layers-dense