이 페이지는 Cloud Translation API를 통해 번역되었습니다.
Switch to English

오토 인코더 소개

TensorFlow.org에서보기 Google Colab에서 실행 GitHub에서 소스보기 노트북 다운로드

이 자습서에서는 기본, 이미지 노이즈 제거 및 이상 감지의 세 가지 예를 통해 자동 인코더를 소개합니다.

오토 인코더는 입력을 출력에 복사하도록 훈련 된 특수한 유형의 신경망입니다. 예를 들어, 손으로 쓴 숫자의 이미지가 주어지면 오토 인코더는 먼저 이미지를 더 낮은 차원의 잠재 표현으로 인코딩 한 다음 잠재 표현을 다시 이미지로 디코딩합니다. 오토 인코더는 재구성 오류를 최소화하면서 데이터를 압축하는 방법을 학습합니다.

오토 인코더에 대해 자세히 알아 보려면 Ian Goodfellow, Yoshua Bengio 및 Aaron Courville의 Deep Learning 에서 14 장을 읽어보십시오.

TensorFlow 및 기타 라이브러리 가져 오기

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import tensorflow as tf

from sklearn.metrics import accuracy_score, precision_score, recall_score
from sklearn.model_selection import train_test_split
from tensorflow.keras import layers, losses
from tensorflow.keras.datasets import fashion_mnist
from tensorflow.keras.models import Model

데이터 세트로드

시작하려면 Fashon MNIST 데이터 세트를 사용하여 기본 오토 인코더를 훈련합니다. 이 데이터 세트의 각 이미지는 28x28 픽셀입니다.

(x_train, _), (x_test, _) = fashion_mnist.load_data()

x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.

