(9/17 コード修正)OpenCVを使って自分で用意した学習用データセットを読み込んで学習させる

　自前の画像セットを用意して学習させようと思ったとき、意外とTipsがなくてつまずいたのでその部分に特化してお話しようと思います。

#やること
　MNISTの時は予め準備されていた部分を、自分で準備します。

- 学習用データセットの準備
- 対応するラベルセットの準備
- 学習用データの整形

　学習用データセットに使う画像は、集める段階から統一されたサイズのものが望ましいです。また、フォーマットも同じ方が楽です。
　最初からデータが統一されていれば、データ整形の工程はいらなくなります。

#考え方
　データセット用の配列Xとラベル用の配列Yを作って、それぞれに読み込んだデータを順番に格納していくだけです。
　ただ、画像データは同じルールにそろえる必要があるので、

- カラーモードは統一する(RGB or RGBA or GRAY etc.)
- 画像のサイズは揃える

　という点は注意です。また、ラベルデータは何かしらの方法でダミー変数に変えておきます。
　問題になるのは画像データを連続で読み込んでいく方法です。ここさえ整理できれば特に難しいことはないと思います。
　今回は、プログラム的に一番簡単な、「データセットそのものを連番にする」というやり方にしようと思います。

#なぜOpenCV？
　今回の内容をやるだけなら、Pillowの方が楽です。ですが、OpenCVで作っておけば後々動画とかへの応用が楽そうという理由でOpenCVを使いました。あとは、ぼくの記事で今まで使ってきたのがOpenCVだからっていう単純な理由もあります。

#学習セット
　ソースコードのあるディレクトリと同じ場所に「apple」「banana」というフォルダを作り、それぞれに1.jpg～20.jpgという名前でリンゴとバナナの画像ファイルを保存してください。形式は全部jpgにしてください。サイズは今回のところは適当で良いです。
　画像はGoogle等で検索してがんばって集めましょう。合計40枚くらいならなんとかなります。

#ソース

　学習データセットの読み込みの部分だけのコードを示します。本質的に重要なのは、「配列化」「規格の統一」「正規化」の3つだけなので、ひとまずコードとしては単純なパターンにしました。

###学習用データセット準備部分
```python
import numpy as np
import cv2
from keras.utils import np_utils

folder = ["apple", "banana"]

X = []
Y = []

for index, name in enumerate(folder):
    for i in range(1,20):
        files = "./" + name + "/" + str(i) + ".jpg"
        image = cv2.imread(files, 1)
        image = cv2.resize(image, (56, 56), cv2.INTER_CUBIC)

        X.append(image)
        Y.append(index)

X = np.array(X)/255
Y = np_utils.to_categorical(Y, 2)

```
　`enumerate`は、返り値として、対象の配列に入っている変数と、そのインデックスを返してくれます。これを利用すれば、ファイルの読み込み指定と同時にラベルの取得ができます。
　ファイルの読み込みですが、今回は"apple"フォルダと"banana"フォルダの下にそれぞれ1～50という名前のjpgファイルが入っているという状態まで人間の方で作業してコードを簡略化しました。
　`imread()`で画像を読み込んできたあと、`resize()`で56×56のサイズに縮小&サイズ統一しています。

　あとは、そうして加工した画像をXに放り込んで配列化＆正規化しています。また、Yに放り込んだラベルデータもダミー変数化しています。
　この辺はMNISTのときと何も変わらないのでだいじょうぶと思います。

###学習モデル
　以前、[MNISTを畳み込み層に放り込んだ時](https://qiita.com/Ka-k/items/deb59b20f3e622028455)はチャンネル情報がなかったので`reshape`レイヤーを使いましたが、今回はカラー画像なのでその処理は不要です。いきなり投入できます。
　とりあえず、Sequentialモデルを使った例を下に書きますが、モデルの構築は自由なので、全結合層に入れる前に`flatten()`で一次元化する、最後の出力が`Dense(2)`で活性化関数が`softmax`、という部分以外は自由に調整してもらって良いと思います。
　学習用データが少ないので、ドロップアウトはあまり入れない方が良いでしょう。今回は全結合層に正規化(バッチノーマライゼーション)する手法を使ってみています。

```python

from keras.models import Sequential
from keras.layers.core import Dense,Activation,Flatten
from keras.layers import Conv2D, MaxPooling2D, BatchNormalization

model = Sequential()

model.add(Conv2D(32,(3,3)))
model.add(Activation("relu"))
model.add(Conv2D(32,(3,3)))
model.add(Activation("relu"))
model.add(MaxPooling2D((2,2)))

model.add(Conv2D(32,(3,3)))
model.add(Activation("relu"))
model.add(MaxPooling2D((2,2)))

model.add(Flatten())
model.add(Dense(256))
model.add(BatchNormalization())
model.add(Activation("relu"))

model.add(Dense(2))
model.add(Activation("softmax"))
```

###コンパイル→学習実行
　いつもの流れですが念のため書いておきます。

```python
model.compile(loss="categorical_crossentropy", optimizer="sgd", metrics=["accuracy"])

hist=model.fit(X, Y, batch_size=2, verbose=1, epochs=10, validation_split=0.2)
```
　今回は精度を度外視してるので、エラーが出ずに学習がちゃんと進めばひとまず成功です。

#参考
- [KerasのCNNを使用してオリジナル画像で画像認識を行ってみる](https://newtechnologylifestyle.net/keras%E3%81%AEcnn%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E3%82%AA%E3%83%AA%E3%82%B8%E3%83%8A%E3%83%AB%E7%94%BB%E5%83%8F%E3%81%A7%E7%94%BB%E5%83%8F%E8%AA%8D%E8%AD%98%E3%82%92%E8%A1%8C%E3%81%A3/)

　大量の画像を一気に読み込む時はglobをインポートしてワイルドカードを使う方が圧倒的に楽です。↑のサイト様の記事が参考になると思います。