面白いデータを探して

適当に書く。間違えていたら教えてください。

オートエンコーダーを実装してみた

tensorflowの練習としてautoencoderを実装してみた。

オートエンコーダーとは

オートエンコーダー(自己符号化器)とは、あるデータを入力とし、同じデータを出力として学習を行うようなニューラルネットワークである。
図にするとこんな感じ。

f:id:netres:20180703001958p:plain

オートエンコーダーは2つの部分からなる。
まずはあるデータxを入力としある特徴量zを出力するエンコーダーの部分。そして、特徴量zからxを復元する(これをx'としている)デコーダー部分である。
このような学習を行うことで何ができるかというと、オートエンコーダーは入力の特徴を低次元に削減することができる。上の図で言えば、隠れ層の$z$は入力$x$の特徴を学習しているというわけだ。
より詳しい説明もたくさん出回っているので、気になった人はチェックしてほしい。

実装

今回実装するのは最もシンプルなオートエンコーダー
エンコーダー : z=\sigma(W_1 x + b_1)
デコーダー : x'=\sigma (W_2 z + b_2)
ここで、\sigma(x)シグモイド関数
損失関数はクロスエントロピー \displaystyle -x*\log(x')-(1-x)*\log(1-x')を使っている。
ただし、\logの中身が0になってはいけないので、中に1e-10(10の-10乗)を足して回避している。
また、学習はtraining用のデータで、テストはtest用のデータで行う。

ソースコード
# -*- coding:utf-8 -*-

# ライブラリのインポート
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from tqdm import tqdm

# データセットの取得
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)

# モデルの設定
# x' = sigmoid(w_2*sigmoid(w_1*x+b_1)+b2)というモデル
x = tf.placeholder(tf.float32, [None, 784])

w_1 = tf.Variable(tf.random_normal([784, 625], mean=0.0, stddev=0.5), dtype=tf.float32)
b_1 = tf.Variable(tf.zeros([625]), dtype=tf.float32)
h_1 = tf.sigmoid(tf.matmul(x, w_1) + b_1)
w_2 = tf.Variable(tf.random_normal([625, 784], mean=0.0, stddev=0.5), dtype=tf.float32)
b_2 = tf.Variable(tf.zeros([784]), dtype=tf.float32)
x_dash = tf.sigmoid(tf.matmul(h_1, w_2) + b_2)

# lossの設定
# クロスエントロピー -x*log(x')-(1-x)*log(1-x')
# log(x)のxが0になるとエラーが起きるので小さな値(10^(-10))を足してそれを防ぐ
cross_entropy = -1. * x * tf.log(x_dash + 1e-10) - (1. - x) * tf.log(1. - x_dash + 1e-10)
loss = tf.reduce_sum(cross_entropy)
train = tf.train.GradientDescentOptimizer(0.01).minimize(loss)

# おまじない(初期化)とbatch_size, epoch数の設定
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)

batch_size = 100
epoch = 1000

# 学習
for i in range(epoch):
    step = i + 1
    batch_x, batch_y = mnist.train.next_batch(batch_size) # バッチからデータ生成
    sess.run(train, feed_dict={x:batch_x}) # 学習

    # 時々lossと学習結果を出力
    # テストデータの最初の10個の画像の復元をしてみる
    x_test = mnist.test.images[0:10]
    if step % 100 == 0 or step == 1:
        tmp_loss = sess.run(loss, feed_dict={x:batch_x})
        print("step:%d, loss:%6f" % (step, tmp_loss))
        plt.figure(figsize=(20, 4))
        for i in range(10):
            ax = plt.subplot(2, 10, i + 1)
            plt.imshow(x_test[i].reshape(28, 28))
            plt.gray()
            ax.get_xaxis().set_visible(False)
            ax.get_yaxis().set_visible(False)

            ax = plt.subplot(2, 10, i + 11)
            output_imgs = sess.run(x_dash, feed_dict={x:x_test})
            plt.imshow(output_imgs[i].reshape(28, 28))
            plt.gray()
            ax.get_xaxis().set_visible(False)
            ax.get_yaxis().set_visible(False)
        file_name = "figure_step_" + str(step) + ".png"
        plt.savefig(file_name)

実行結果

上が入力した画像、下がオートエンコーダーが復元した画像。
学習用のデータには入力した画像は含まれていないが、上手く特徴抽出(1, 2, 3, ,,, といった特徴)ができているため、学習用のデータに含まれていないデータもうまく学習できているように見える。

学習する前
f:id:netres:20180703004334p:plain
まだわけがわからない

100回学習した後
f:id:netres:20180703004338p:plain
ぼやっと何か見えてきた

1000回学習した後
f:id:netres:20180703004331p:plain
おおよそはっきり数字が見えるようになった

まとめ

tensorflowの練習のためにオートエンコーダーを実装して試してみた。
上手く画像の復元に成功した!!