DCGAN - (4) Generator 구현

Previous Article: DCGAN - (3) Architecture

pytorch tutorial에서 제시한 celebA데이터의 경우에는 크기가 제법 되기에 1차적인 목표는 MNIST 데이터를 통해 구현해보는 것이다. MNIST data를 pytorch로 가져오는 방법은 여기, MNIST data에 대한 DCGAN model은 여기에 나와있다.

Architecture 구성을 제외한 모든 과정은 pytorch tutorial과 동일하게 진행하면 되기에 두 모델을 설정하는 부분만 살펴보고, 나머지는 깃허브 링크로 남겨두겠다.

위 링크에서 다룬 tensorflow tutorial에서의 Generator network는 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def make_generator_model():
model = tf.keras.Sequential()
model.add(layers.Dense(7*7*256, use_bias=False, input_shape=(100,)))
model.add(layers.BatchNormalization())
model.add(layers.LeakyReLU())

model.add(layers.Reshape((7, 7, 256)))
assert model.output_shape == (None, 7, 7, 256) # 주목: 배치사이즈로 None이 주어집니다.

model.add(layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False))
assert model.output_shape == (None, 7, 7, 128)
model.add(layers.BatchNormalization())
model.add(layers.LeakyReLU())

model.add(layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False))
assert model.output_shape == (None, 14, 14, 64)
model.add(layers.BatchNormalization())
model.add(layers.LeakyReLU())

model.add(layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))
assert model.output_shape == (None, 28, 28, 1)

return model

총 네가지의 layer로 이루어져 있음을 알 수 있다.

첫번째 layer에서는 100X1 latent vector로 7X7X256의 feature maps을 만든다. 위에서는 dense layer를 통해 총 7X7X256개의 node를 만들고 reshape을 했지만, 우리는 pytorch tutorial에서 사용한 방법과 동일하게 convolutional layer를 이용할 것이다.

이 때, in_channel: 100, out_channel: 256, kernel size: 7, stride: 1의 convolutional transpose layer를 이용한다. pytorch는 tensorflow처럼 output shape의 크기에 맞게 알아서 padding을 넣어주지 않기 때문에 직접 padding 값을 계산해야 한다. 이는 convolutional layer의 원리에 대한 이해가 필요하다. (조만간 자세하게 다루는 글을 작성할 것이다.)

두번째 layer에서는 in_channel: 256, out_channel: 128, kernel size: 5, stride: 1, padding: 2의 convolutional transpose layer를 이용하여 7X7X128 feature maps을 만든다.

세번째 layer에서는 위 모델과 조금 다르게 진행할 수밖에 없었다. pytorch에서 Conv2DTranspose layer의 원리 상, stride가 2이고 kernel size가 홀수일 때 width와 height이 짝수인 feature map을 만들지 못한다. 이는 tensorflow와 달리 pytorch에서는 asymmetric padding을 주지 못하기 때문이다.

따라서 kernel size 5는 유지하되, output_padding을 1만큼 줌으로써 절충하였다. 즉, in_channel: 128, out_channel: 64, kernel size: 5, stride: 2, padding: 2, output_padding: 1의 convolutional transpose layer를 이용하여 14X14X64 feature maps을 만들었다.

마지막 layer에서도 마찬가지 이유로 in_channel: 64, out_channel: 1, kernel size: 5, stride: 2, padding: 2, output_padding: 1의 convolutional transpose layer를 이용하여 28X28X1 feature maps(fake image)를 만들었다.

최종 코드는 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Generator(nn.Module):
def __init__(self, ngpu):
super(Generator, self).__init__()
self.ngpu = ngpu
self.main = nn.Sequential(
nn.ConvTranspose2d(100,256,7,1,0,bias=False),
nn.BatchNorm2d(256),
nn.LeakyReLU(True),

nn.ConvTranspose2d(256,128,5,1,2,bias=False),
nn.BatchNorm2d(128),
nn.LeakyReLU(True),

nn.ConvTranspose2d(128,64,4,2,1,bias=False),
nn.BatchNorm2d(64),
nn.LeakyReLU(True),

nn.ConvTranspose2d(64,1,4,2,1,bias=False),
nn.Tanh()
)
def forward(self, input):
return self.main(input)

어쩌다 보니 글이 길어졌기에, Discriminator network와 학습결과는 다음 글에서 이어나가도록 하겠다.

Next Article: DCGAN - (5) Descriminator 구현 및 학습 결과

Share