読者です 読者をやめる 読者になる 読者になる

ゆるふわめも

in Kyoto or Tokyo

pythonでAutoencoderを動かす

環境

python2.7, ubuntu14.04上。Kerasを使用して、入力はベクトルを想定。

モデルの定義

print(autoencoder.summary())とすればモデルに含まれるパラメータ数を出力してくれます。 今回は入力のベクトルをPolynomialFeaturesでわざと増やしています。 ようはx*y多項式の特徴をつくるため一気に次元数が増えます。

from keras.layers import Input, Dense
from keras.models import Model
from sklearn.preprocessing import PolynomialFeatures

poly = PolynomialFeatures(2).fit(train_X)
train_pX, test_pX = poly.transform(train_X), poly.transform(test_X)

encoding_dim = 32
input_v = Input(shape=(train_pX.shape[1],))
encoded = Dense(encoding_dim, activation='relu')(input_v)
decoded = Dense(train_pX.shape[1], activation='sigmoid')(encoded)
autoencoder = Model(input=input_v, output=decoded)
autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')
print(autoencoder.summary())

出力

____________________________________________________________________________________________________
Layer (type)                     Output Shape          Param #     Connected to                     
====================================================================================================
input_2 (InputLayer)             (None, 253)           0                                            
____________________________________________________________________________________________________
dense_3 (Dense)                  (None, 32)            8128        input_2[0][0]                    
____________________________________________________________________________________________________
dense_4 (Dense)                  (None, 253)           8349        dense_3[0][0]                    
====================================================================================================
Total params: 16477
____________________________________________________________________________________________________
None

モデルの訓練

誤差の減少過程を出力するためにコールバックを新しくインポート。 verbose=2は訓練中の出力のオプション。

from keras.callbacks import Callback
class LossHistory(Callback):
    def on_train_begin(self, logs={}):
        self.losses = []

    def on_batch_end(self, batch, logs={}):
        self.losses.append(logs.get('loss'))
        
plotdata = LossHistory()
autoencoder.fit(train_pX, train_pX,
                nb_epoch=50,
                batch_size=100,
                shuffle=True,
                validation_data=(test_pX, test_pX),
                verbose=2,
                callbacks=[plotdata])

誤差の減少具合

plt.plot(plotdata.losses)
plt.xlabel('train step')
plt.ylabel('binary_crossentropy')

f:id:misos:20161022050628p:plain

このモデルでは、もうこれ以上は誤差が減りそうにありません。 もう少し複雑なモデルを試してみます。

オートエンコーダーのモデルを複雑に

層の数を増やして、層の次元数を 1000 -> 500 -> 250 といった具合に半分はんぶんになっていくように定義し直します。

encoding_dim = 50
dimension = train_pX.shape[1]

input_v = Input(shape=(dimension,))
encoded2 = Dense(encoding_dim, activation='relu')(input_v)
encoded2 = Dense(int(dimension/2), activation='relu')(encoded2)
encoded2 = Dense(int(dimension/4), activation='relu')(encoded2)

decoded2 = Dense(int(dimension/4), activation='relu')(encoded2)
decoded2 = Dense(int(dimension/2), activation='relu')(decoded2)
decoded2 = Dense(dimension, activation='sigmoid')(encoded2)

autoencoder2 = Model(input=input_v, output=decoded2)
autoencoder2.compile(optimizer='adadelta', loss='binary_crossentropy')
print(autoencoder.summary())
print(autoencoder.summary())
____________________________________________________________________________________________________
Layer (type)                     Output Shape          Param #     Connected to                     
====================================================================================================
input_3 (InputLayer)             (None, 253)           0                                            
____________________________________________________________________________________________________
dense_5 (Dense)                  (None, 50)            12700       input_3[0][0]                    
____________________________________________________________________________________________________
dense_6 (Dense)                  (None, 126)           6426        dense_5[0][0]                    
____________________________________________________________________________________________________
dense_7 (Dense)                  (None, 63)            8001        dense_6[0][0]                    
____________________________________________________________________________________________________
dense_10 (Dense)                 (None, 253)           16192       dense_7[0][0]                    
====================================================================================================
Total params: 43319
____________________________________________________________________________________________________
None

パラメータ数はさっきの五倍近くになりました。

二つのモデルの比較

新しいオートエンコーダーをエポック数、バッチサイズを同条件にして訓練。 そのあと損失関数の減少具合を比較してみます。

plotdata2 = LossHistory()
autoencoder2.fit(train_pX, train_pX,
                nb_epoch=50,
                batch_size=100,
                shuffle=True,
                validation_data=(test_pX, test_pX),
                verbose=2,
                callbacks=[plotdata2])

plt.plot(plotdata.losses, label='simple model')
plt.plot(plotdata2.losses, label='complex model', alpha=.5)
plt.xlabel('train step')
plt.ylabel('binary_crossentropy')
plt.legend()

f:id:misos:20161022052410p:plain

青色が複雑にしたモデルの結果です。 わずかに精度改善しただけなので、モデルの層を増やすのではなくバッチサイズなどの他パラメータが原因で精度が止まっている可能性があることがわかりました。

参考

Building Autoencoders in Keras