Cycle GAN을 통해 낮의 이미지를 밤으로 밤의 이미지를 낮으로 변환하는 네트워크를 설계한다.
인공 신경망에서는 벡터의 형태로 입력된 데이터를 전달 받고 각각의 입력에 웨이트(Weight)라는 가중치를 곱하고 합산, 이후 바이어스 까지 더하는 과정을 통해 실제 뉴런과 비슷한 인공 신경망을 구성하게 되고 이러한 여러 개의 인공 신경망들을 겹쳐서 많은 층을 만들어 내는 과정을 통해 네트워크를 설계하면 아래와 같은 딥러닝 네트워크(Deep Neural Network)가 구성되게 된다.
이러한 딥러닝 네트워크를 이미지 변환을위한 네트워크로 변환하기 위해 합성 곱 신경망(Convolution Network)이라는 개념을 통해서 네트워크를 변환시킨다.
일반적 GAN 은 Generator를 통해 실제 이미지를 생성하고 Discriminator를 통해 이미지를 식별하는 역할을 한다. 하지만 Cycle GAN의 경우엔 일반 GAN 모델을 응용하여 2개의 네트워크를 동시에 학습시키는 네트위크 구조이고 서로다른 두 이미지를 통해 양뱡향 학습을 진행하게 된다.
def GAN_model(generatorA2B, generatorB2A, discriminatorA, discriminatorB, train_optimizer, lambda_cyc = 10, lambda_idt = 5):
image_A = Input(shape=(128, 128, 3))
image_B = Input(shape=(128, 128, 3))
fake_image_B = generatorA2B(image_A)
fake_image_A = generatorB2A(image_B)
reconstructed_image_A = generatorB2A(fake_image_B)
reconstructed_image_B = generatorA2B(fake_image_A)
identity_image_A = generatorB2A(image_A)
identity_image_B = generatorA2B(image_B)
decisionA = discriminatorA(fake_image_A)
decisionB = discriminatorB(fake_image_B)
gan_model = Model(inputs = [inA, inB], outputs = [decisionA, decisionB, reconstructed_image_A, reconstructed_image_B, identity_image_A, identity_image_B])
gan_model.compile(loss= ['mse', 'mse', 'mae', 'mae', 'mae', 'mae'], loss_weights= [1, 1, lambda_cyc, lambda_cyc, lambda_idt, lambda_idt],
optimizer = train_optimizer)
return gan_model
전체 네트워크를 정의후 Generator와 Discriminator를 구축한다.
def generator_network(resnet_blocks=10):
input_layer = Input(shape=(128,128,3))
layer_1 = Conv2D(filters=64, kernel_size=7, strides=1, padding="same")(input_layer)
layer_1 = InstanceNormalization(axis=1)(layer_1)
layer_1 = Activation("relu")(layer_1)
layer_2 = Conv2D(filters=128, kernel_size=3, strides=2, padding="same")(layer_1)
layer_2 = InstanceNormalization(axis=1)(layer_2)
layer_2 = Activation("relu")(layer_2)
layer_3 = Conv2D(filters=256, kernel_size=3, strides=2, padding="same")(layer_2)
layer_3 = InstanceNormalization(axis=1)(layer_3)
layer_3 = Activation("relu")(layer_3)
layer_4 = layer_3
for i in range(resnet_blocks):
layer_4 = resnet_block(layer_4)
layer_5 = Conv2DTranspose(filters=128, kernel_size=3, strides=2, padding='same', use_bias=False)(layer_4)
layer_5 = InstanceNormalization(axis=1)(layer_5)
layer_5 = Activation("relu")(layer_5)
layer_6 = Conv2DTranspose(filters=64, kernel_size=3, strides=2, padding='same', use_bias=False)(layer_5)
layer_6 = InstanceNormalization(axis=1)(layer_6)
layer_6 = Activation("relu")(layer_6)
layer_7 = Conv2D(filters=3, kernel_size=7, strides=1, padding="same")(layer_6)
output_layer = Activation('tanh')(layer_7)
model = Model(inputs=[input_layer], outputs=[output_layer])
return model
def resnet_block(layer):
layer_1 = Conv2D(filters=256, kernel_size=3, strides=1, padding="same")(layer)
layer_1 = InstanceNormalization(axis=1)(layer_1)
layer_1 = Activation('relu')(layer_1)
layer_2 = Conv2D(filters=256, kernel_size=3, strides=1, padding="same")(layer_1)
layer_2 = InstanceNormalization(axis=1)(layer_2)
return Add()([layer_1, layer_2])
def discriminator_network():
input_layer = Input(shape=(128, 128, 3))
layer_1 = ZeroPadding2D(padding=(1, 1))(input_layer)
layer_2 = Conv2D(filters=64, kernel_size=4, strides=2, padding="valid")(layer_1)
layer_2 = LeakyReLU(alpha=0.2)(layer_2)
layer_3 = ZeroPadding2D(padding=(1, 1))(layer_2)
layer_4 = layer_3
for i in range(1, 4):
layer_4 = Conv2D(filters=2 ** i * 64, kernel_size=4, strides=2, padding="valid")(layer_4)
layer_4 = InstanceNormalization(axis=1)(layer_4)
layer_4 = LeakyReLU(alpha=0.2)(layer_4)
layer_4 = ZeroPadding2D(padding=(1, 1))(layer_4)
layer_5 = Conv2D(filters=1, kernel_size=4, strides=1, activation="sigmoid")(layer_4)
output_layer = layer_5
model = Model(inputs=[input_layer], outputs=[output_layer])
return model