【超初心者による】Keras(Tensorflowベース)でCNNを使った画像認識

今回は「Pythonによるスクレイピング&機械学習」のコードを材料に自分なりに勉強した事書きなぐってみました。
プログラム自体も初心者なので当たり前のメモ等ありますがご容赦ください！

##まずはCaltechというサイトから画像を取得し、機械学習しやすい形に整形
```python:caltech101_makedata.py
from sklearn import cross_validation
from PIL import Image
import os, glob
import numpy as np

#分類対象のカテゴリーを選ぶ
caltech_dir = "./image/101_ObjectCategories" # .から打つと.が自分の今いる場所ということになる
categories = ["chair", "camera","butterfly","elephant","flamingo"]
nb_classes = len(categories)

#画像サイズ指定
image_w = 64
image_h = 64
pixels = image_w * image_h * 3 #ここの3はRGBの３つという意味

#画像データを読み込み
X = [] #実際のデータをXに、そのデータが何を表すかのラベルをYにいれていく。
Y = []

for idx, cat in enumerate(categories): #enumerate関数は、ループの際にそのcategoriesの要素と一緒にインデックスもいれてくれる！なので一週目はidxには0, catにはchairが入る！
    #ラベルを指定 ---
    label = [0 for i in range(nb_classes)] #ここではおそらく、カテゴリーの数だけの0を要素として持つ配列を生成している。そんでもって現在のindexのものだけを１に書き換えることで、そのカテゴリに対応するラベルを生成？
    label[idx] = 1
    #画像
    image_dir = caltech_dir + "/" + cat
    files = glob.glob(image_dir+"/*.jpg") #ここではモジュールとして入れてたglobを使用。これはパターンにマッチする名前でファイルを探す時に役立つ。今はjpgのものだけ引っ掛けている。おそらく画像がまばらで変なjpg以外のものも混ざっているのだろう。*はなんでもって意味かな。
    for i, f in enumerate(files):
        img = Image.open(f) #このImage.openとかでてきたらライブラリのPILの出番。これは画像処理をあんじょうやってくれる。resizeも下記の通り楽チン。一旦.openで開かなっきゃいけないみたい。
        img = img.convert("RGB")
        img = img.resize((image_w, image_h))
        data = np.asarray(img) #ここはこの写真をnumpyのarrayにしてみただけ
        X.append(data)
        Y.append(label)
        if i % 10 == 0: # %は余りを求めるもの。　ここでは10で割って割り切れるものを指定。んで１０個ごとにprintしている、
            print(i, "\n", data)
X = np.array(X)
Y = np.array(Y)

# 学習データとテストデータを分ける
X_train, X_test, y_train, y_test = cross_validation.train_test_split(X,Y) #このtrain_test_split関数は一定の割合が検証用データになるように開発データを分割する関数。引数に検証用データの割合も指定できる。デフォのままだと250と84にわかれてた。
xy = (X_train, X_test, y_train, y_test)
np.save("./image/5obj.npy", xy)

print("ok", len(Y))
```

##上記で作成したデータをKeras（Tensorflowベース）でCNNしてみる！

```python:caltech101_keras.py
from keras.models import Sequential
from keras.layers import Convolution2D, MaxPooling2D
from keras.layers import Activation, Dropout, Flatten, Dense
import numpy as np

#カテゴリー指定
categories = ["chair","camera","butterfly","elephant","flamingo"]
nb_classes = len(categories)

#画像サイズ指定
image_w = 64
image_h = 64

#データロード
X_train, X_test, y_train, y_test = np.load("./image/5obj.npy")
#データを正規化する
X_train = X_train.astype("float") / 256
X_test = X_test.astype("float") / 256
print('X_train shape:', X_train.shape)

#モデル構築
model = Sequential() #kerasではモデルはSequentialか複雑なものに対応したmodelの２つがある。Sequentialはシンプルで、層を積み重ねたもの。これは一本の線。何本もSequentialのインスタンス立てて
model.add(Convolution2D(32, 3, 3, border_mode='same', input_shape=X_train.shape[1:])) #最初の引数はfilter（kernelともいう）の数。その次はfilterの大きさ3x3ね。本当はもっとstrideとか指定できる。border_modeというのはsameにすると、元画像がフィルターかかる前にゼロパディングされる。なのでフィルターかけた後も同じサイズになる。これをvalidにするとどんどん画像は小さくなっていく。input_shapeに関しては最初の層で、入力の形を指定しなければならない。.shape[1:]の書き方は、84x64x64だったら64x64が出力される。最初の値が無視される。
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2))) #Pooling層ではそのストライドに合った最大値を取っていく。なのでデータ自体がキュッとする。ここでは32x32の出力のはず。。。
model.add(Dropout(0.25))#おそらく25%のノードを捨てるということかな。
model.add(Convolution2D(64, 3, 3, border_mode='same'))
model.add(Activation('relu'))
model.add(Convolution2D(64, 3, 3))
model.add(MaxPooling2D(pool_size=(2, 2))) #ここでは16x16になってるのではあるまいか
model.add(Dropout(0.25))

model.add(Flatten())
model.add(Dense(512))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(nb_classes))
model.add(Activation('softmax'))

model.compile(loss='binary_crossentropy',optimizer='rmsprop', metrics=['accuracy'])

#モデルを訓練
model.fit(X_train, y_train, batch_size=32, nb_epoch=50)

#モデルの評価
score = model.evaluate(X_test, y_test)
print('loss=', score[0])
print('accuracy=', score[1])
```

今回は何も工夫せずただただテキスト通り行ったため、超シンプルな構成になっている。
今後は自分なりに工夫して正答率あげていきたい。。。。

何か意見等あればぜひコメント欄にお願い致します！