IT/AI\ML

[python/Tensorflow2.0] AutoEncoder(오토인코더) ; basic

개발자 두더지 2020. 4. 21. 15:02
728x90

1. AutoEncoder이란?

 AutoEncoder는 아래의 그림과 같이 단순히 입력을 출력으로 복사하는 신경망이다. 그러나 단순한 복사가 아닌 네트워크에 여러가지 방법으로 제약을 준다. 예를 들어 아래 그림처럼 hidden layer의 뉴런 수를 입력층(input layer)보다 작게 하여 데이터를 압축(=차원 축소)한다거나, 입력 데이터에 노이즈(nosie)를 추가한 후 원본 입력을 복원할 수 있도록 네트워크를 학습시키는 등 다양한 AutoEncoder가 있다. 이를 통해 데이터를 효율적으로 표현(representation)하는 방법을 학습하도록 제어한다. 즉 AutoEncoder이란 차원 축소 등을 위해 표현학습(Representation Learning) 또는 특징학습(Feature Learning)을 비지도 학습의 형태로 학습하는 신경망이라고 정의할 수 있다.

표현학습(Representation Learning) /특징학습(Feature Learning)

특징 탐지(feature detection)나 분류(classification)를 위해 필요한 특징점들을 자동으로 발견하는 시스템적 기법들의 총체를 일컫는다.
차원의 저주(Curse of Dimensionality) ; 차원을 축소하는 이유

고차원 공간의 데이터를 분석하거나 측정할 때 저차원 공간에서는 나타나지 않았던 여러 문제들이 발생하는 것으로, 머신러닝에서는 일반적으로 차원이 증가할 경우 기하급수적인 데이터가 요구되는 현상을 말한다.

 AutoEncoder은 위 그림과 같이 인코더(encoder)부분과 디코더(decoder), 두 부분으로 구성돼있다. 

- 인코더 (encoder) : 인지 네트워크(recognition network)라고도 하며, 입력을 내부 표현으로 변환한다.
- 디코더(decoder) : 생성 네트워크(generative network)라고도 하며, 내부 표현을 출력으로 변환한다.

 AutoEncoder는 위 그림과 같이 입력과 출력층의 뉴런 수가 동일하다는 것만 제외하면 일반적인 MLP(Multi-Layer Perception)과 동일한 구조이다. AutoEncoder는 입력을 재구성하기 때문에 출력을 '재구성(reconstruction)'이라고도 하며, 손실 함수는 입력과 재구성(출력)의 차이를 이용해 계산한다.

 위 그림의 오토인토더는 히든 레이어의 뉴런(노드, 유닛)이 입력층보다 작으므로 입력이 저차원으로 표현되는데, 이러한 오토인코더를 Undercomplete Autoencoder라고 한다. undercomplete 오토인코더는 저차원을 가지는 히든 레이어에 의해 입력을 그대로 출력으로 복사할 수 없기 때문에, 출력이 입력과 같은 것을 출력하기 위해 학습해야 한다. 이러한 학습을 통해 undercomplete 오토인코더는 입력 데이터에서 가장 중요한 특성(feature)을 학습하도록 만든다.

 종합하자면 AutoEncoder은 아래의 네 가지 키워드로 정리해서 설명할 수 있다. 

1. Unsupervised learning
2. Manifold learning
3. Generative model learining
4. ML(; Maximum Likehood) density estimation

AutoEncoder을 학습할 때, 학습 방법은 비교사 학습 방법(Unsupervised learning)을 따르며 , Loss는 negative ML(;Maximum Likehood)로 해석된다(ML density estimation) . 한편 학습된 AutoEncoder에서는 인코더는 차원 축소 역할을 수행하며(Manifold learning), 디코더는 생성 모델의 역할을 수행(Generative model learining)한다.

Manifold learning이란?

고차원의 데이터가 저차원의 다양체(Manifold)에 표현될 수 있다는 것을 가정하는 것을 의미한다.

* 다양체 : 기하학적인 유추를 통하여 4차원 이상의 공간을 연구하기 위해 도입된 개념이다. 점, 직선, 평면, 원, 삼각형, 입체, 구(球)와 같은 기하학적 도형의 집합을 1개의 공간으로 보았을 때를 의미한다.