print (x_train.shape)
print (x_test.shape)
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz
32768/29515 [=================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz
26427392/26421880 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz
8192/5148 [===============================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz
4423680/4422102 [==============================] - 0s 0us/step
(60000, 28, 28)
(10000, 28, 28)

첫 번째 예 : 기본 오토 인코더

기본 오토 인코더 결과

이미지를 64 차원 잠재 벡터로 압축하는 encoder 와 잠복 공간에서 원본 이미지를 재구성하는 decoder 라는 두 개의 Dense 레이어로 자동 encoder 정의합니다.

모델을 정의하려면 Keras Model Subclassing API를 사용하십시오.

latent_dim = 64 

class Autoencoder(Model):
  def __init__(self, latent_dim):
    super(Autoencoder, self).__init__()
    self.latent_dim = latent_dim   
    self.encoder = tf.keras.Sequential([
      layers.Flatten(),
      layers.Dense(latent_dim, activation='relu'),
    ])
    self.decoder = tf.keras.Sequential([
      layers.Dense(784, activation='sigmoid'),
      layers.Reshape((28, 28))
    ])

  def call(self, x):
    encoded = self.encoder(x)
    decoded = self.decoder(encoded)
    return decoded

autoencoder = Autoencoder(latent_dim)
autoencoder.compile(optimizer='adam', loss=losses.MeanSquaredError())

x_train 을 입력과 목표 모두로 사용하여 모델을 훈련시킵니다. encoder 는 데이터 세트를 784 차원에서 잠복 공간으로 압축하는 방법을 배우고 decoder 는 원본 이미지를 재구성하는 방법을 배웁니다. .

autoencoder.fit(x_train, x_train,
                epochs=10,
                shuffle=True,
                validation_data=(x_test, x_test))
Epoch 1/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0239 - val_loss: 0.0132
Epoch 2/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0116 - val_loss: 0.0105
Epoch 3/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0100 - val_loss: 0.0097
Epoch 4/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0095 - val_loss: 0.0094
Epoch 5/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0092 - val_loss: 0.0092
Epoch 6/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0090 - val_loss: 0.0091
Epoch 7/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0090 - val_loss: 0.0090
Epoch 8/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0089 - val_loss: 0.0090
Epoch 9/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0088 - val_loss: 0.0090
Epoch 10/10
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0088 - val_loss: 0.0088

<tensorflow.python.keras.callbacks.History at 0x7f220fe53fd0>

모델이 학습되었으므로 테스트 세트에서 이미지를 인코딩 및 디코딩하여 모델을 테스트 해 보겠습니다.

encoded_imgs = autoencoder.encoder(x_test).numpy()
decoded_imgs = autoencoder.decoder(encoded_imgs).numpy()
n = 10
plt.figure(figsize=(20, 4))
for i in range(n):
  # display original
  ax = plt.subplot(2, n, i + 1)
  plt.imshow(x_test[i])
  plt.title("original")
  plt.gray()
  ax.get_xaxis().set_visible(False)
  ax.get_yaxis().set_visible(False)

  # display reconstruction
  ax = plt.subplot(2, n, i + 1 + n)
  plt.imshow(decoded_imgs[i])
  plt.title("reconstructed")
  plt.gray()
  ax.get_xaxis().set_visible(False)
  ax.get_yaxis().set_visible(False)
plt.show()

png

두 번째 예 : 이미지 노이즈 제거

이미지 노이즈 제거 결과

오토 인코더는 이미지에서 노이즈를 제거하도록 훈련 될 수도 있습니다. 다음 섹션에서는 각 이미지에 임의의 노이즈를 적용하여 Fashion MNIST 데이터 세트의 노이즈 버전을 생성합니다. 그런 다음 잡음이있는 이미지를 입력으로 사용하고 원본 이미지를 대상으로 사용하여 오토 인코더를 훈련합니다.

이전에 수정 한 내용을 생략하기 위해 데이터 세트를 다시 가져 오겠습니다.

(x_train, _), (x_test, _) = fashion_mnist.load_data()
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.

x_train = x_train[..., tf.newaxis]
x_test = x_test[..., tf.newaxis]

print(x_train.shape)
(60000, 28, 28, 1)

이미지에 임의의 노이즈 추가

noise_factor = 0.2
x_train_noisy = x_train + noise_factor * tf.random.normal(shape=x_train.shape) 
x_test_noisy = x_test + noise_factor * tf.random.normal(shape=x_test.shape) 

x_train_noisy = tf.clip_by_value(x_train_noisy, clip_value_min=0., clip_value_max=1.)
x_test_noisy = tf.clip_by_value(x_test_noisy, clip_value_min=0., clip_value_max=1.)

잡음이있는 이미지를 플로팅합니다.

n = 10
plt.figure(figsize=(20, 2))
for i in range(n):
    ax = plt.subplot(1, n, i + 1)
    plt.title("original + noise")
    plt.imshow(tf.squeeze(x_test_noisy[i]))
    plt.gray()
plt.show()

png

컨볼 루션 오토 인코더 정의

이 예제에서는 길쌈 사용 autoencoder 훈련합니다 Conv2D의 에 층을 encoderConv2DTranspose의 에서 레이어 decoder .

class Denoise(Model):
  def __init__(self):
    super(Denoise, self).__init__()
    self.encoder = tf.keras.Sequential([
      layers.Input(shape=(28, 28, 1)), 
      layers.Conv2D(16, (3,3), activation='relu', padding='same', strides=2),
      layers.Conv2D(8, (3,3), activation='relu', padding='same', strides=2)])

    self.decoder = tf.keras.Sequential([
      layers.Conv2DTranspose(8, kernel_size=3, strides=2, activation='relu', padding='same'),
      layers.Conv2DTranspose(16, kernel_size=3, strides=2, activation='relu', padding='same'),
      layers.Conv2D(1, kernel_size=(3,3), activation='sigmoid', padding='same')])

  def call(self, x):
    encoded = self.encoder(x)
    decoded = self.decoder(encoded)
    return decoded

autoencoder = Denoise()
autoencoder.compile(optimizer='adam', loss=losses.MeanSquaredError())
autoencoder.fit(x_train_noisy, x_train,
                epochs=10,
                shuffle=True,
                validation_data=(x_test_noisy, x_test))
Epoch 1/10
1875/1875 [==============================] - 26s 14ms/step - loss: 0.0182 - val_loss: 0.0112
Epoch 2/10
1875/1875 [==============================] - 25s 14ms/step - loss: 0.0100 - val_loss: 0.0093
Epoch 3/10
1875/1875 [==============================] - 25s 13ms/step - loss: 0.0089 - val_loss: 0.0087
Epoch 4/10
1875/1875 [==============================] - 26s 14ms/step - loss: 0.0085 - val_loss: 0.0084
Epoch 5/10
1875/1875 [==============================] - 25s 14ms/step - loss: 0.0083 - val_loss: 0.0083
Epoch 6/10
1875/1875 [==============================] - 26s 14ms/step - loss: 0.0082 - val_loss: 0.0082
Epoch 7/10
1875/1875 [==============================] - 25s 13ms/step - loss: 0.0081 - val_loss: 0.0081
Epoch 8/10
1875/1875 [==============================] - 25s 13ms/step - loss: 0.0081 - val_loss: 0.0080
Epoch 9/10
1875/1875 [==============================] - 25s 13ms/step - loss: 0.0080 - val_loss: 0.0080
Epoch 10/10
1875/1875 [==============================] - 25s 14ms/step - loss: 0.0079 - val_loss: 0.0080

<tensorflow.python.keras.callbacks.History at 0x7f22122b45c0>

인코더 요약을 살펴 보겠습니다. 이미지가 28x28에서 7x7로 어떻게 다운 샘플링되는지 확인하십시오.

autoencoder.encoder.summary()
Model: "sequential_2"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 14, 14, 16)        160       
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 7, 7, 8)           1160      
=================================================================
Total params: 1,320
Trainable params: 1,320
Non-trainable params: 0
_________________________________________________________________

