삼남매 아빠=애국자
원문 주소: GAN by Example using Keras on Tensorflow Backend
생성적 적대 신경망(Generative Adversarial Networks, 이하 GAN)은 딥러닝에서 최근 개발되고 있는 가장 유망한 것 중 하나입니다. 2014년에 이안 굿펠로우(Ian Goodfellow)가 소개한 GAN은, 서로 경쟁과 협력을 병행하는 생성자(Generator)와 식별자(Discriminator)로 불려지는 두 개의 딥 네트워크를 훈련시켜 비지도학습(unsupervised learning) 방식으로 문제를 풀어나가는 방식입니다. 훈련 과정에서 두개의 네트워크는 최종적으로 그들이 과제를 어떻게 수행할지 학습하게 됩니다.
GAN은 대체로 위조지폐범(생성자)과 경찰(식별자)로 설명됩니다.
초기에 위조지폐범은 경찰에게 위조지폐를 보여줍니다. 그리고, 경찰은 그것을 위조지폐라고 식별합니다.
경찰의 피드백은 위조지폐범에게 그게 왜 위조지폐라고 식별했는지를 알려줍니다.
위조지폐범은 피드백을 반영한 새로운 위조지폐를 만들어냅니다. 경찰은 위조지폐범에게 그게 위조지폐라고 판단하게된 새로운 피드백을 전달합니다.
위조지폐범은 최종 피드백을 근간으로 새로운 위조지폐를 만듭니다.
이런 순환이 경찰이 위조지폐를 실제 지폐로 인식할때까지 끝없이 반복됩니다.
이론상으로는 GAN은 단순하지만, 제대로 동작하는 모델을 만드는 것은 어렵습니다.
GAN에서는 두 개의 심화 신경망(deep network)이 쌍으로 함께 동작하며, 도전적으로 두번의 그라디언트 역전파(back propagation of gradients)를 만들어 냅니다.
심화 컨볼루션 GAN(Deep Convolutional GAN, 이하 DCGAN)은 그런 모델 중의 하나이며, 새로운 이미지를 합성하는 법을 스스로 학습해 나가는 실질적인 GAN을 만들어 나가는지 설명합니다.
이 아티클에서 우리는 200줄 이하의 코드로 구성된 텐서플로우 1.0을 백엔드로 하는 케라스2.0을 사용하여 DCGAN을 어떻게 동작시키는 지에 대해 논의할 것입니다. 그리고, MNIST 방식으로 손글씨 모양의 숫자를 쓰는 법에 대해 DCGAN을 훈련시킬 것입니다.
식별자가 실제 이미지를 인식하는 방법에는 Figure 1에서 보이는 바와 같이 심화 컨볼루션 신경망(deep Convolutional Neural Network, 이하 DCNN)이 기본적으로 사용됩니다.
MNIST 데이터셋으로 28 픽셀x 28 픽셀x 1 채널의 이미지를 입력 데이터로 합니다.
시그모이드(sigmoid) 결과는 실제 이미지 정도의 확률을 (0.0이 가짝 1.0이 진짜, 회색 영역은 임의의 값)과 같이 단일 값으로 보여줍니다. 전형적인 CNN과 다른 점은 레이어 사이에서 최대 풀링(max-pooling)이 없다는 것입니다. 대신에 다운 샘플링(downsampling, 임의로 이미지의 일부를 샘플링 하는 것) 방식을 취합니다.
각 CNN 레이어의 활성함수(activation function)는 ReLU를 사용합니다.
레이어 사이에 0.4~0.7의 값을 가지도록 드랍아웃(dropout) 값을 설정하면 과적합(over fitting)과 암기(특정 값을 외우는 것, memorization)를 방지할 수 있습니다.
Listing 1의 코드는 케라스로 구현한 내용입니다.
Figure 1. Discriminator of DCGAN tells how real an input image of a digit is. MNIST Dataset is used as ground truth for real images. Strided convolution instead of max-pooling down samples the image.
Listing 1. Keras code for the Discriminator in Figure 1.
생성자는 가짜 이미지를 합성합니다. Figure 2에서 -1.0에서 1.0 사이의 균등 분포(uniform distribution)를 가진 100차원의 노이즈를 가지고 전치 컨볼루션(transposed convolution)이라 불렸던 컨볼루션의 역(inverse of convolution)으로 가짜 이미지를 생성합니다.
DCGAN에서 권장하는 단편적으로 향상되는 컨볼루션(fractionally-strided convolution) 대신에, 더 사실에 가까웃 손글씨 이미지를 합성하기 위해 첫 세개의 레이어에서 업샘플링(upsampling)을 하겠습니다.
레이어들 사이에 배치 표준화(batch normalization)는 학습하는데 안정성을 부여합니다.
각 레이어 이후의 활성 함수(activation function)는 ReLU를 사용합니다.
최종 레이어에서 시그모이드(sigmoid)의 결과는 가짜 이미지를 생성합니다.
첫 레이어에서 0.3~0.5의 값으로 드랍아웃(dropout)을 설정하면 과적합(overfitting)을 방지할 수 있습니다. Listing 2의 코드는 케라스로 구현한 내용입니다.
Figure 2. Generator model synthesizes fake MNIST images from noise. Upsampling is used instead of fractionally-strided transposed convolution.
Listing 2. Keras code for the generator in Figure 2.
아직까지는 모델이 없습니다. 이번에 훈련할 모델을 만들어 보겠습니다. 우리에게는
1) 식별자 모델(경찰)과
2)적대적 모델 또는 생성자-식별자(경찰로부터 학습하는 위조지폐범)라는
두개의 모델이 필요합니다.
Listing 3의 케라스 코드는 식별자 모델입니다. 이 식별자는 훈련을 위한 손실함수(loss function)에 대해 기술되어 있습니다. 식별자의 결과는 시그모이드(sigmoid)이기 때문에, 우리는 손실에 대해 이진 값(binary cross entropy)을 사용합니다. RMSProp 옵티마이저는 이 경우에는 아담(Adam)에 비해 더 현실적인 가짜 이미지를 생성합니다. 학습 비율(learning rate)은 0.0008 입니다. 감쇠(decay)와 클립(clip)에 대한 가중치(weight) 값은 훈련의 마지막 부분에서 학습의 안정화와 관계가 있습니다.
학습 비율(learning rate)을 조정한다면 감쇠(decay)값을 조정해야 합니다.
Listing 3. Discriminator Model implemented in Keras.
적대적 모델은 Figure 3에서 보이는 바와 같이 생성자-식별자가 함께 쌓아 놓은 것을 가지고 합니다. 생성자 부분은 멍청한 식별자(최초 생성했을 때)와 함께 피드백으로 부터 학습하는 방식으로 합니다. Listing 4는 케라스 코드로 구현한 것입니다. 훈련용 파라미터는 학습 비율(learning rate)과 감쇠(decay) 가중치 값이 줄어드는 부분 외에는 식별자 모델의 값과 같습니다.
Figure 3. The Adversarial model is simply generator with its output connected to the input of the discriminator. Also shown is the training process wherein the Generator labels its fake image output with 1.0 trying to fool the Discriminator.
Listing 4. Adversarial Model as shown in Figure 3 implemented in Keras.
Training is the hardest part. We determine first if Discriminator model is correct by training it alone with real and fake images. Afterwards, the Discriminator and Adversarial models are trained one after the other. Figure 4 shows the Discriminator Model while Figure 3 shows the Adversarial Model during training. Listing 5 shows the training code in Keras.
훈련은 가장 어려운 부분입니다. 우리는 식별자 모델이 실제와 가짜 이미지로 혼자 훈련하여 정확해지는 첫번 째 방법을 결정해야 합니다. 그 다음 식별자 모델과 적대적 모델을 순차/반복적으로 훈련합니다. Figure 4는 Figure 3에서처럼 적대적 모델이 훈련하는 동안 식별자 모델의 모습을 보여줍니다.
Listing 5는 케라스로 훈련하는 코드입니다.
Figure 4. Discriminator model is trained to distinguish real from fake handwritten images.
Listing 5. Sequential training of Discriminator Model and Adversarial Model. Training steps above 1000 generates respectable outputs.
GAN 모델을 충분히 훈련시키는 것은 많은 인내를 필요로 합니다.
이 때, 여기서 몇 가지 주의할 점이 있습니다.
1. 문제: 생성된 이미지는 노이즈(noise)처럼 보입니다.
해결방안: 식별자와 생성자 양쪽에 dropout을 사용합니다. 낮은 dropout 값 (0.3에서 0.6)은 더 실제같은 이미지를 생성합니다.
2. 문제: 식별자의 손실값(loss)가 지나치게 빨리 0에 수렴하여 생성자의 학습을 중단시킵니다.
해결방안: 식별자를 미리 훈련시키지 마세요. 대신에 적대적 모델(Adversarial model)의 학습 비율(learning rate)보다 더 크게 학습 비율(learning rate)을 설정하세요. 생성자를 위해 다른 노이즈 샘플로 훈련하세요.
3. 문제: 생성자 이미지가 여전히 노이즈처럼 보입니다.
해결방안: 실행(activation), 배치 표준화(batch normalization)와 dropout이 정확한 순서로 적용되었는지 확인하세요.
4. 문제: 정확한 훈련/모델 파라미터를 알고 싶어요.
해결방안: 출판된 책이나 코드로부터 알려진 효과가 있는 값드로 시작해서 한번에 하나의 파라미터씩 맞추세요. 2,000 이상의 단계를 훈련하기 전에 500 또는 1,000 단계 정도로 파라미터 값이 적정한지 관찰하세요.
Figure 5는 훈련 동안의 출력 이미지들의 변화 또는 진화를 보여줍니다. Figure 5를 관찰하는 것은 상당히 재미있으며, GAN은 그 자체로 손글씨 숫자를 쓰는 방법을 학습합니다!!
Figure 5. DCGAN output images during 10,000 steps of training.
케라스의 완성된 코드는 여기서 볼 수 있습니다.