KerasでMNIST

#とりあえず書いてみた
KerasでMNISTコードを書くのは初めてだったので、このサイトを参考に書いてみた
http://aidiary.hatenablog.com/entry/20161109/1478696865

####はじめにMNISTのデータを準備する

```py3
from keras.datasets import mnist
from keras.utils import np_utils

(x_train,y_train),(x_test,y_test) = mnist.load_data()
```
####データを使える形に変換する。

```py3
x_train = x_train.reshape(len(x_train),784)
x_test = x_test.reshape(len(x_test),784)

x_train = x_train.astype("float32")
x_test = x_test.astype("float32")

x_train = x_train / 255
x_test = x_test / 255

print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

nb_classes = 10

y_train = np_utils.to_categorical(y_train,nb_classes)
y_test = np_utils.to_categorical(y_test,nb_classes)
```

入力データ（`x_train`,`x_test`）はもともと28x28の二次元配列なのでそれを784の一次元配列に変換する。また０〜２５５という数字は扱えないので０〜１に変換するために２５５で割っている。
出力データ（`y_train`,`y_test`）はもともと数字が入っているがone-hot形式に変換したほうが使いやすいので`np_utils.to_categorical()`を使う。

####実際にモデルを作る

```py3
def build_model():
    model = Sequential()
    model.add(Dense(512, input_shape=(784,)))
    model.add(Activation("relu"))
    model.add(Dropout(0.2))
    model.add(Dense(512))
    model.add(Activation("relu"))
    model.add(Dropout(0.2))
    model.add(Dense(10))
    model.add(Activation("softmax"))
    
    return model

model = build_model()

model.summary()

model.compile(loss="categorical_crossentropy",
             optimizer=Adam(),
             metrics=['accuracy'])
```
ここでは`model.summary()`はモデルの層を表示するだけなので書かなくてもいいが今回は見てみたかったので書いておいた。
実際に実行すると下のような出力になった。

```:output
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_1 (Dense)              (None, 512)               401920    
_________________________________________________________________
activation_1 (Activation)    (None, 512)               0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_2 (Dense)              (None, 512)               262656    
_________________________________________________________________
activation_2 (Activation)    (None, 512)               0         
_________________________________________________________________
dropout_2 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_3 (Dense)              (None, 10)                5130      
_________________________________________________________________
activation_3 (Activation)    (None, 10)                0         
=================================================================
Total params: 669,706
Trainable params: 669,706
Non-trainable params: 0
_________________________________________________________________
```
####学習させてみる
参考にしたサイトに過学習を防止するためのコードが書かれていたので少し変えて使用させていただいた。

```py3
early_stopping = EarlyStopping(patience=2)

model.fit(x_train,y_train,
          batch_size=32,
          epochs=100,
          verbose=1,
          validation_split=0.1,
          shuffle=True,
          callbacks=[early_stopping])
```
ここでは`EarlyStopping`を利用して過学習をしているようなら中断するようにした。この時、`patience`を`2`にすることで学習不足も防止できるようにしてみた。（MNISTでそこまで影響があるかわからない）

これだけで実際、精度は0.98以上出ているのでしっかり学習できていると思う。

####テストデータで確認
テストデータで最後に精度を確認した

```py3
print(model.evaluate(x_test,y_test))
```
ロスと精度が出てくるので確認してみると0.97以上出てくるので精度はかなり高い。

#元のデータを加工して学習させる
元のデータを少し回転させてもっと読み取り精度を高めてみた
回転させるためにはPILを使った。
下をインポートする。

```py3
from PIL import Image
import numpy as np
```
まずは入力データに回転を加えた。

```py3

#deg = 回転させる角度
#n = 生成する枚数
def rotate_array(x_array,deg,n):
    def rotate(x):
        img = Image.fromarray(x)
        
        arr = []
        for _ in range(n):
            arr.append(np.asarray(img.rotate(np.random.rand()*deg*2-deg)))
        
        return arr
    
    x_out = []
    for x in x_array:
        arr = rotate(x)
        
        for a in arr:
            x_out.append(a)
        
    return np.array(x_out)

x_train = rotate_array(x_train,30,10)
x_test = rotate_array(x_test,30,10)
```
これだけでは出力側と合わなくなるので下のコードを書いた。

```py3
def add_y(y_array,n):
    y_out = []
    for y in y_array:
        for _ in range(n):
            y_out.append(y)
            
    return np.array(y_out)

y_train = add_y(y_train,10)
y_test = add_y(y_test,10)
```
####回転したデータで学習
これでデータに回転がかかり学習できる状態になったので学習させた
10倍のデータがあるので自分の環境では時間がかった。`model.fit()`の中の`batch_size`を`128`にあげるともう少し早く終了した。
精度は0.98以上が出ていた。

#結果
予想していたよりも簡単にとても高い精度が出るものが作れた。
このあと角度を45度、60度で試してみたがどちらもとても高い精度が出て驚いた。
Kerasを利用して他の画像認識なども試してみようと思った。