디코더는 이미지를 7x7에서 28x28로 다시 업 샘플링합니다.

autoencoder.decoder.summary()
Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_transpose (Conv2DTran (None, 14, 14, 8)         584       
_________________________________________________________________
conv2d_transpose_1 (Conv2DTr (None, 28, 28, 16)        1168      
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 28, 28, 1)         145       
=================================================================
Total params: 1,897
Trainable params: 1,897
Non-trainable params: 0
_________________________________________________________________

오토 인코더에서 생성 된 노이즈가있는 이미지와 노이즈가 제거 된 이미지를 모두 플로팅합니다.

encoded_imgs = autoencoder.encoder(x_test).numpy()
decoded_imgs = autoencoder.decoder(encoded_imgs).numpy()
n = 10
plt.figure(figsize=(20, 4))
for i in range(n):

    # display original + noise
    ax = plt.subplot(2, n, i + 1)
    plt.title("original + noise")
    plt.imshow(tf.squeeze(x_test_noisy[i]))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)

    # display reconstruction
    bx = plt.subplot(2, n, i + n + 1)
    plt.title("reconstructed")
    plt.imshow(tf.squeeze(decoded_imgs[i]))
    plt.gray()
    bx.get_xaxis().set_visible(False)
    bx.get_yaxis().set_visible(False)
plt.show()

png

세 번째 예 : 이상 감지

개요

이 예에서는 ECG5000 데이터 세트 에서 이상을 감지하도록 오토 인코더를 훈련합니다. 이 데이터 세트에는 각각 140 개의 데이터 포인트가있는 5,000 개의 심전도 가 포함되어 있습니다. 각 예제는 0 (비정상 리듬에 해당) 또는 1 (정상 리듬에 해당)으로 레이블이 지정된 단순화 된 버전의 데이터 세트를 사용합니다. 비정상적인 리듬을 식별하는 데 관심이 있습니다.

오토 인코더를 사용하여 이상을 어떻게 감지합니까? 오토 인코더는 재구성 오류를 최소화하도록 훈련되었습니다. 오토 인코더를 정상적인 리듬으로 만 훈련 한 다음이를 사용하여 모든 데이터를 재구성합니다. 우리의 가설은 비정상적인 리듬이 더 높은 재건 오류를 가질 것이라는 것입니다. 그런 다음 재구성 오류가 고정 임계 값을 초과하는 경우 리듬을 이상으로 분류합니다.

ECG 데이터로드

사용할 데이터 세트는 timeseriesclassification.com 의 데이터 세트를 기반으로합니다.

