Digit Recognizer Sample (Deep Neural Network Keras way) を読んで勉強する

[Digit Recognizer の Tutorial](https://www.kaggle.com/c/digit-recognizer#tutorial) で紹介されている Notebook その 2 ([Deep Neural Network Keras way](https://www.kaggle.com/poonaml/deep-neural-network-keras-way)) を読んで見て機械学習を勉強する。

# Import all required libraries

```py
import numpy as np
import pandas as pd

import matplotlib.pyplot as plt
%matplotlib inline

from keras.models import Sequential
from keras.layers import Dense, Dropout, Lambda, Flatten
from keras.optimizers import Adam, RMSprop
from sklearn.model_selection import train_test_split

from subprocess import check_output
```

* Sequential
    * 層を重ねたニューラルネットワークのモデルを表す
* Dense
    * 通常の全結合ニューラルネットワークレイヤー
* Dropout
    * 入力にドロップアウトを適用する
    * 過学習を防ぐための仕組み
    * [ドロップアウトを説明している記事](http://sonickun.hatenablog.com/entry/2016/07/18/191656)
* Lambda
    * 任意の式をラップする
    * レイヤー内で特殊な？複雑な？計算をしたいときに使用する
* Flatten
    * 入力を平滑化する
    * ノイズの除去や特徴の強調などで使われるよう
    * [平滑化を説明している記事](https://qiita.com/icoxfog417/items/53e61496ad980c41a08e#%E5%B9%B3%E6%BB%91%E5%8C%96%E3%82%B9%E3%83%A0%E3%83%BC%E3%82%B8%E3%83%B3%E3%82%B0)
* Adam
    * 最適化アルゴリズムの一つ
    * 最適化とは最適化問題を解くことで、与えられた条件で最小（最大）の解を求めること
    * [最適化問題を説明している記事](https://www.albert2005.co.jp/knowledge/machine_learning/optimisation_basics/optimisation_problem)
    * [Adam の式](http://postd.cc/optimizing-gradient-descent/#adam)
* RMSprop
    * 最適化アルゴリズムの一つ
    * [RMSprop の式](http://postd.cc/optimizing-gradient-descent/#rmsprop)

# Load Train and Test data

```py
train = pd.read_csv("../input/train.csv")
print(train.shape)
train.head()
```

```py
test= pd.read_csv("../input/test.csv")
print(test.shape)
test.head()
```

* shape: 行数, 列数を返す
* head: 最初の x 行のデータを返す。デフォルトは 5

```py
X_train = (train.ix[:,1:].values).astype('float32')
y_train = train.ix[:,0].values.astype('int32')
X_test = test.values.astype('float32')
```

* ix: 行・列を指定してデータを取り出す
    * loc, iloc を使えと warning が出た
* astype: 複数データを型変換できる

```py
X_train = X_train.reshape(X_train.shape[0], 28, 28)

for i in range(6, 9):
    plt.subplot(330 + (i+1))
    plt.imshow(X_train[i], cmap=plt.get_cmap('gray'))
    plt.title(y_train[i]);
```

* (num_images, img_rows, img_cols) の形式にデータを変換
* ラベル付きでデータを表示

```py
X_train = X_train.reshape(X_train.shape[0], 28, 28,1)
X_train.shape

X_test = X_test.reshape(X_test.shape[0], 28, 28,1)
X_test.shape
```

* グレースケールのために一次元追加

# Preprocessing the digit images

* 標準化
* 最も大切な前処理

```py
mean_px = X_train.mean().astype(np.float32)
std_px = X_train.std().astype(np.float32)

def standardize(x): 
    return (x-mean_px)/std_px
```

# One Hot encoding of labels

* One Hot ベクトルは多くの次元が 0 、一つの次元が 1 となる
* 整数 n は、n 次元目が 1 となるベクトルで表現される
* 例 : `3 would be [0,0,0,1,0,0,0,0,0,0]`
* to_categorical で One HOt ベクトルに変換している

```py
from keras.utils.np_utils import to_categorical
y_train= to_categorical(y_train)
num_classes = y_train.shape[1]
num_classes
```

10 番目のラベルを plot すると

```py
plt.title(y_train[9])
plt.plot(y_train[9])
plt.xticks(range(10));
```

3 となった

# Designing Neural Network Architecture

* 再現性のために random seed を指定

```py
seed = 43
np.random.seed(seed)
```

# Linear Model

* EarlyStopping
    * コールバックの関数
    * 監視する値の変化が停止した時に訓練を終了する
* BatchNormalization
    * 各バッチ毎に前の層の出力を正規化する、正規化手法の一つ
    * [Batch Normalization を説明した記事](https://deepage.net/deep_learning/2016/10/26/batch_normalization.html)
* Convolution2D
    * 2次元入力をフィルターする畳み込み層
    * 畳み込みとは特徴量を計算することのよう
    * [畳み込みを説明している記事 1](https://deepage.net/deep_learning/2016/11/07/convolutional_neural_network.html)
    * [畳み込みを説明している記事 2](http://postd.cc/how-do-convolutional-neural-networks-work/)
* MaxPooling2D
    * 空間データのマックスプーリング演算
    * [Deep learning を説明している記事]
        * プーリングとは画像で言う低画像化のことで、畳み込み演算における計算の削減を可能にするとのこと

```py
from keras.models import Sequential
from keras.layers.core import  Lambda, Dense, Flatten, Dropout
from keras.callbacks import EarlyStopping
from keras.layers import BatchNormalization, Convolution2D, MaxPooling2D
```

* Keras Sequential 層からシンプルなモデルを作成する
    * 合計、平均、指数のようなシンプルな演算を Lambda 層で行う
        * 1st 層で (rows, columns, colour channel) 形式でデータの入力次元を定義する
    * 入力を一次配列に平滑化する
    * Dense は fully connected layer（全てのニューロンと接続する層） 
        * 最後の層で出力する次元・クラスを指定する
        * 今回は 10 種類の整数を出力するので 10 を指定する
        * [activation（活性化関数）](https://keras.io/ja/activations/)
        * [活性化関数を説明している記事](https://qiita.com/namitop/items/d3d5091c7d0ab669195f)
            * 入力に対して、どのように出力するかを決める関数のよう

```py
model= Sequential()
model.add(Lambda(standardize,input_shape=(28,28,1)))
model.add(Flatten())
model.add(Dense(10, activation='softmax'))
print("input shape ",model.input_shape)
print("output shape ",model.output_shape)
```

# Compile network

* トレーニングのためのネットワークを作成する前に、以下のことを追加する必要がある
    * 損失関数 : ネットワークを評価する
        * [いくつかの損失関数を説明している記事](http://s0sem0y.hatenablog.com/entry/2017/06/19/084210)
        * [なぜ損失で評価をするのかわかりやすい記事](http://designcode.jp/2017/02/05/8-%E8%80%83%E5%AF%9F%E5%AD%A6%E7%BF%92%E3%81%AB%E7%B2%BE%E5%BA%A6%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%8F%E6%90%8D%E5%A4%B1%E3%82%92%E6%8C%87%E6%A8%99%E3%81%AB%E3%81%99%E3%82%8B%E7%90%86%E7%94%B1/)
            * 損失に注目することで細かく評価できるよう
    * 最適化 : 値の損失を減らして、より多くのデータを見えるようにネットワークを更新
    * 評価関数 : ネットワークのパフォーマンスをモニターする

* compile で optimizer, loss, metrics を設定
    * [RMSprop](https://keras.io/optimizers/#rmsprop)
        * lr: 学習率
        * 学習率とは、学習していく中でどれくらい重みを変えていくかを決めるものらしい
    * categorical_crossentropy
        * 目的関数を交差エントロピー誤差にする
        * [交差エントロピーを説明してる記事](http://cookie-box.hatenablog.com/entry/2017/05/07/121607)
    * metrics（評価関数）
        * accuracy（精度）を metrics として使う
        * 内容はわからなかったが Keras で用意している metrics


```py
from keras.optimizers import RMSprop
model.compile(optimizer=RMSprop(lr=0.001),
 loss='categorical_crossentropy',
 metrics=['accuracy'])
```

* ImageDataGenerator
    * 前処理として、画像データの拡張を簡単に行うためのクラス
    * [ImageDataGenerator の色々な処理を説明している記事](http://aidiary.hatenablog.com/entry/20161212/1481549365)


```py
from keras.preprocessing import image
gen = image.ImageDataGenerator()
```

* [flow](https://keras.io/ja/preprocessing/image/)
    * (データ, ラベル) を引数にバッチを生成する

```py
from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.10, random_state=42)
batches = gen.flow(X_train, y_train, batch_size=64)
val_batches=gen.flow(X_val, y_val, batch_size=64)
```

* [fit_generator](https://keras.io/ja/models/model/)
    * バッチ毎に生成されたデータでモデルを訓練する
    * validation_data はハイパーパラメータの調整に使われるよう
    * [ハイパーパラメータの調整手法を紹介している記事](https://qiita.com/cvusk/items/1f3b178f34c39beb29ff)

```py
history=model.fit_generator(batches, batches.n, nb_epoch=1, 
                    validation_data=val_batches, nb_val_samples=val_batches.n)
```

* history
    * [エポック](https://keras.io/ja/getting-started/faq/#samplebatchepoch)ごとの損失や精度が格納されており後から評価するのに使えるらしい
    * [History を使って可視化してる記事](https://qiita.com/hiroyuki827/items/213146d551a6e2227810)

```py
history_dict = history.history
history_dict.keys()
```

* 以下でプロットしてる
    * epoch を 1 にしているで一点しかプロットされない

```py
import matplotlib.pyplot as plt
%matplotlib inline
loss_values = history_dict['loss']
val_loss_values = history_dict['val_loss']
epochs = range(1, len(loss_values) + 1)

# "bo" is for "blue dot"
plt.plot(epochs, loss_values, 'bo')
# b+ is for "blue crosses"
plt.plot(epochs, val_loss_values, 'b+')
plt.xlabel('Epochs')
plt.ylabel('Loss')

plt.show()
```

```py
plt.clf()   # clear figure
acc_values = history_dict['acc']
val_acc_values = history_dict['val_acc']

plt.plot(epochs, acc_values, 'bo')
plt.plot(epochs, val_acc_values, 'b+')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')

plt.show()
```

値を変えて学習

```py
model.optimizer.lr=0.01
gen = image.ImageDataGenerator()
batches = gen.flow(X_train, y_train, batch_size=64)
history=model.fit_generator(batches, batches.n, nb_epoch=1)
```

提出用ファイル作成

```py
predictions = model.predict_classes(X_test, verbose=0)

submissions=pd.DataFrame({"ImageId": list(range(1,len(predictions)+1)),
                         "Label": predictions})
submissions.to_csv("DR.csv", index=False, header=True)
```