深層学習(ディープラーニング)で画像認識に挑戦
こんにちは。
AI coordinatorの清水秀樹です。
以前の記事でMNISTを使った数字画像認識の学習モデルを作成しました。
でも、やっぱり色々な画像を認識できる学習済モデルを作成したいと思い、画像認識モデルで有名なCIFAR-10を使った学習済モデルの作成に挑戦してみました。
で、その学習済みモデルを使って実際に画像認識ができるところまで作成してみたので、その内容を紹介します。
参考にした書籍
これからDeep Learningの勉強をするなら、こちらで紹介する書籍が参考になります。
開発環境
macOS Sierra
Anaconda3-4.2.0-MacOSX-x86_64
keras 1.2.2
tensorflow 0.12.1
CIFAR-10とは
今回使用する画像データセットCIFAR-10とは、10種類の画像それぞれ6000枚集めた計60000枚の画像データセットのことです。
そのうち訓練用画像が50000枚、テスト用画像が10000枚の構成になった画像データセットです。
どんな画像が入っているのかというと、
[“airplane”,”automobile”,”bird”,”cat”,”deer”,
“dog”,”frog”,”horse”,”ship”,”truck”]
です。
自分で画像を準備するとなると、ものすごい労力がかかりますが、手頃に画像データの学習を始めるならCIFAR-10がオススメです。
最近ではCIFAR-100とかいう画像データセットもあるようです。
詳細はこちらのサイトで確認してみてください。
学習モデルの作成
では早速作成に取り掛かりたいと思います。
深層学習(ディープラーニング)で有名な畳み込みニューラルネットワークの勉強も兼ねて実装しています。
今回は9層で試してみました。
正直、精度の高い学習モデルを作成するためには、どのくらいの層が必要で、過学習を防ぐためには「Dropout」にどんな値を設定すれば良いのか良く分かりません。
この辺については、そのうち色々な実験を繰り返して真面目に勉強していくとして、今回は適当に学習モデルを定義して実装することにします。
学習回数も適当です。
この辺りはお好みで修正してください。
取り敢えず以下のソースそのままでも動きます。
# coding:utf-8 import numpy as np import scipy.misc import tensorflow as tf from keras.utils import np_utils from keras.models import Sequential, Model, model_from_json from keras.layers.core import Dense, Activation, Flatten, Dropout from keras.layers.convolutional import Convolution2D from keras.layers.convolutional import MaxPooling2D from keras.optimizers import SGD from keras.layers.normalization import BatchNormalization from keras.callbacks import EarlyStopping, TensorBoard, ModelCheckpoint from keras.datasets import cifar10 import keras.backend.tensorflow_backend as KTF import matplotlib.pyplot as plt #1024個の一層目を定義 in_shape = (32, 32, 3) #縦、横、RGB #クラスを指定 categories = ["airplane","automobile","bird","cat","deer","dog","frog","horse","ship","truck"] nub_classes = len(categories) #モデルの作成 def build_model(): model = Sequential() #畳み込み層の作成 #1層目の追加 1024個の層を最初に作り、フィルター3*3のフィルターを16個作成 model.add(Convolution2D(16, 3, 3, border_mode="same", input_shape=in_shape)) model.add(Activation("relu")) #2層目の畳み込み層 model.add(Convolution2D(16, 3, 3, border_mode="same")) model.add(Activation("relu")) #プーリング層 model.add(MaxPooling2D()) #Dropoutとは過学習を防ぐためのもの 0.5は次のニューロンへのパスをランダムに半分にするという意味 model.add(Dropout(0.5)) #3層目の作成 model.add(Convolution2D(32, 3, 3, border_mode="same")) model.add(Activation("relu")) #4層目の作成 model.add(Convolution2D(32, 3, 3, border_mode="same")) model.add(Activation("relu")) #プーリング層 model.add(MaxPooling2D()) model.add(Dropout(0.5)) #5層目 model.add(Convolution2D(64, 3, 3, border_mode="same")) model.add(Activation("relu")) #6層目 model.add(Convolution2D(64, 3, 3, border_mode="same")) model.add(Activation("relu")) #プーリング層 model.add(MaxPooling2D()) #Dropout model.add(Dropout(0.5)) #7層目 model.add(Convolution2D(128, 3, 3, border_mode="same")) model.add(Activation("relu")) #Dropout model.add(Dropout(0.5)) #平坦化 model.add(Flatten()) #8層目 全結合層 FC model.add(Dense(100)) model.add(Activation("relu")) #Dropout model.add(Dropout(0.5)) #8層目 引数nub_classesとは分類の数を定義する。 model.add(Dense(nub_classes)) model.add(Activation('softmax')) #ここまででモデルの層完成 #lossは損失関数を定義するところ model.compile(loss="categorical_crossentropy", metrics = ["accuracy"], optimizer = "adam" ) return model if __name__ == "__main__": #ここに読み込み処理と関数呼び出しを行う #cifar10からデータを取得 10種類の画像データセットがある 計5万枚 (X_train, y_train), (X_test, y_test) = cifar10.load_data() print(X_train.shape, y_train.shape) print(X_test.shape, y_test.shape) y_train = np_utils.to_categorical(y_train) y_test = np_utils.to_categorical(y_test) X_train = X_train.astype('float32') / 255 X_test = X_test.astype('float32') / 255 print("X_train", X_train.shape) print("y_train", y_train.shape) print("X_test", X_test.shape) print("y_test", y_test.shape) #ここからが上記で作成したモデルを呼び出す処理 model = build_model() model.fit(X_train, y_train, nb_epoch=30, #学習させる回数 今回は10 回数はお好みで pythonのnb_epochとはrangeの繰り返しのこと batch_size=500, #無作為に何枚学習に使用するか決定する。数字はなんでも良い validation_data=(X_test, y_test) ) #学習モデルの保存 json_string = model.to_json() #モデルのファイル名 拡張子.json open('cifar10.json', 'w').write(json_string) #重みファイルの保存 拡張子がhdf5 model.save_weights('cifar10.hdf5') # モデルの評価evaluate score = model.evaluate(X_train, y_train) print("test loss", score[0]) print("test acc", score[1])
以下学習結果です。
(50000, 32, 32, 3) (50000, 1) (10000, 32, 32, 3) (10000, 1) X_train (50000, 32, 32, 3) y_train (50000, 10) X_test (10000, 32, 32, 3) y_test (10000, 10) Train on 50000 samples, validate on 10000 samples Epoch 1/30 50000/50000 [==============================] - 131s - loss: 2.1206 - acc: 0.1993 - val_loss: 1.9238 - val_acc: 0.2699 Epoch 2/30 50000/50000 [==============================] - 133s - loss: 1.8135 - acc: 0.3127 - val_loss: 1.6944 - val_acc: 0.3694 Epoch 3/30 50000/50000 [==============================] - 137s - loss: 1.6492 - acc: 0.3877 - val_loss: 1.5570 - val_acc: 0.4337 Epoch 4/30 50000/50000 [==============================] - 137s - loss: 1.5521 - acc: 0.4301 - val_loss: 1.5233 - val_acc: 0.4420 Epoch 5/30 50000/50000 [==============================] - 132s - loss: 1.4758 - acc: 0.4589 - val_loss: 1.3826 - val_acc: 0.4949 Epoch 6/30 50000/50000 [==============================] - 136s - loss: 1.4423 - acc: 0.4738 - val_loss: 1.4624 - val_acc: 0.4803 Epoch 7/30 50000/50000 [==============================] - 132s - loss: 1.3971 - acc: 0.4916 - val_loss: 1.3176 - val_acc: 0.5252 Epoch 8/30 50000/50000 [==============================] - 136s - loss: 1.3530 - acc: 0.5128 - val_loss: 1.3531 - val_acc: 0.5201 Epoch 9/30 50000/50000 [==============================] - 136s - loss: 1.3192 - acc: 0.5225 - val_loss: 1.3031 - val_acc: 0.5377 Epoch 10/30 50000/50000 [==============================] - 131s - loss: 1.2908 - acc: 0.5376 - val_loss: 1.1918 - val_acc: 0.5726 Epoch 11/30 50000/50000 [==============================] - 142s - loss: 1.2623 - acc: 0.5476 - val_loss: 1.2366 - val_acc: 0.5513 Epoch 12/30 50000/50000 [==============================] - 142s - loss: 1.2462 - acc: 0.5560 - val_loss: 1.1357 - val_acc: 0.5912 Epoch 13/30 50000/50000 [==============================] - 142s - loss: 1.2225 - acc: 0.5619 - val_loss: 1.1851 - val_acc: 0.5775 Epoch 14/30 50000/50000 [==============================] - 136s - loss: 1.1996 - acc: 0.5700 - val_loss: 1.2754 - val_acc: 0.5499 Epoch 15/30 50000/50000 [==============================] - 146s - loss: 1.1814 - acc: 0.5777 - val_loss: 1.1019 - val_acc: 0.6053 Epoch 16/30 50000/50000 [==============================] - 144s - loss: 1.1655 - acc: 0.5868 - val_loss: 0.9921 - val_acc: 0.6471 Epoch 17/30 50000/50000 [==============================] - 146s - loss: 1.1480 - acc: 0.5919 - val_loss: 1.0030 - val_acc: 0.6428 Epoch 18/30 50000/50000 [==============================] - 153s - loss: 1.1323 - acc: 0.5991 - val_loss: 0.9781 - val_acc: 0.6510 Epoch 19/30 50000/50000 [==============================] - 154s - loss: 1.1083 - acc: 0.6077 - val_loss: 1.0131 - val_acc: 0.6386 Epoch 20/30 50000/50000 [==============================] - 141s - loss: 1.1111 - acc: 0.6083 - val_loss: 1.0421 - val_acc: 0.6278 Epoch 21/30 50000/50000 [==============================] - 136s - loss: 1.0894 - acc: 0.6158 - val_loss: 1.0570 - val_acc: 0.6222 Epoch 22/30 50000/50000 [==============================] - 139s - loss: 1.0692 - acc: 0.6239 - val_loss: 0.9527 - val_acc: 0.6588 Epoch 23/30 50000/50000 [==============================] - 137s - loss: 1.0726 - acc: 0.6238 - val_loss: 0.9829 - val_acc: 0.6491 Epoch 24/30 50000/50000 [==============================] - 138s - loss: 1.0509 - acc: 0.6313 - val_loss: 0.9221 - val_acc: 0.6705 Epoch 25/30 50000/50000 [==============================] - 136s - loss: 1.0448 - acc: 0.6341 - val_loss: 0.9370 - val_acc: 0.6644 Epoch 26/30 50000/50000 [==============================] - 147s - loss: 1.0364 - acc: 0.6339 - val_loss: 0.9620 - val_acc: 0.6543 Epoch 27/30 50000/50000 [==============================] - 140s - loss: 1.0223 - acc: 0.6417 - val_loss: 0.9511 - val_acc: 0.6591 Epoch 28/30 50000/50000 [==============================] - 145s - loss: 1.0115 - acc: 0.6443 - val_loss: 0.8920 - val_acc: 0.6857 Epoch 29/30 50000/50000 [==============================] - 144s - loss: 1.0084 - acc: 0.6472 - val_loss: 0.9256 - val_acc: 0.6732 Epoch 30/30 50000/50000 [==============================] - 145s - loss: 0.9967 - acc: 0.6517 - val_loss: 0.8526 - val_acc: 0.6931 49952/50000 [============================>.] - ETA: 0stest loss 0.788950727882 test acc 0.71516 In [ ]:
78%の精度となりました。
かなり精度が悪いですね。
畳み込みニューラルネットワークの学習モデルをもう少し工夫するか、学習回数を大幅に増やすなどの対応が必要そうです。
ただ今回は学習済モデルの作成と、その学習済モデルで実際に画像を認識させてみるところが目的なので、学習結果は多少悪くても良しとします。
学習済モデルで画像認識に挑戦
学習済みモデルができたら、実際に画像を準備して認識させてみましょう。
今回準備した画像は以下の画像たちです。
適当にネットから拝借してきました。
blog_testpicというディレクトリを作成し、そこに認識させたい画像を保存して以下のソースを実行してみましょう。
# coding:utf-8 import keras import sys, os import scipy import scipy.misc import numpy as np from keras.models import model_from_json import json imsize = (32, 32) #認識したい画像のパスを指定する # ./blog_testpic/xxx.jpg といった指定を意味する testpic = "./blog_testpic/" #使用するモデルを指定する keras_model = "./cifar10.json" keras_param = "./cifar10.hdf5" #画像の読み込み #読み込んだ画像を32X32にする def load_image(path): img = scipy.misc.imread(path, mode="RGB") img = scipy.misc.imresize(img, imsize) img = img / 255.0 #RGBの最大値を指定 return img #リストで結果を返す関数 def get_file(dir_path): filenames = os.listdir(dir_path) return filenames #メイン開始 if __name__ == "__main__": #画像を読み込んで、ファイル名をリスト化する。 pic = get_file(testpic) print(pic) #モデルの読み込み model = model_from_json(open(keras_model).read()) model.load_weights(keras_param) model.summary() ##ここまでで実行するとモデルの形が結果に表示される #リスト化したファイルから読み込んで処理する for i in pic: print(i) # ファイル名の出力 #画像ディレクトリにあるファイルのi番目を読み込む img = load_image(testpic + i) prd = model.predict(np.array([img])) print(prd) #確信度最大値を取得する prelabel = np.argmax(prd, axis=1) print(prelabel) # 各画像ファイルにairplaneなら0が、dogなら5、shipなら8のラベルが付いている if prelabel == 0: print(">>> airplane") elif prelabel == 1: print(">>> automobile") elif prelabel == 2: print(">>> bird") elif prelabel == 3: print(">>> cat") elif prelabel == 4: print(">>> deer") elif prelabel == 5: print(">>> dog") elif prelabel == 6: print(">>> frog") elif prelabel == 7: print(">>> horse") elif prelabel == 8: print(">>> ship") elif prelabel == 9: print(">>> truck") print() print()
結果にinputにした画像ファイル名と認識した画像の種類を出力しているようにしています。
以下、実行結果です。
Total params: 351,846 Trainable params: 351,846 Non-trainable params: 0 ____________________________________________________________________________________________________ airplane.jpg [[ 9.93673444e-01 3.23235804e-06 2.19863467e-03 8.30059871e-05 2.08738929e-04 5.68661517e-06 3.38327550e-06 3.45552667e-06 3.79910809e-03 2.12868217e-05]] [0] >>> airplane automobile.jpg [[ 6.19480988e-06 9.98218834e-01 5.71798502e-08 4.14908605e-08 5.71382852e-09 2.49827292e-09 2.76060405e-07 1.31873146e-09 3.17344893e-06 1.77149393e-03]] [1] >>> automobile dog.jpg [[ 3.08061601e-04 1.27699059e-05 8.04589465e-02 2.73394156e-02 6.33710861e-01 9.80996788e-02 1.21392561e-02 1.47868127e-01 5.19889863e-06 5.76526072e-05]] [4] >>> deer ship.jpg [[ 3.52313067e-03 9.79593642e-06 2.25756394e-05 7.40491805e-06 3.58149464e-06 8.80972451e-08 5.26029339e-07 1.23592031e-07 9.96417522e-01 1.51478107e-05]] [8] >>> ship truck.jpg [[ 1.21543708e-05 1.17212556e-04 8.85880809e-08 6.86258034e-07 1.01148956e-07 2.54100208e-08 6.89700652e-09 2.59936337e-06 1.81963208e-06 9.99865294e-01]] [9] >>> truck
概ね正解していますが、dogをdeerと間違えています。
学習精度が低いのでしょうがない感じですね。
ただ、実際に目的としていた画像を認識させてみるところまでは実装できたので、今後はどうやったら学習精度が上がるか模索していきたいと思います。
併せて、自分で集めた画像から学習モデルの作成にも挑戦していくので、成功したら紹介していきたいと思います。
その他の物体検出記事はこちらから
それではまた。
この記事へのコメントはありません。