"BOKU"のITな日常

62歳・文系システムエンジニアの”BOKU”は日々勉強を楽しんでます

kerasブログのAutoencoderサンプルをTensorflow2.0環境で動かす

「Building Autoencoders in Keras」という有名な記事のサンプルを、Tensorflow2.0環境で動くように手直ししてみました。

f:id:arakan_no_boku:20200604232413p:plain

 

Building Autoencoders in Keras

 

この「Building Autoencoders in Keras」は、keras Blogの記事です。

f:id:arakan_no_boku:20200604232716p:plain

当時、探したAutoencoderのサンプルでは、一番わかりやすかった気がしています。

英語ですけど、ソースコードが読みやすかったので。

ブックマークの整理中にたまたま見つけて、久しぶりに動かしてみました。

でも、悲しいかな、まともに動きません。

Tensorflow2.0にバージョンをあげていたからのようです。

放置するのも気持ち悪いので、ちょっと手を入れて動くようにしてみました・・というのが今回の話題です。

 

変更したポイント

 

Tensorflos2.0にkerasは一体化しています。

なので、以前のkerasを別途インストールしていた時とは、importのパスが違います。

ブログのサンプルは。

from keras.layers import Input, Dense
from keras.models import Model

 なのですが、現在(tensorflow2.2で動作確認)では

import tensorflow as tf
from tensorflow.keras.layers import Dense

となり、InputとModelは以下のように、tf.kerasをつけてソースに記述しました。

tf.keras.Input

tf.keras.Model

 これで、importのエラーは消えますし、エラーなく動くのですが、ロス率が高いまま(自分の環境だと0.7くらいから)じりじりとしか下がりません。

ロス率が0.09くらいにはならないと、AutoEncoderのアウトプットはグチャグチャなままになります。

その原因はここです。

autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')

エラーにはなりませんが、この書き方は非推奨になったようです。

そこで。

lossの指定を、tf.keras.losses.BinaryCrossentropy()に変更し、optimizerを「adadelta」から「adam」に変更します。

autoencoder.compile(optimizer='adam', loss=tf.keras.losses.BinaryCrossentropy())

 自分の環境だと、これで一気に改善しました。

 

ソースコード全文です

 

Deep autoencoderのケースだけやってます。

import tensorflow as tf
from tensorflow.keras.layers import Dense
from tensorflow.keras.datasets import mnist
import numpy as np
import matplotlib.pyplot as plt


# this is the size of our encoded representations
encoding_dim = 32  # 32 floats -> compression of factor 24.5, assuming the input is 784 floats

# this is our input placeholder
input_img = tf.keras.Input(shape=(784,))

encoded = Dense(128, activation='relu')(input_img)
encoded = Dense(64, activation='relu')(encoded)
encoded = Dense(32, activation='relu')(encoded)

decoded = Dense(64, activation='relu')(encoded)
decoded = Dense(128, activation='relu')(decoded)
decoded = Dense(784, activation='sigmoid')(decoded)
# this model maps an input to its reconstruction
autoencoder = tf.keras.Model(inputs=input_img, outputs=decoded)

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

x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = x_train.reshape((len(x_train), np.prod(x_train.shape[1:])))
x_test = x_test.reshape((len(x_test), np.prod(x_test.shape[1:])))
print(x_train.shape)
print(x_test.shape)

# autoencoder.load_weights('autoencoder.h5')

autoencoder.compile(optimizer='adam', loss=tf.keras.losses.BinaryCrossentropy())
autoencoder.fit(x_train, x_train,
                epochs=100,
                batch_size=256,
                shuffle=True,
                validation_data=(x_test, x_test))

autoencoder.save_weights('autoencoder.h5')
# encode and decode some digits
# note that we take them from the *test* set
decoded_imgs = autoencoder.predict(x_test)

n = 10  # how many digits we will display
plt.figure(figsize=(10, 4))

for i in range(n):
    # display original
    ax = plt.subplot(2, n, i + 1)
    plt.imshow(x_test[i].reshape(28, 28))
    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].reshape(28, 28))
    plt.gray()
    ax.get_xaxis().set_visible(False)
    ax.get_yaxis().set_visible(False)
plt.show()

毎回学習するのも時間の無駄なので、サンプルにはありませんが

autoencoder.save_weights('autoencoder.h5')

を追加しています。

一度学習したあとは、こちらをコメントアウトして、こちら 

# autoencoder.load_weights('autoencoder.h5')

のコメントを外して、結果表示してます。

これを実行すると、ロス率が0.08から0.09の間くらいになって、以下のように上段が元画像・下段に結果画像を10個だけ表示します。

f:id:arakan_no_boku:20200605002606p:plain

まあまあ。

ブログのサンプル程度には再現できていると思います。

今回はこんなところで。

ではでは。