2. AutoEncoder의 사용예

 AutoEncoder는 사전학습(Pre Training)으로 차원의 감소하는데 사용됐다. 그러나 최근은 CNN이나 RNN와 같은 각각의 알고리즘의 안에 차원감소처리가 포함되어 있으므로 사전학습으로서 사용되는 경우가 없어졌지만, 현재는 아래의 용도로 사용되고 있다.

1) 학습 데이터의 노이즈 제거

 학습 데이터의 노이즈는 분류기의 인식률을 떨어뜨린다. AutoEncoder은 이러한 노지를 감소시키는 데이터 클리닝 등에 사용된다. 아래의 그림과 같이 노이즈가 없는 이미지를 훈련시킨 AutoEncoder을 사용하여 입력 데이터(X)에 있는 노이즈(더러워진 부분, 빛이나 그림자가 있는부분)을 제거시키고 있다.

 

 

2) 이상 검지의 이상 개소 특정

구조를 응용한 이상 검지 시스템의 예이다. 정상품의 데이터만을 학습한 AutoEncoder는 검출대상에 상처나 균열 등 이상이 있는 경우에도 그러한 상처나 균열 등을 제거한 이미지(X')을 출력한다. 이 출력(X')을 원래 데이터(X)와 비교하여 차이를 추출하는 것으로써 이상 검지가 되어 어디에 상처나 금이 있는지를 특정해 마크를 붙일 수 있다.

 

3) 압축한 특징을 바탕으로 한 클러스터링

특징을 압축한 잠재변수를 z 공간에 맵핑하면, 특징에 대한 분산의 형태를 나태낼 수 있다. 즉 encoder가 잘 특징을 추출하면, 그러한 압축된 특징으로 클러스터링(분류)하는 것이 가능하다. 


3. 간단한 AutoEncoder 구현(keras이용)

 AutoEncoder을 만들기 위해서는 세 가지가 필요하다.

1. 인코딩 함수(encoding function)
2. 디코딩 함수(decoding function)
3. 원본에 대해 압축된 표현(representation)과 압축 해제된 표현(representation)간 정보 손신량 간의 거리 함수(즉, loss function)

 인코더와 디코더는 parametic 함수(일반적으로 신경망) 로 선택되고 거리 함수와 관련하여 차별화되므로 인코딩/디코딩 함수의 매개변수를 확률적 경사하강법(Stochastic gradient descent)을 사용하여 재구성 손실을 최소화하도록 최적화할 수 있다. 이제 본격적으로 만들어보자.

1) Encdoer

class Encoder(tf.keras.layers.Layer):
  def __init__(self, intermediate_dim):
    super(Encoder, self).__init__()
    self.hidden_layer = tf.keras.layers.Dense(
      units=intermediate_dim,
      activation=tf.nn.relu,
      kernel_initializer='he_uniform'
    )
    self.output_layer = tf.keras.layers.Dense(
      units=intermediate_dim,
      activation=tf.nn.sigmoid
    )
    
  def call(self, input_features):
    activation = self.hidden_layer(input_features)
    return self.output_layer(activation)

먼저 tf.keras.layers.Layer를 상속하는 Encoder 클래스를 정의하여 모델 대신 레이어로 정의한다. 왜 모델이 아닌 레이어일까? 인코더는 자동 인코더 모델의 구성 요소이다. 코드를 통해 인코더 레이어는 입력 피처의 활성화를 학습하기 위해 단일 뉴런 뉴런 레이어 (self.hidden_layer)를 갖도록 정의된다. 그런 다음 은닉층의 데이터 표현을 낮은 차원으로 인코딩하는 레이어 (self.output_layer)에 연결한다. 이 레이어는 중요한 표현으로 생각되는 것으로 구성된다. 따라서, 인코더 층의 "출력"은 입력 데이터 x에 대해 학습된 data representation z이다.

 

2) Decoder

class Decoder(tf.keras.layers.Layer):
  def __init__(self, intermediate_dim, original_dim):
    super(Decoder, self).__init__()
    self.hidden_layer = tf.keras.layers.Dense(
      units=intermediate_dim,
      activation=tf.nn.relu,
      kernel_initializer='he_uniform'
    )
    self.output_layer = tf.keras.layers.Dense(
      units=original_dim,
      activation=tf.nn.sigmoid
    )
  
  def call(self, code):
    activation = self.hidden_layer(code)
    return self.output_layer(activation)

