인공지능 분야에서 최근 정말 핫한 GAN에 대해서 추상적으로는 이해하는 것은 어렵지 않지만, 딥하게 이해하기 위해 글을 작성한다.
(앞으로 공부를 하면서 주의 하려고 하는 점은, 개념적인 것과 코드 사이의 관계를 보고 실습을 진행하는 것을 목표로 하려 한다. 매번 개념적인 부분만 학습하다 보니 뜬구름 잡는 느낌이 있고 내가 만들 수 있을까? 하는 생각이 걱정으로 바뀌는 것 같아서.)
본문은 dreamgonfly님의 쉽게 씌어진 GAN을 제가 이해하기 편하게 정리한 글입니다.
- 원문 쉽게씌어진 GAN : https://dreamgonfly.github.io/2018/03/17/gan-explained.html
흐름 정리를 위해 추가로 사용한 글 : https://pathmind.com/kr/wiki/generative-adversarial-network-gan
생성적 적대 신경망(GANs)에 대한 초보자용 가이드 (GANs)
생성적 적대 신경망(GANs)이란 한 네트워크가 다른 네트워크와 겨루는 두개의 네트워크로 구성된 심층 신경망 구조이다.
pathmind.com
GAN의 기본 개념
Generator 와 Discriminator가 서로 상호 작용하며 점점 발전하는 네트워크라고 할 수 있다.
출처 : wiki 내 이미지 (from O'Relly)
1. Generator의 목적은 현실과 비슷한 지폐(위조지폐, 이미지)를 만들고
2. Discriminator는 해당 지폐가 위조 지폐인지 진짜 지폐인지(0 OR 1) 구분해 내는 것이다.
3. Generator는 생성된 이미지를 통해 Discriminator를 속이려 하고 Discriminator는 정확히 구분하려고 하는 과정을 통해 진짜에 가까운 이미지를 만들어 낼 수 있게 된다.
위 세개로 나누어 공부해 보자.
1. Generator의 목적은 다양할 수 있지만, 예를들어 현실과 비슷한 지폐(위조지폐, 이미지)를 만든다.
1의 과정은 정확히는 Noise Vector(부분 정보, 실제로는 랜덤 값)를 받아 이를 Up-Sampling(실제 이미지 처럼 변경)하여 이미지를 만드는 것이다. 이 부분 부터 코드적 관점과 현실적 관점에서 살펴보자.
참조 글 :
Image Completion in Deep Learning : https://bamos.github.io/2016/08/09/deep-completion/#step-1-interpreting-images-as-samples-from-a-probability-distribution
Image Completion with Deep Learning in TensorFlow
Image Completion with Deep Learning in TensorFlow August 9, 2016 Introduction Content-aware fill is a powerful tool designers and photographers use to fill in unwanted or missing parts of images. Image completion and inpainting are closely related technolo
bamos.github.io
쉽게 씌어진 GAN : https://dreamgonfly.github.io/2018/03/17/gan-explained.html
쉽게 씌어진 GAN
이 글은 마이크로소프트웨어 391호 인공지능의 체크포인트(THE CHECKPOINT OF AI)에 ‘쉽게 쓰이는 GAN’이라는 제목으로 기고된 글입니다. 블로그에는 이 글의 원제이자 윤동주 시인의 ‘쉽게 씌어진 시’를 따라 지어진 제목인 ‘쉽게 씌어진 GAN’으로 포스팅합니다.
dreamgonfly.github.io
[ 현실적 관점 ]
어떻게 Noise Vector를 통해서 이미지를 만드는 것일까?
몇개 안되는 정보(Noise Vector)를 통해서 원래의 이미지를 만들어 내려면 정보 추론이 필요한데 그것이 1) Contextual Information 과 2) Perceptual Information 이다.
1) Contextual Information : 추론하고 싶은 픽셀의 주변 픽셀을 통해 해당 픽셀의 값을 추론한다. 맥락적 정보.
2) Perceptual Information : 이미지가 현실적이기 위해선 해당 픽셀의 값이 어떻게 되어야 하는지 추론한다. 쉽게 말하면 '그럴듯 하게'이다. 이를 위해선 기존에 학습되어 있어야 한다. AI가 만든 고양이 사진을 우리가 이상하다고 생각하는 것은 이 인지적 정보를 통해서 파악하는 것이다. 인지적 정보
인간은 위의 두가지 정보를 쉽게 알 수 있지만, 어떻게 그걸 알아내고 있는지 알고리즘으로 표현할 방법이 없다. 아직까지는 이를 제일 잘 해내고 있는 것이 통계와 머신러닝을 활용하는 방법이다.
[ 코드 관점 ]
Noise Vector는 무엇일까? 어떤 기준으로 만드는 것일까?
Noise Vector는 관용적으로 변수 Z 에 생성, 저장하여 활용하는데 이는 단순하게 균등분포(Uniform Distribution)이나 정규분포(Normal Distribution)에서 무작위로 추출된 값이다. Z 벡터가 존재하는 공간을 잠재공간(Latent Space)라고도 한다.
#pytorch로 코드를 작성한다면 z값은 단순히 이런 느낌
#위에서 생성한 z값을 Generator에 넣어준다.
Generator(z)
Colored by Color Scripter
1) Z의 크기는 어떻게 정하는 것이지?
- 임의로 결정하는 것이다. 하지만 Z의 값을 통해서 이를 이미지로 만드는 것이기 때문에, 이미지의 특성을 충분히 담을 수 있을 정도의 크기여야 한다. 위 코드에서는 100차원으로 잡았다.
2) 위에서 '충분한'을 어떻게 알 수 있고, Z벡터의 의미를 어떻게 받아들여야 하지?
- 알기 힘들다. 일반적인 GAN에서는 Z의 의미를 쉽게 이해하기 힘들고 이 부분을 보완한 변형된 GAN중 하나가 DC GAN이다. Z의 특정 성분이 이미지의 특징(예를들면 얼굴의 모양 계란형 / 동그란 얼굴 / 네모 얼굴)등을 담당할 텐데 기존 GAN에서는 해당 성분을 찾을 수 없었다면 DCGAN에서 해당 성분을 찾아낼 수 있도록 하였다.
Generator : Noise Vector를 어떻게 Upsampling 하여 이미지를 만드는 것일까? (본문의 모든 코드는 Dreamgonfly님의 github 코드)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#Generator Class
#인공지능 세계의 Hello World라 불리는 MNIST 데이터셋을 활용하여 이미지 생성을 하는 GAN을 만드는 주제
# 네트워크 구조, 100차원의 Noise Vector를 - 256 - 512 - 1024 - 28*28 순서로 변형시켜 Up sampling 함.
# 마지막에서는 Tanh를 사용하여 -1부터 1사이의 픽셀 값으로 내보낸다.
def __init__(self):
super(Generator, self).__init__()
nn.LeakyReLU(0. 2 , inplace= True),
nn.LeakyReLU(0. 2 , inplace= True),
nn.LeakyReLU(0. 2 , inplace= True),
# (batch_size x 100) 크기의 랜덤 벡터를 받아
# 이미지를 (batch_size x 1 x 28 x 28) 크기로 출력한다.
def forward(self, inputs):
Colored by Color Scripter
- 위 코드를 보면 Generator도 결국 하나의 Network일 뿐이다. 100차원의 Noise Vector를 받아서 이를 여러 단계의 Layer를 통해 충분한 매개변수를 붙여주고 마지막에 이미지 형태로 내보내기 위해 28 X 28 사이즈로 출력한다.
2. Discriminator는 해당 지폐가 위조 지폐인지 진짜 지폐인지(0 OR 1) 구분해 내는 것이다.
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
# <코드3> GAN의 구분자(Discriminator)
# 구분자는 이미지를 입력으로 받아 이미지가 진짜인지 가짜인지 출력한다.
# 네트워크 구조
def __init__(self):
super(Discriminator, self).__init__()
nn.LeakyReLU(0. 2 , inplace= True),
nn.Dropout(inplace= True),
nn.LeakyReLU(0. 2 , inplace= True),
nn.Dropout(inplace= True),
nn.LeakyReLU(0. 2 , inplace= True),
nn.Dropout(inplace= True),
nn.Sigmoid())
# (batch_size x 1 x 28 x 28) 크기의 이미지를 받아
# 이미지가 진짜일 확률을 0~1 사이로 출력한다.
def forward(self, inputs):
Colored by Color Scripter
- 위 코드의 네트워크 구조를 보면 이미지 형태 28*28을 받아 마지막 Sigmoid 함수를 거쳐 해당 이미지가 진짜일 확률을 0~1사이값으로 반환한다.
3. Generator는 생성된 이미지를 통해 Discriminator를 속이려 하고 Discriminator는 정확히 구분하려고 하는 과정을 통해 진짜에 가까운 이미지를 만들어 낼 수 있게 된다.
3-1. 먼저 Discriminator가 Real Image를 잘 맞출 수 있도록 학습시킨다.
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
32
33
# 진짜 이미지를 구분자에 넣는다.
D_result_from_real = D(real_data)
# 구분자의 출력값이 정답지인 1에서 멀수록 loss가 높아진다. criterion은 BCELoss Function.
D_loss_real = criterion(D_result_from_real, target_real)
# 생성자에 입력으로 줄 랜덤 벡터 z를 만든다.
if use_gpu:
z = z.cuda()
# 생성자로 가짜 이미지를 생성한다.
fake_data = G(z)
# 생성자가 만든 가짜 이미지를 구분자에 넣는다.
D_result_from_fake = D(fake_data)
# 구분자의 출력값이 정답지인 0에서 멀수록 loss가 높아진다.
D_loss_fake = criterion(D_result_from_fake, target_fake)
# 구분자의 loss는 두 문제에서 계산된 loss의 합이다.
D_loss = D_loss_real + D_loss_fake
# 구분자의 매개 변수의 미분값을 0으로 초기화한다.
D.zero_grad()
# 역전파를 통해 매개 변수의 loss에 대한 미분값을 계산한다.
D_loss.backward()
# 최적화 기법을 이용해 구분자의 매개 변수를 업데이트한다.
Colored by Color Scripter
- D_loss_real : Real Data를 Discriminator에 넣으면 나와야 하는 값인 target_real(1로 이뤄진 tensor)과 비교하여 Loss를 계산한다.
- D_loss_fake : Fake Data를 Discriminator에 넣으면 나와야 하는 값인 target_fake(0으로 이뤄진 tensor)과 비교하여 Loss를 계산한다.
- Loss.backward()를 통해서 미분값을 역 전파하고, 해당 미분값을 통해 optimizer.step()을 활용해 Learning Rate와 비례해 값을 업데이트한다.
3-2. Generator는 Discriminator를 속일 수 있도록 학습해야 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# <코드8> 생성자 학습시키기
# 생성자에 입력으로 줄 랜덤 벡터 z를 만든다.
z = z.cuda()
# 생성자로 가짜 이미지를 생성한다.
fake_data = G(z)
# 생성자가 만든 가짜 이미지를 구분자에 넣는다.
D_result_from_fake = D(fake_data)
# 생성자의 입장에서 구분자의 출력값이 1에서 멀수록 loss가 높아진다.
G_loss = criterion(D_result_from_fake, target_real)
# 생성자의 매개 변수의 미분값을 0으로 초기화한다.
G.zero_grad()
# 역전파를 통해 매개 변수의 loss에 대한 미분값을 계산한다.
G_loss.backward()
# 최적화 기법을 이용해 생성자의 매개 변수를 업데이트한다.
Colored by Color Scripter
- Noise Vector인 z를 활용해 Generator로 새로운 이미지를 만들고, 해당 이미지를 D에 넣어 나온 값이 1이 나와야 목적을 달성하는 것이다.
- Loss를 (D(G(z)), 1)끼리 비교한다. G(z)는 생성된 Fake Image / D(G(z)) 는 Fake Image가 Discriminator입장에서 얼마나 Real한지를 반환.
- 마찬가지로 Backward로 미분값을 계산하고, Step()을 통해 Learning Rate와 비례해 매개변수들을 업데이트 한다.
위의 과정을 반복하여 학습하면서 Real한 이미지를 만들기 위한 Parameter값을 찾게 되는 구조가 GAN이다.
* 번외 - Pytorch에서 Backward()와 Step()
Backward()를 하면 각 Parameter에 Gradient값을 저장해 줌.
Step()을 하면 Parameter에 저장된 Gradient에 Learning Rate를 곱해서 Parameter를 업데이트 함.
GAN의 한계
GAN의 개념은 혁신적이지만 고질적인 문제가 있었다. GAN을 학습 시키는 것이 어렵다는 것이다. 그 이유는 여러가지이지만 '쉽게 씌어진 GAN'에서는 다음 세개를 얘기한다.
1. G 와 D가 함께 비슷한 속도로 성장을 해야 한다.
2. Mode Collapse현상 : 생성자가 계속해서 비슷한 이미지만 만들어 내는 상황
3. 텍스트 같은 표현이 불연속적인(실수가 아닌) 것들을 학습하기가 어려움
위 GAN의 한계를 극복하기 위해 시도된 것 중 큰 발전을 만든 GAN이 바로 DCGAN이다.
DCGAN(Deep Convolutional GAN)
DCGAN의 가장 큰 특징은 좋은 최적화 기법을 알아낸 것과 적절한 학습 속도를 알아낸 것이다.
아래는 여러 DCGAN의 특징이다.
1. 이미지의 위치 정보를 잃게 만드는 선형 Layer와 Pooling Layer 대신, Convolution과 Transposed Convolution을 사용함.
(Pooling Layer, 예를들면 Max pool은 이미지의 특정 정보만 활용하여 특징을 잘 잡아주긴 한다.)
2. 배치 정규화(Batch Normalize)를 시켜준다. 평균과 분산을 활용해서 입력 데이터 분포를 다듬는다.
- 이는 역 전파를 레이어에 쉽게 전달 할 수 있도록 한다.
3. 모든 레이어에 ReLU, LeakyReLU를 활용한다.
4. 잠재공간에 데이터 특성이 투영됐는지 살펴보는 것.
[ 코드 ]
- 코드에서는 기존 GAN과 대부분 동일하고, 구분자와 생성자 Layer들에 Transposed Convolution 적용, 배치 정규화, ReLU/LeakyReLU 활용만 넣어주면 된다.
cGAN(Conditional GAN)
기존 GAN은 이미지를 생성하는 반면, cGAN은 이미 있는 이미지를 다른 영역의 이미지로 변형할 때 사용한다.
이를 위해 당연히 cGAN의 생성자에서는 잠재 공간을 받기 보다 변형할 이미지를 입력으로 받고, 구분자는 변형 이미지가 올바르게 변형 되었는지(그럴듯 한지와 변형할 이미지를 적절히 변경 했는지)
EX) 스케치에 채색, 흑백 사진 컬러, 낮->밤
1. 기존 GAN에서는 하나의 이미지 도메인 내의 움직임이었다면, cGAN은 그걸 극복했다.
다양한 GAN의 종류
WGAN(Wassertein GAN) : 실제 데이터와 생성 데이터의 분포가 얼마나 다른지 측정하는 거리 개념을 변경해 안정적 학습을 하게 만듬.
EBGAN(Energy-based GAN) : GAN을 에너지 관점에서 바라봐서 안정적 학습.
BEGAN(Boundary Equilibrium GAN) : WGAN / EBGAN 을 발전 시켜 이미지 퀄리티을 높이고, 다양성을 컨트롤 할 수 있게 함.
CycleGAN / DiscoGAN : 매칭 데이터 셋이 없어도 이미지 변형을 가능하게 함 ( cGAN 의 업그레이드 )
StarGAN : 아이디어를 확장 시켜 세 개 이상의 이미지 변형을 시도함.
SRGAN(Super-Resolution GAN) : 사진 해상도를 높임
SEGAN(Speech Enhancement GAN) : 음성 녹음의 노이즈를 줄여 줌.