KerasのCNNを使用してオリジナル画像で画像認識を行ってみる
今まではMNISTやscikit-learn等の予め用意されていたデータを使用して画像認識などを行っていました。今回からいよいよオリジナルの画像でCNNの画像認識を行っていきます。画像認識はKerasのCNNを使用して行っていきます。
用意した画像は4種類。
・猫 ・・・・185枚
・ライオン ・・・・151枚
・犬 ・・・・180枚
・女性 ・・・・223枚
・合計 ・・・・739枚
枚数が違うのは当初250枚を用意していましたが、明らかに異なる画像が混入していために、不要なデータを除去しているうちに差分が出てしまいました。
8割を訓練用データに用いて、残り2割をテスト用データに使用しています。
訓練用データ・・・591枚
テスト用データ・・・148枚
1 2 3 4 5 6 7 8 9 10 11 |
# coding:utf-8 import keras from keras.utils import np_utils from keras.models import Sequential from keras.layers.convolutional import Conv2D, MaxPooling2D from keras.layers.core import Dense, Dropout, Activation, Flatten import numpy as np from sklearn.model_selection import train_test_split from PIL import Image import glob |
必要なライブラリを取り込んでいます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
folder = ["cat","lion","dog","woman"] image_size = 50 X = [] Y = [] for index, name in enumerate(folder): dir = "./" + name files = glob.glob(dir + "/*.jpg") for i, file in enumerate(files): image = Image.open(file) image = image.convert("RGB") image = image.resize((image_size, image_size)) data = np.asarray(image) X.append(data) Y.append(index) X = np.array(X) Y = np.array(Y) |
猫(cat)、ライオン(lion)、犬(dog)、女性(woman)のディレクトリを事前に作成しておき、その中に画像を格納しています。
画像は50×50ピクセルのRGB形式に変換され、それぞれnumpy形式に変換しています。
Xは画像データ、Yは正解ラベルのデータになります。
#画像データを0から1の範囲に変換
1 2 |
X = X.astype('float32') X = X / 255.0 |
画像データを0から1の範囲に変換しています。RGB形式のため(0,0,0)~(255,255,255)の範囲となるため、255で割ることで0~1の範囲となります。
1 2 |
# 正解ラベルの形式を変換 Y = np_utils.to_categorical(Y, 4) |
Kerasの場合は正解ラベルは数値ではなく、0or1を要素に持つベクトルで扱う必要があるため、正解ラベルの形式を変換します。例:猫[1,0,0,0]、ライオン[0,1,0,0]
1 2 |
# 学習用データとテストデータ X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.20) |
学習用データとテストデータに分割をしています。8割を訓練用データに用いて、残り2割をテスト用データに使用しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# 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(4)) model.add(Activation('softmax')) # コンパイル model.compile(loss='categorical_crossentropy',optimizer='SGD',metrics=['accuracy']) |
CNNのモデルを構築しています。Kerasは視覚的に層階層が見やすいです。結果を踏まえ調整をしていきます。
1 2 |
#訓練 history = model.fit(X_train, y_train, epochs=200) |
バッチサイズは省略しています。省略した場合はdefaultで32となっています。エポック数は200に設定しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
32/591 [>.............................] - ETA: 12s - loss: 0.1744 - acc: 0.9375 64/591 [==>...........................] - ETA: 11s - loss: 0.1512 - acc: 0.9531 96/591 [===>..........................] - ETA: 10s - loss: 0.1184 - acc: 0.9583 128/591 [=====>........................] - ETA: 10s - loss: 0.1070 - acc: 0.9531 160/591 [=======>......................] - ETA: 9s - loss: 0.0872 - acc: 0.9625 192/591 [========>.....................] - ETA: 8s - loss: 0.0787 - acc: 0.9688 224/591 [==========>...................] - ETA: 8s - loss: 0.0718 - acc: 0.9732 256/591 [===========>..................] - ETA: 7s - loss: 0.0657 - acc: 0.9766 288/591 [=============>................] - ETA: 6s - loss: 0.0650 - acc: 0.9757 320/591 [===============>..............] - ETA: 6s - loss: 0.0591 - acc: 0.9781 352/591 [================>.............] - ETA: 5s - loss: 0.0558 - acc: 0.9801 384/591 [==================>...........] - ETA: 4s - loss: 0.0594 - acc: 0.9792 416/591 [====================>.........] - ETA: 3s - loss: 0.0617 - acc: 0.9784 448/591 [=====================>........] - ETA: 3s - loss: 0.0599 - acc: 0.9799 480/591 [=======================>......] - ETA: 2s - loss: 0.0567 - acc: 0.9812 512/591 [========================>.....] - ETA: 1s - loss: 0.0548 - acc: 0.9824 544/591 [==========================>...] - ETA: 1s - loss: 0.0521 - acc: 0.9835 576/591 [============================>.] - ETA: 0s - loss: 0.0523 - acc: 0.9826 591/591 [==============================] - 13s 22ms/step - loss: 0.0512 - acc: 0.9831 Epoch 200/200 |
1 2 |
#評価 & 評価結果出力 print(model.evaluate(X_test, y_test)) |
実際にテストを実行し評価を行っています。
1 2 3 4 5 6 |
32/148 [=====>........................] - ETA: 1s 64/148 [===========>..................] - ETA: 0s 96/148 [==================>...........] - ETA: 0s 128/148 [========================>.....] - ETA: 0s 148/148 [==============================] - 1s 7ms/step [1.1267402655369527, 0.70945945623758677] |
結果は71%でした。
訓練データでは98%をいっていましたが、結果が70%という非常に悪い成績になりました。
過学習しすぎたのか、モデルが悪かったのか、写真の精度が良くなかったのか、どこかしら問題があるようです。
今後はいろいろなケースを試してみて精度を上げていきたいと思います。