【入門】オートエンコーダー【Tensorflow, Keras】

この記事ではオートエンコーダーについて紹介します。 あまり理論的なところは突っ込まず、オートエンコーダーとはについてと、実装してどんなものかを紹介していきます。

オートエンコーダーとは

入力と出力が同一になるように学習することで、入力データの次元圧縮器(エンコーダー)を自動で生成するニューラルネットワーク(深層学習モデル)の一つです。 中間層は入力層より小さくなっています。 以下が簡単なイメージ図になります。

エンコーダーとデコーダーから構成されています。

入力を再現できるように学習することで、中間層(エンコーダーからの出力)には入力データを圧縮したデータが出力されるようになります。

用途

主な用途としては、データの次元圧縮や異常検知などがあります。

次元圧縮

入力データを再現するように学習したエンコーダーを使うことで、入力データの次元圧縮をすることができます。以下の図のように

画像データの次元圧縮などでよく用います。

異常検知

また、オートエンコーダーは異常検知などで用いられます。この記事でも紹介していますが、手順としては、正常画像だけでオートエンコーダーを学習し、そのオートエンコーダーは正常画像しか再現できない状態にします。そして推論時には不良品画像を入力すると、不良個所を再現できないので、そこが異常であると判断するものです。

詳細は以下の記事を参考にしていただければと思います。

実装 Tensorflow

オートエンコーダーをTensorflow(主にKeras)を使って実装していきます。
今回はMNISTの数字データを再構成するオートエンコーダーを作っていきます。
colabで実装しています。ソースコードはgithubにあげてあります。

まずは必要なモジュールをimportします。colabを使っていない場合にtensorflow等はimportしてください。

import os
import numpy as np
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras import datasets, layers, models
from tensorflow.keras.models import Model
import copy
from IPython import display

データセットを読み込みんで、0~1間のデータに正規化します。

(x_train, y_train), (x_test, y_test) = datasets.mnist.load_data()
x_train = x_train / 255
x_test = x_test / 255

どのような画像かをプロットして確認してみます。

def plot_imgs(imgs,shuffle=False):
    plt.figure(figsize=(10,10))
    plot_imgs = copy.deepcopy(imgs)
    if shuffle:
        np.random.shuffle(plot_imgs)
    for i in range(36):
        plt.subplot(6,6,i+1)
        plt.xticks([])
        plt.yticks([])
        plt.grid(False)
        plt.imshow(np.squeeze(imgs[i]), cmap="gray", vmin=0, vmax=1)
    plt.show()
plot_imgs(x_train)

上のコードを実行すると以下のような画像がプロットされます。今回はこの数字のデータを入力して、同じ画像を出力できるようなオートエンコーダーをつくります。

MNISTデータセット

では、オートエンコーダーを実装します。
まずはエンコーダー。28×28のデータを32次元のデータにエンコードするモデルです。

inputs = layers.Input(shape=(28, 28, 1))
x = layers.Conv2D(16, (3, 3), activation='relu', padding='same', strides=2)(inputs)
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same', strides=2)(x)
x = tf.keras.layers.Flatten()(x)
encoded = layers.Dense(32)(x)
encoder = tf.keras.Model(inputs, encoded)

次にデコーダーを実装します。32次元のデータから28×28のデータにします。

x = layers.Dense(7*7)(encoded)
x = layers.Reshape((7,7,1))(x)

x = layers.Conv2DTranspose(8, kernel_size=3, strides=2, activation='relu', padding='same')(x)
x = layers.Conv2DTranspose(16, kernel_size=3, strides=2, activation='relu', padding='same')(x)
decoded = layers.Conv2D(1, kernel_size=(3, 3), activation='sigmoid', padding='same')(x)
decoder = tf.keras.Model(encoded, decoded)

inputsとデーコーダーからの出力であるdecodedをつなげて(encoder, decoderをつなげて)オートエンコーダーを作ります。

autoencoder = tf.keras.Model(inputs, decoded)
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
autoencoder.summary()
tf.keras.utils.plot_model(autoencoder, show_shapes=True, dpi=64)

入力データと出力データを見比べるための関数を用意しておきます。

n = 10
input_num = 100
def plot_rec(input_images):
    plt.figure(figsize=(20, 4))
    decoded_imgs = autoencoder(input_images[:input_num], training=True)
    plt_index = np.random.randint(0,input_num,size=n)
    decoded_imgs = tf.squeeze(decoded_imgs)
    input_images = np.squeeze(input_images)

    for i in range(n):
        ax = plt.subplot(2, n, i + 1)
        idx = plt_index[i]
        plt.imshow(input_images[idx], cmap="gray", vmin=0, vmax=1)
        plt.title("input")
        plt.gray()
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
        
        ax = plt.subplot(2, n, i + 1 + n)
        plt.imshow(decoded_imgs[idx], cmap="gray", vmin=0, vmax=1)
        plt.title("output")
        plt.gray()
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
    plt.show()

まずは学習前のオートエンコーダーの出力を見てみます。

plot_rec(x_train)

学習していないので、まったく復元できません。

では、オートエンコーダーを学習してみます。Kerasのモデルなのでfitで学習できます。

autoencoder.fit(x_train,x_train,epochs=100, batch_size=120, shuffle=True, validation_data=(x_test,x_test))

では、もう一度オートエンコーダーからの出力を見てみます。

plot_rec(x_train)

良い感じに再現できていますね。

今回は中間層を32次元にしているので、ある程度再現できますが、これを2次元などにすると、ここまでキレイに再現できなかったりします。興味があれば実験してみてください。

コメント

タイトルとURLをコピーしました