kerasでCNN 自分で拾った画像でやってみる

### kerasでCNN 拾ってきた画像でいろいろやってみます

```
ここでは、Python2.7.6 で行なっています。また、主に以下のパッケージを利用しています。
Keras (2.0.4)
tensorflow (1.1.0)
```
### はじめに
***

kerasでCNNにチャレンジしてみました。例題のデータセットだけだと面白くないので、自分で拾ってきた画像をCNNで分類しました。

ここではCNNの理論的な部分はある程度わかっている前提で、処理の部分に焦点を当てています。
分析環境は、AWSのEC2を利用。

なお、画像に関しては必要な部分の切り出しを行なった上で実行しています。
(私はOpenCVで行いました)

### 分析環境について
***
TensorFlowをGPUで動くよう、環境を構築したかったのですが初心者には難しく…
AWSですでに環境が構築されているAMI(Bitfusion Ubuntu 14 TensorFlow)があったので、こちらを利用しています。
必要なパッケージも既に入ってます。

https://aws.amazon.com/marketplace/pp/B01EYKBEQ0

なお、上記のAMIはPython3も入っているので、そちらでも利用できるかと思います。
(なおコストはかかるので、その点はちゃんと確認ください。デフォルトのEBSサイズが100GBなので、そこも注意です)


### 必要なパッケージのインポート
***

```py

# coding:utf-8

import keras
from keras.utils import np_utils
from keras.layers.convolutional import Conv2D, MaxPooling2D
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.preprocessing.image import array_to_img, img_to_array, list_pictures, load_img
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

```


内容についてはkerasのホームページなどを参照ください。
keras.preprocessing を利用すると前処理がラクにできます。


### 画像の読み込みと行列への変換 データセットの作成
***

```py
temp_img = load_img('./test/test1.jpg', target_size=(64,64))
```
これで画像を読み込めます。target_sizeで読み込みのサイズも指定することができます。
モデルには決まったサイズの画像をinputするので、前処理で画像のサイズを揃えていない場合はここで揃えます。

モデルには行列へ変換して投入します。画像を行列へ変換するのは以下で可能です。

```py
temp_img_array  = img_to_array(temp_img)
```

shapeで形を見ると、(64, 64, 3)になっています。
これは、64×64の画像に関し各ピクセルの色(RGB)の情報を持っている、ということなんだと思います。

さて、これらを利用してデータセットを作成します。
ここでは、test1フォルダにある対象Aの画像（例えば猫）が、test2フォルダには違う対象B（例えば犬）が入っているとします。

```py
# フォルダの中にある画像を順次読み込む
# カテゴリーは0から始める

X = []
Y = []

# 対象Aの画像
for picture in list_pictures('./test1/'):
    img = img_to_array(load_img(picture, target_size=(64,64)))
    X.append(img)
    
    Y.append(0)
    

# 対象Bの画像
for picture in list_pictures('./test2/'):
    img = img_to_array(load_img(picture, target_size=(64,64)))
    X.append(img)
    
    Y.append(1)
    

# arrayに変換
X = np.asarray(X)
Y = np.asarray(Y)
```

Xに画像の情報をインプットし、Yにクラスの情報を付与しています。
続いて、画素値の正規化、クラスのデータ変換（One-Hot表現というらしい）を行います。

```py

# 画素値を0から1の範囲に変換
X = X.astype('float32')
X = X / 255.0

# クラスの形式を変換
Y = np_utils.to_categorical(Y, 2)

# 学習用データとテストデータ
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.33, random_state=111)
```

### モデルの構築
***
データセットができたので、モデルを構築していきます。
モデルについては、探せば事例はいろいろあると思うので、そういったものを参考にして構築しています。

```py

# CNNを構築
model = Sequential()

model.add(Conv2D(32, (3, 3), padding='same',
                 input_shape=X_train.shape[1:]))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Conv2D(64, (3, 3), padding='same'))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(2))       # クラスは2個
model.add(Activation('softmax'))

# コンパイル
model.compile(loss='categorical_crossentropy',
              optimizer='SGD',
              metrics=['accuracy'])

# 実行。出力はなしで設定(verbose=0)。
history = model.fit(X_train, y_train, batch_size=5, epochs=200,
                   validation_data = (X_test, y_test), verbose = 0)

```

historyの中には学習の履歴があるので、確認できます。
以下では、学習データとテストデータのaccuracyをプロットしています。

```py

plt.plot(history.history['acc'])
plt.plot(history.history['val_acc'])
plt.title('model accuracy')
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.legend(['acc', 'val_acc'], loc='lower right')
plt.show()
```

検証データに適用し、実際に適用しconfusion matrixを作成します。


```py

# テストデータに適用
predict_classes = model.predict_classes(X_test)

# マージ。yのデータは元に戻す
mg_df = pd.DataFrame({'predict': predict_classes, 'class': np.argmax(y_test, axis=1)})

# confusion matrix
pd.crosstab(mg_df['class'], mg_df['predict'])
```

### まとめ
***
DeepLearningは敷居が高かったのですが、keras使えば書きやすいと思いました。
また、分析環境は既に構築されているものを利用するとラクです。

モデルの精緻化に関してはこれから勉強します。
初心者なので間違っている部分があるかもしれませんが、もし何かあればご指摘いただけるとありがたいです。
最後までお読みいただき、ありがとうございました。