Decoder역시 tf.keras.layers.Layer에 정의되어 있다. 또한 Encoder에 의해 학습된 representation을 재구성하기 위한 단일 뉴런의 은닉층을 갖도록 정의된다. 그런 다음 은닉층을 낮은 차원에서 원래 차원으로 데이터 표현을 디코딩하는 계층에 연결한다. 따라서, 디코더 층의 "출력"은 data representation z로부터 재구성된 데이터 x이다. 궁극적으로 디코더의 출력은 AutoEncoder의 출력이다.  AutoEncoder의 요소를 정의했으므로 이제 model을 빌드해보자.

 

3) Building the AutoEncoder Model

class Autoencoder(tf.keras.Model):
  def __init__(self, intermediate_dim, original_dim):
    super(Autoencoder, self).__init__()
    self.encoder = Encoder(intermediate_dim=intermediate_dim)
    self.decoder = Decoder(intermediate_dim=intermediate_dim, original_dim=original_dim)
  
  def call(self, input_features):
    code = self.encoder(input_features)
    reconstructed = self.decoder(code)
    return reconstructed

 

4) loss function

AutoEncoder역시 다른 뉴럴 네트워크와 마찬가지로 오차역전파(backpropagation)으로 학습한다. 그러나 모델의 값과 라벨을 비교하는 대신, 재구성 된 데이터 x-hat과 원본 데이터 x를 비교한다. 이 비교를 reconstruction error 함수라고 표현하도록 하겠다. 이는 다음의 식처럼 표현할 수 있다.

mean-squared error 함수와 거의 비슷하다.

 Tensorflow에서는 위와 같은 식을 아래와 같이 표현할 수 있다.

def loss(model, original):
  reconstruction_error = tf.reduce_mean(tf.square(tf.subtract(model(original), original)))
  return reconstruction_error

 

5) training

def train(loss, model, opt, original):
  with tf.GradientTape() as tape:
    gradients = tape.gradient(loss(model, original), model.trainable_variables)
    gradient_variables = zip(gradients, model.trainable_variables)
    opt.apply_gradients(gradient_variables)

기울기를 구하고 이를 최적화하여 역전파를 구현할 수 있다.

 

6) Optimizer & Preparing Dataset(MNIST)

TensorBoard를 사용함으로써 훈련 결과를 시각화할 수 있다. 그리고 사용 결과를 기록하기 위한 summary file도 설정하였다. (tf.summary.creat_file_writer) 또한 tf.summary.record_if.를 이용하여 교육에 대한 요약을 기록한다.

autoencoder = Autoencoder(intermediate_dim=64, original_dim=784)
opt = tf.optimizers.Adam(learning_rate=learning_rate)

(training_features, _), (test_features, _) = tf.keras.datasets.mnist.load_data()
training_features = training_features / np.max(training_features)
training_features = training_features.reshape(training_features.shape[0],
                                              training_features.shape[1] * training_features.shape[2])
training_features = training_features.astype('float32')
training_dataset = tf.data.Dataset.from_tensor_slices(training_features)
training_dataset = training_dataset.batch(batch_size)
training_dataset = training_dataset.shuffle(training_features.shape[0])
training_dataset = training_dataset.prefetch(batch_size * 4)

writer = tf.summary.create_file_writer('tmp')

with writer.as_default():
  with tf.summary.record_if(True):
    for epoch in range(epochs):
      for step, batch_features in enumerate(training_dataset):
        train(loss, autoencoder, opt, batch_features)
        loss_values = loss(autoencoder, batch_features)
        original = tf.reshape(batch_features, (batch_features.shape[0], 28, 28, 1))
        reconstructed = tf.reshape(autoencoder(tf.constant(batch_features)), (batch_features.shape[0], 28, 28, 1))
        tf.summary.scalar('loss', loss_values, step=step)
        tf.summary.image('original', original, max_outputs=10, step=step)
        tf.summary.image('reconstructed', reconstructed, max_outputs=10, step=step)

 


참고자료

https://towardsdatascience.com/implementing-an-autoencoder-in-tensorflow-2-0-5e86126e9f7

https://keraskorea.github.io/posts/2018-10-23-keras_autoencoder/

https://products.sint.co.jp/aisia/blog/vol1-21

https://www.youtube.com/watch?v=YxtzQbe2UaE

https://github.com/ExcelsiorCJH/Hands-On-ML/blob/master/Chap15-Autoencoders/Chap15-Autoencoders.ipynb

 

 

728x90