[Keras/TensorFlow] KerasでCV(クロスバリデーション)

# 目的
ゼロからKerasとTensorFlow(TF)を自由自在に動かせるようになる。
そのための、End to Endの作業ログ(備忘録)を残す。
※環境はMacだが、他のOSでの汎用性を保つように意識。
※アジャイルで執筆しており、精度を逐次高めていく予定。


# 環境
- Mac: 10.12.3
- Python: 3.6
- TensorFlow: 1.0.1
- Keras: 2.0.2


# To Do
### Keras導入編
[Keras(Tensorflow)の環境構築](http://qiita.com/agumon/items/4d7826c2c39d0af868bd)
[KerasでMINSTの学習と予測](http://qiita.com/agumon/items/4c6ff24bfd77a5c8101d)
[KerasでTensorBoardの利用](http://qiita.com/agumon/items/114da6921c5dc4f7d7f9) 
[Kerasで重みファイルの保存/読み込み](http://qiita.com/agumon/items/91f897b7f260f6aeca95)
[Kerasで自前データの学習と予測](http://qiita.com/agumon/items/ab2de98a3783e0a93e66) 
[Kerasで転移学習](http://qiita.com/f2um2326/items/60f7bcc8ae26b5004a3a#_reference-5d15f52415912c9c2182)


### 学習のテクニック編
[KerasでCV(クロスバリデーション)](http://qiita.com/agumon/items/0df9f008a255796b5a94)<---いまココ
Kerasの学習のオプションの確認
Kerasでパラメータチューニング(グリッドサーチ etc)
Kerasで画像の水増し
Kerasで学習過程の可視化
Kerasで事前学習


# 参考
http://machinelearningmastery.com/evaluate-performance-deep-learning-models-keras/

# 概要
https://github.com/fchollet/keras/blob/master/examples/mnist_mlp.py
にあるMINSTのサンプルファイルをCVに書き換える。
sklearnを利用したが、もっと簡単の方法があるのではないかと考えてる。

# sklearnのStratifiedKFoldの利用

```py3:minst_cv.py
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.optimizers import RMSprop
from sklearn.model_selection import StratifiedKFold
import numpy

# number for CV
fold_num = 5 

batch_size = 128
num_classes = 10
epochs = 1

# fix random seed for reproducibility
seed = 7
numpy.random.seed(seed)

# load dataset
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape(60000, 784)
x_test = x_test.reshape(10000, 784)
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255

# y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

# input data
X = x_train
Y = y_train


# define X-fold cross validation
kfold = StratifiedKFold(n_splits=fold_num, shuffle=True, random_state=seed)
cvscores = []

for train, test in kfold.split(X, Y):
    # create model
    model = Sequential()
    model.add(Dense(512, activation='relu', input_shape=(784,)))
    model.add(Dropout(0.2))
    model.add(Dense(512, activation='relu'))
    model.add(Dropout(0.2))
    model.add(Dense(10, activation='softmax'))

    model.compile(loss='categorical_crossentropy',
              optimizer=RMSprop(),
              metrics=['accuracy'])
 
    # Fit the model
    model.fit(X[train], keras.utils.to_categorical(Y[train], num_classes),
                    batch_size=batch_size,
                    epochs=epochs,
                    verbose=1)


    # Evaluate
    scores = model.evaluate(X[test], keras.utils.to_categorical(Y[test], num_classes), verbose=0)
    print("%s: %.2f%%" % (model.metrics_names[1], scores[1]*100))
    cvscores.append(scores[1] * 100)

print("%.2f%% (+/- %.2f%%)" % (numpy.mean(cvscores), numpy.std(cvscores)))

```

実装のポイントとしては、MINSTは10種類の文字のマルチクラス分類問題であり、デフォルトのスクリプトでは`keras.utils.to_categorical(y_train, num_classes)`で`y_train`は(60000,)から(60000,10)に変換されてしまう。
一方で`kfold.split`の入力では(60000,)でないとエラーになる。
そこで、一度データを入力してから`keras.utils.to_categorical(Y[train], num_classes)`を利用するよう書き換える。


# 実行
```
python minst_cv.py
```

以下の結果が表示される。1エポックを5回実行したことが確認できる。

```
Epoch 1/1
47995/47995 [==============================] - 10s - loss: 0.2773 - acc: 0.9152      
acc: 96.22%
Epoch 1/1
47998/47998 [==============================] - 12s - loss: 0.2696 - acc: 0.9164      
acc: 95.78%
Epoch 1/1
48000/48000 [==============================] - 11s - loss: 0.2701 - acc: 0.9169      
acc: 96.28%
Epoch 1/1
48003/48003 [==============================] - 9s - loss: 0.2705 - acc: 0.9181       
acc: 95.61%
Epoch 1/1
48004/48004 [==============================] - 11s - loss: 0.2759 - acc: 0.9149      
acc: 96.40%
96.06% (+/- 0.31%)
```

# カラー画像の場合
入力がRGBの場合。

# 執筆中