오토인코더란어떤 지도 없이도 잠재 표현 또는 입력 데이터의 밀집 표현을 학습할 수 있는 인공 신경망이다.

특정 오토 인코더는 훈련 데이터와 매우 비슷한 새로운 데이터를 생성할 수 있는데, 이를 생성 모델이라고 부른다. 이에 더 나아가 GAN, Difussion 모델들이 요즘 많이 등장하고, 사용되고 있으며, 이는 정말 사람의 얼굴 사진이라고 믿을 만한 결과물을 뽑아내기도 한다.

GAN에 대하여 간단하게만 살펴보자면, 생성자와 판별자가 존재한다. 이는 아래 이미지와 같다.

Untitled

생성자와 판별자의 관계를 정의하자면 경찰과 도둑의 관계로 정의가 가능하다. 생성자는 가짜 위조 지폐를 만들어내는 도둑, 반대로 판별자는 그 위조 지폐를 판별해내는 경찰로 볼 수 있다는 것이다.

위 그림에서 가우시안 노이즈를 적용한 z를 입력받은 도둑(생성자, G)은 이미지를 하나 만들어 낸다. 그리고 경찰(판별자, D)은 그 이미지를 반별하고, 그 결과에 따라 피드백을 전달한다. 이를 계속 반복하면 도둑이 점점 더 판별하기 어려운 이미지를 만들어 낸다는 것이 그 요점이다. 위의 결과는 직접 실험해본 결과이다. 제일 오른 쪽의 $x^_{start}$의 이미지와 $x^_{end}$의 이미지를 육안으로 보아도 학습 과정의 시작과 끝에서 도둑인 생성자가 이미지를 잘 만들어 내도록 학습함을 확인할 수 있다.

적층(심층) 오토인코더

여러 층을 가지는 오토인코더를 적층 오토인코더라고 한다. 케라스를 이용하여 간단하게 구현하여 보자.

import tensorflow as tf

encoder = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=[28, 28]),
    tf.keras.layers.Dense(100, activation='selu'),
    tf.keras.layers.Dense(30, activation='selu'),
])

decoder = tf.keras.models.Sequential([
    tf.keras.layers.Dense(100, activation='selu', input_shape=[30]),
    tf.keras.layers.Dense(28*28, activation='sigmoid'),
    tf.keras.layers.Reshape([28, 28])
])

auto_encoder = tf.keras.Sequential([encoder, decoder])

auto_encoder.compile(loss='binary_crossentopy',
                     optimizer=tf.keras.optimizers.SGD(learning_rate=1.5))

GAN

Generative Adversarial Nets인 GAN은 앞서 설명한 구조를 가지고 있다. 결국은 도둑이 경찰에게 구분하기 어려운 위조 지폐를 만들어 낸다는 것인데 이를 코드로 살펴보자(코랩에서는 돌리기 어려울 수 있다).

%matplotlib inline

import matplotlib.pyplot as plt
import numpy as np

from tensorflow.keras.datasets import mnist
from tensorflow.keras.layers import Dense, Flatten, Reshape, Conv2D, Input
from tensorflow.keras.layers import LeakyReLU
from tensorflow.keras.models import Sequential
from tensorflow.keras.optimizers import Adam

img_rows = 28
img_cols = 28
channels = 1

img_shape = (img_rows, img_cols, channels)

z_dim = 100

먼저 필요한 라이브러리들을 가지고 온다.

def build_generator(img_shape, z_dim):
    model = Sequential()
    model.add(Dense(128, input_dim=z_dim))
    model.add(Dense(256, activation='swish'))
    model.add(Dense(256, activation='swish'))
    model.add(Dense(256, activation='swish'))
    model.add(LeakyReLU(alpha=0.01))
    model.add(Dense(28 * 28 * 1, activation='tanh'))
    model.add(Reshape(img_shape))
    return model

다음으로 도둑인 생성자를 구성한다. 위 코드에서는 fully connected된 Dense layer을 사용하여 생성자를 구성하였다.

def build_discriminator(img_shape):
    model = Sequential()
    model.add(Flatten(input_shape=img_shape))
    model.add(Dense(128))
    model.add(LeakyReLU(alpha=0.01))
    model.add(Dense(1, activation='sigmoid'))
    return model

다음으로 판별자를 구성하였다. 이는 이미지를 Flatten layer을 통해 펼치고, 마지막에 sigmoid를 통해 반별을 진행한다. sigmoid를 사용하는 이유는 판별자인 경찰은 이미지가 진짜인지 가짜인지를 구분하는 것이기때문이다.

def build_gan(generator, discriminator):
    model = Sequential()
    model.add(generator)
    model.add(discriminator)
    return model

discriminator = build_discriminator(img_shape)
discriminator.compile(loss='binary_crossentropy',
                      optimizer=Adam(),
                      metrics=['accuracy'])

generator = build_generator(img_shape, z_dim)

discriminator.trainable = False

gan = build_gan(generator, discriminator)
gan.compile(loss='binary_crossentropy', optimizer=Adam())