Python
Keras
Autoencoder

KerasでAutoEncoderその2

KerasでAutoEncoderの続き。

Kearsのexamplesの中にvariational autoencoderがあったのだ

以上のように、KerasのBlogに書いてあるようにやればOKなんだけれど、Deep Convolutional Variational Autoencoderについては、サンプルコードが書いてないので、チャレンジしてみる。

とか前回の記事には書いてたんだけれど、https://github.com/keras-team/keras/blob/master/examples/variational_autoencoder_deconv.py は、ConvolutionでVariationalなAutoEncoderだった。

潜在変数を求める関数sampling()

def sampling(args):
    z_mean, z_log_var = args
    batch = K.shape(z_mean)[0]
    dim = K.int_shape(z_mean)[1]
    epsilon = K.random_normal(shape=(batch, dim))
    return z_mean + K.exp(0.5 * z_log_var) * epsilon

前回の記事に書いたのは以下のようになっていて、違うような同じような。

def sampling(args):
    z_mean, z_log_var = args
    latent_dim = 20
    epsilon_std = 1.0
    epsilon = K.random_normal(shape=(K.shape(z_mean)[0],
                                     K.shape(z_mean)[1],
                                     K.shape(z_mean)[2],
                                     latent_dim),
                              mean=0.,
                              stddev=epsilon_std)
    return z_mean + K.exp(z_log_var / 2) * epsilon

多分、kerasのsampleにある方が汎用的な気がする。

loss関数

前回の記事では、loss関数は以下の様に定義していた。

# loss関数
# Compute VAE loss
xent_loss = K.mean(metrics.binary_crossentropy(input_img, decoded), axis=-1)
kl_loss =  - 0.5 * K.mean(K.sum(1 + K.log(K.square(z_log_var)) - K.square(z_mean) - K.square(z_log_var), axis=-1))
vae_loss = K.mean(xent_loss + kl_loss)

けれど、kerasのexampleに書いてあるものは、少し違う。

reconstruction_loss = binary_crossentropy(K.flatten(inputs),
                                          K.flatten(outputs))

reconstruction_loss *= image_size * image_size
kl_loss = 1 + z_log_var - K.square(z_mean) - K.exp(z_log_var)
kl_loss = K.sum(kl_loss, axis=-1)
kl_loss *= -0.5
vae_loss = K.mean(reconstruction_loss + kl_loss)

kerasのexampleでは、コマンドライン引数でMSEかBinaryCrossEntropyかを指定するようになっているんだけれど、いずれにせよ、上記のような定義になっている。

特にimage_size*image_sizeを乗算するところとか、どんな意味があるのかは、ちょっと分からない。

CNNの定義

kerasのexampleには、CNNの定義にMaxPoolingが含まれていない。
それから、この書き方は、楽でイイな。

inputs = Input(shape=input_shape, name='encoder_input')
x = inputs
for i in range(2):
    filters *= 2
    x = Conv2D(filters=filters,
               kernel_size=kernel_size,
               activation='relu',
               strides=2,
               padding='same')(x)

実行結果

前回の記事と同様に、数字の1のみを学習させてみる。

ちなみに、我が家の2012年型のMacBook Pro 13inchで、CPUだけで学習させても、MNISTで50 epochs程度なら、10分もかからない。

20180714_001.png

なんか、前回よりも、ちゃんと入力からむりくり1を復元しようとしている感がある。

20180714_002.png

異常検知

異常検知とは、1じゃない画像が入力された場合には、その画像を1と思って再構成した画像と元の画像との間には差異があるはずで、ソレを可視化できれば異常検知に使えるはずだ、という理屈。

20180714_003.png

意図どおりに動作した感がある。

本日のコード

解消できなかった課題

さて、今回は使っている画像がMNISTなので、全画像をメモリの上に置くことができたのだが、もう少し大きいサイズで、大量の画像で同様のことをやろうとすると、kerasのImageDataGeneratorflow_from_directory()のお世話になる他はない。

ということで、試してみたのだけれど、fit_generator()でエラーになってしまって、どうにもうまくいかなかった。
なんか良い方法があるんかなぁ。

駄目だったコード

#(前略)

gen = ImageDataGenerator(rescale=1./255)
train_gen = gen.flow_from_directory(
    'train',
    target_size=(image_size, image_size),
    batch_size=batch_size,
    class_mode=None)
valid_gen = gen.flow_from_directory(
    'valid',
    target_size=(image_size, image_size),
    batch_size=batch_size,
    class_mode=None)

autoencoder.fit_generator(
    train_gen,
    steps_per_epoch=int(np.ceil(train_gen.samples/batch_size)),
    epochs=epochs,
    validation_data=(valid_gen, None)
    validation_steps=int(np.ceil(valid_gen.samples/batch_size)))

どうしたら良いんでしょうね、コレ。
情報求ム。