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分もかからない。
なんか、前回よりも、ちゃんと入力からむりくり1
を復元しようとしている感がある。
異常検知
異常検知とは、1
じゃない画像が入力された場合には、その画像を1
と思って再構成した画像と元の画像との間には差異があるはずで、ソレを可視化できれば異常検知に使えるはずだ、という理屈。
意図どおりに動作した感がある。
本日のコード
解消できなかった課題
さて、今回は使っている画像がMNISTなので、全画像をメモリの上に置くことができたのだが、もう少し大きいサイズで、大量の画像で同様のことをやろうとすると、kerasのImageDataGenerator
のflow_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)))
どうしたら良いんでしょうね、コレ。
情報求ム。