KerasでAutoEncoderその2

[KerasでAutoEncoder](https://qiita.com/fukuit/items/2f8bdbd36979fff96b07)の続き。

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

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

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

```python
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
```

[前回の記事](https://qiita.com/fukuit/items/2f8bdbd36979fff96b07)に書いたのは以下のようになっていて、違うような同じような。

```python
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](https://github.com/keras-team/keras/blob/master/examples/variational_autoencoder_deconv.py)にある方が汎用的な気がする。

### loss関数

[前回の記事](https://qiita.com/fukuit/items/2f8bdbd36979fff96b07)では、loss関数は以下の様に定義していた。

```python
# 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](https://github.com/keras-team/keras/blob/master/examples/variational_autoencoder_deconv.py)に書いてあるものは、少し違う。

```python
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](https://github.com/keras-team/keras/blob/master/examples/variational_autoencoder_deconv.py)では、コマンドライン引数でMSEかBinaryCrossEntropyかを指定するようになっているんだけれど、いずれにせよ、上記のような定義になっている。

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

### CNNの定義

[kerasのexample](https://github.com/keras-team/keras/blob/master/examples/variational_autoencoder_deconv.py)には、CNNの定義にMaxPoolingが含まれていない。
それから、この書き方は、楽でイイな。

```python
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)
```

## 実行結果

[前回の記事](https://qiita.com/fukuit/items/2f8bdbd36979fff96b07)と同様に、数字の```1```のみを学習させてみる。

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

![20180714_001.png](https://qiita-image-store.s3.amazonaws.com/0/15553/c06c3ee4-97f1-e3b1-b41c-f6e9020b4140.png "20180714_001.png")

なんか、[前回](https://qiita.com/fukuit/items/2f8bdbd36979fff96b07)よりも、ちゃんと入力からむりくり```1```を復元しようとしている感がある。

![20180714_002.png](https://qiita-image-store.s3.amazonaws.com/0/15553/34b8beac-fe0d-73d2-bb08-5f15c3ea9fa7.png "20180714_002.png")

### 異常検知

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

![20180714_003.png](https://qiita-image-store.s3.amazonaws.com/0/15553/c6fde260-c438-2921-3a3e-8bc1cbd2ba0b.png "20180714_003.png")

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

## 本日のコード

- https://github.com/fukuit/Python_SelfLearning/blob/master/autoencoder/conv_var_autoencoder2.py

## 解消できなかった課題

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

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

### 駄目だったコード

```python
#(前略)

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)))
```

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