# Download the dataset
dataframe = pd.read_csv('http://storage.googleapis.com/download.tensorflow.org/data/ecg.csv', header=None)
raw_data = dataframe.values
dataframe.head()
# The last element contains the labels
labels = raw_data[:, -1]

# The other data points are the electrocadriogram data
data = raw_data[:, 0:-1]

train_data, test_data, train_labels, test_labels = train_test_split(
    data, labels, test_size=0.2, random_state=21
)

데이터를 [0,1] 로 정규화합니다.

min_val = tf.reduce_min(train_data)
max_val = tf.reduce_max(train_data)

train_data = (train_data - min_val) / (max_val - min_val)
test_data = (test_data - min_val) / (max_val - min_val)

train_data = tf.cast(train_data, tf.float32)
test_data = tf.cast(test_data, tf.float32)

이 데이터 세트에서 1 로 레이블이 지정된 일반 리듬 만 사용하여 오토 인코더를 훈련합니다. 정상 리듬과 비정상 리듬을 분리합니다.

train_labels = train_labels.astype(bool)
test_labels = test_labels.astype(bool)

normal_train_data = train_data[train_labels]
normal_test_data = test_data[test_labels]

anomalous_train_data = train_data[~train_labels]
anomalous_test_data = test_data[~test_labels]

정상적인 ECG를 플로팅합니다.

plt.grid()
plt.plot(np.arange(140), normal_train_data[0])
plt.title("A Normal ECG")
plt.show()

png

비정상적인 ECG를 플로팅합니다.

plt.grid()
plt.plot(np.arange(140), anomalous_train_data[0])
plt.title("An Anomalous ECG")
plt.show()

png

모델 구축

class AnomalyDetector(Model):
  def __init__(self):
    super(AnomalyDetector, self).__init__()
    self.encoder = tf.keras.Sequential([
      layers.Dense(32, activation="relu"),
      layers.Dense(16, activation="relu"),
      layers.Dense(8, activation="relu")])

    self.decoder = tf.keras.Sequential([
      layers.Dense(16, activation="relu"),
      layers.Dense(32, activation="relu"),
      layers.Dense(140, activation="sigmoid")])

  def call(self, x):
    encoded = self.encoder(x)
    decoded = self.decoder(encoded)
    return decoded

autoencoder = AnomalyDetector()
autoencoder.compile(optimizer='adam', loss='mae')

오토 인코더는 일반 ECG 만 사용하여 훈련되지만 전체 테스트 세트를 사용하여 평가됩니다.

history = autoencoder.fit(normal_train_data, normal_train_data, 
          epochs=20, 
          batch_size=512,
          validation_data=(test_data, test_data),
          shuffle=True)
Epoch 1/20
5/5 [==============================] - 0s 20ms/step - loss: 0.0582 - val_loss: 0.0534
Epoch 2/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0564 - val_loss: 0.0519
Epoch 3/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0540 - val_loss: 0.0508
Epoch 4/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0514 - val_loss: 0.0491
Epoch 5/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0482 - val_loss: 0.0467
Epoch 6/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0448 - val_loss: 0.0449
Epoch 7/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0414 - val_loss: 0.0429
Epoch 8/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0380 - val_loss: 0.0413
Epoch 9/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0345 - val_loss: 0.0400
Epoch 10/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0316 - val_loss: 0.0390
Epoch 11/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0293 - val_loss: 0.0382
Epoch 12/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0276 - val_loss: 0.0379
Epoch 13/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0262 - val_loss: 0.0370
Epoch 14/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0251 - val_loss: 0.0366
Epoch 15/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0244 - val_loss: 0.0359
Epoch 16/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0237 - val_loss: 0.0355
Epoch 17/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0231 - val_loss: 0.0352
Epoch 18/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0225 - val_loss: 0.0345
Epoch 19/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0219 - val_loss: 0.0343
Epoch 20/20
5/5 [==============================] - 0s 5ms/step - loss: 0.0214 - val_loss: 0.0341

plt.plot(history.history["loss"], label="Training Loss")
plt.plot(history.history["val_loss"], label="Validation Loss")
plt.legend()
<matplotlib.legend.Legend at 0x7f21d014f438>

png

재구성 오류가 일반 교육 예제에서 표준 편차 1보다 큰 경우 ECG를 비정상으로 분류합니다. 먼저 학습 세트의 일반 ECG, 오토 인코더에 의해 인코딩 및 디코딩 된 후의 재구성 및 재구성 오류를 플로팅 해 보겠습니다.

encoded_imgs = autoencoder.encoder(normal_test_data).numpy()
decoded_imgs = autoencoder.decoder(encoded_imgs).numpy()

plt.plot(normal_test_data[0],'b')
plt.plot(decoded_imgs[0],'r')
plt.fill_between(np.arange(140), decoded_imgs[0], normal_test_data[0], color='lightcoral' )
plt.legend(labels=["Input", "Reconstruction", "Error"])
plt.show()

png

이번에는 비정상적인 테스트 예제를 위해 비슷한 플롯을 만듭니다.

encoded_imgs = autoencoder.encoder(anomalous_test_data).numpy()
decoded_imgs = autoencoder.decoder(encoded_imgs).numpy()

plt.plot(anomalous_test_data[0],'b')
plt.plot(decoded_imgs[0],'r')
plt.fill_between(np.arange(140), decoded_imgs[0], anomalous_test_data[0], color='lightcoral' )
plt.legend(labels=["Input", "Reconstruction", "Error"])
plt.show()

png

이상 징후 감지

재구성 손실이 고정 임계 값보다 큰지 여부를 계산하여 이상을 감지합니다. 이 자습서에서는 훈련 세트의 일반 예제에 대한 평균 평균 오차를 계산 한 다음 재구성 오차가 훈련 세트의 표준 편차보다 큰 경우 향후 예제를 비정상적인 것으로 분류합니다.

훈련 세트의 정상 ECG에 대한 재구성 오류를 플로팅합니다.

reconstructions = autoencoder.predict(normal_train_data)
train_loss = tf.keras.losses.mae(reconstructions, normal_train_data)

plt.hist(train_loss, bins=50)
plt.xlabel("Train loss")
plt.ylabel("No of examples")
plt.show()

png

평균보다 한 표준 편차가 높은 임계 값을 선택하십시오.

threshold = np.mean(train_loss) + np.std(train_loss)
print("Threshold: ", threshold)
Threshold:  0.033377893

테스트 세트의 비정상적인 예에 ​​대한 재구성 오류를 조사하면 대부분 임계 값보다 더 큰 재구성 오류가 있음을 알 수 있습니다. 임계 값을 변경하여 분류기의 정밀도재현율 을 조정할 수 있습니다.

reconstructions = autoencoder.predict(anomalous_test_data)
test_loss = tf.keras.losses.mae(reconstructions, anomalous_test_data)

plt.hist(test_loss, bins=50)
plt.xlabel("Test loss")
plt.ylabel("No of examples")
plt.show()

png

재구성 오류가 임계 값보다 큰 경우 ECG를 이상으로 분류합니다.

def predict(model, data, threshold):
  reconstructions = model(data)
  loss = tf.keras.losses.mae(reconstructions, data)
  return tf.math.less(loss, threshold)

def print_stats(predictions, labels):
  print("Accuracy = {}".format(accuracy_score(labels, preds)))
  print("Precision = {}".format(precision_score(labels, preds)))
  print("Recall = {}".format(recall_score(labels, preds)))
preds = predict(autoencoder, test_data, threshold)
print_stats(preds, test_labels)
Accuracy = 0.944
Precision = 0.9921875
Recall = 0.9071428571428571

다음 단계

오토 인코더를 사용한 이상 탐지에 대해 자세히 알아 보려면 Victor Dibia가 TensorFlow.js로 구축 한이 훌륭한 대화 형 예제를 확인하십시오. 실제 사용 사례의 경우 Airbus가 TensorFlow를 사용하여 ISS 원격 측정 데이터에서 이상을 감지 하는 방법을 알아볼 수 있습니다. 기본 사항에 대해 자세히 알아 보려면 François Chollet의이 블로그 게시물 을 읽어보십시오. 자세한 내용은 Ian Goodfellow, Yoshua Bengio 및 Aaron Courville의 Deep Learning 에서 14 장을 확인하십시오.