Kerasで動物の画像認識

(注意)ディープランニングはパソコンへの負担が大きいように思えますので、少し遊んでみるだけか、本格的にするのであれば専用のパソコンを用意してした方がいいと思います。

AIによる画像認識をしたいと思いネットで調べました。最初、CIFAR-10で画像分類しようと思い調べたら、アルゴリズム雑記さんのコードでできました。次に、自分で画像を用意してAIによる分類をしたいと思い調べると、どれも自分の環境では作動せず、技術的特異点さんの画像をPythonに読める形にするコードがよさそうだったので、アルゴリズム雑記さんと技術的特異点さんのコードを使わせていただくことにしました。

環境
Windows7 SP1
Anaconda3 2018.12(64-bit)
Anaconda3内の環境
 Python 3.6
 jupyter1.0.0
 matplotlib 2.2.2
 scikit-learn 0.19.1
 tensorflow 1.5.0
 keras 2.2.0
 pillow 5.4.1


最初にフォルダを仮にデスクトップ上に作り、その中に10個のフォルダを作ります。


10個のフォルダそれぞれの中に画像認識したい同じ種類の画像を入れます。(空のフォルダがあってもフォルダ名さえ入力していれば実行されます。)
自分は犬150、(タヌキ、アライグマ)97、オオカミ112、キツネ150、魚135、カメ31、ペンギン102、象10、カニ114、パンダ10個、体の周りを切り抜いた画像を用意しました。
画像はpixabayさんからお借りしました。

次に、Anacondaをインストールしていない人はAnacondaのインストール方法などで最新のAnacondaをインストールしてみてください。
(左下)スタート→すべてのプログラム→Anaconda3(64-bit)→Anaconda Navigator
Anaconda Navigatorが開いたら


自分のpcの情報を自動送信したくない人は、Yes,I’d like to help improve Anaconda. のチェックを外して、Ok,and don’t show again をクリックします。
自分のpcの情報を自動送信してAnaconda Navigatorの開発に協力してもいい人は、Yes,I’d like to help improve Anaconda. のチェックを入れたままOkをクリックします。



そして、(左上)Environmentsを押して→(左下)Create→Create new environmentの窓が開きます。


Name の所に自分が作りたい環境の名前をアルファべットで入れてPythonはPython3.6を選んでPython3.6の左にチェックを入れてCreatをクリックします。



そして新しく作った環境(仮にdeepとします)の右の三角をクリックしてOpen Terminal をクリックします。



(deep)のコマンドプロンプトが開いたら 

conda install jupyter

 と入力してEnterをクリックし
Jupyter Notebook をインストールします。

インストールが完了したら同様に次のコードをコピペしてEnterを一つずつします。

conda install matplotlib==2.2.2
pip install scikit-learn==0.19.1
pip install tensorflow==1.5.0
pip install keras==2.2.0
pip install  pillow==5.4.1

間違って違うライブラリをインストールしたら

conda uninstall (ライブラリ名==バージョン)
pip uninstall (ライブラリ名==バージョン)

でアンインストールしましょう。
(例)

conda uninstall matplotlib==2.2.2

(例)

pip uninstall scikit-learn==0.19.1


すべてのインストールが終わったら、新しく作った環境(deep)の右の三角をクリックして、Open with Jupyter Notebook をクリックします。そうするとブラウザ上で Jupyter Notebook が開きます。


そして Jupyter Notebook の Home 画面の右上の Newをクリックして開いたプルダウンメニューのPython 3をクリックします。そうすると別タブでコードを実行するページが開きます。



そうしたら下の In []: と書かれた所の右の長方形の中に訓練のコードを貼り付けます。そしてコードの最後でShiftを押しながらEnterを押してコードを実行させます。

# -*- coding: utf-8 -*-
from keras.models import Sequential
from keras.layers.pooling import MaxPool2D
from keras.layers.core import Dense,Activation,Dropout,Flatten
import numpy as np
import keras
from keras.utils import np_utils
from keras.layers.convolutional import Conv2D, MaxPooling2D
from sklearn.model_selection import train_test_split
##train_test_split・・・学習用データ(train_images,train_labels,)と検証用データ(valid_images,valid_labels)に分割
from PIL import Image
import glob
from keras.preprocessing.image import load_img, img_to_array
from keras.initializers import TruncatedNormal, Constant
from keras.layers import Input, Dropout, Flatten, Conv2D, MaxPooling2D, Dense, Activation, BatchNormalization
from keras.optimizers import SGD
import json

# モデル構築
def build_model():
    # CNNのモデル構築
    model = Sequential()
    model.add(Conv2D(32,(3,3), padding='same', input_shape=(32,32,3)))
    model.add(Activation('relu'))
    model.add(Conv2D(32,(3,3),padding='same'))
    model.add(Activation('relu'))
    model.add(MaxPool2D(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),padding='same'))
    model.add(Activation('relu'))
    model.add(MaxPool2D(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(10, activation='softmax'))

    return model

# -------------------------------------------------------------------------------------
#                        初期設定部
# -------------------------------------------------------------------------------------

def main():

# 入力画像サイズ(画像サイズは正方形とする)
    INPUT_IMAGE_SIZE = 32

# 使用する訓練画像の入ったフォルダ(ルート)
    TRAIN_PATH = "C://Users//(ユーザー名)//Desktop//(フォルダ名)"
# 使用する訓練画像の各クラスのフォルダ名
    folder = ["000_dog", "001_raccoon_dog_and_raccoon", "002_wolf", "003_fox"
          , "004_fish", "005_turtle" , "006_penguin", "007_elephant" , "008_crab", "009_panda" ]
# CLASS数を取得する
    CLASS_NUM = len(folder)
    print("クラス数 : " + str(CLASS_NUM))

# -------------------------------------------------------------------------------------
#                        訓練画像入力部
# -------------------------------------------------------------------------------------

# 各フォルダの画像を読み込む
    v_image = []
    v_label = []
    for index, name in enumerate(folder):
        dir = TRAIN_PATH + "/" + name
        files = glob.glob(dir + "/*.png")
        print(dir)
        for i, file in enumerate(files):
            img = load_img(file, target_size=(INPUT_IMAGE_SIZE, INPUT_IMAGE_SIZE))
            array = img_to_array(img)
            v_image.append(array)
            v_label.append(index)
##.append(array)・・・末尾(最後)に要素arrayを追加
##array = img_to_array(img) ・・・画像をarrayに変換する
##for (インデックス, 要素) in enumerate(s): ・・・sからインデックス,と要素を取り出す

    v_image = np.array(v_image)
    v_label = np.array(v_label)
##Numpy array・・・配列として計算する?

# imageの画素値をint型からfloat型にする
    v_image = v_image.astype('float32')
# .astype('float32')は下方の画像データの正規化でしている
# 画素値を[0~255]⇒[0~1]とする
    v_image = v_image / 255.0

# 正解ラベルの形式を変換
    v_label = np_utils.to_categorical(v_label, CLASS_NUM)

# 学習用データ(train_images,train_labels,)と検証用データ(valid_images,valid_labels)に分割する
    train_images, valid_images, train_labels, valid_labels = train_test_split(v_image, v_label, test_size=0.10)
    x_train = train_images
    y_train = train_labels
    x_test = valid_images
    y_test = valid_labels

    # CNNのモデル構築
    model = build_model()

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

    # 学習
    history = model.fit(x_train,y_train, batch_size=128, nb_epoch=1, verbose=1, validation_split=0.1)
##validation_split・・・訓練データの中で検証データとして使う割合
##nb_epoch・・・学習を繰り返す回数

    # モデルと重みを保存
    open('cifar10.json',"w").write(model.to_json())
    model.save_weights('cifar10.h5')

    # モデルの詳細表示
    model.summary()

    # モデルの性能評価
    score = model.evaluate(x_test, y_test, verbose=0)
    print('Test loss:', score[0]) # Test loss: 0.683512847137
    print('Test accuracy:', score[1]) # Test accuracy: 0.7871

# 学習履歴を保存
    json.dump(history.history, open("history.json", "w"))

if __name__ == '__main__':
    main()

コードの実行が成功したら調べたい画像を仮にデスクトップ上に用意します。そして Jupyter Notebook の先程の訓練のコードの下の In []: と書かれた所の右の長方形の中にテストのコードを貼り付けます。そしてコードの最後でShiftを押しながらEnterを押してコードを実行させます。

# -*- coding: utf-8 -*-
import numpy as np
from keras.models import Sequential, model_from_json
from keras.models import Sequential
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPool2D
from keras.layers.core import Dense,Activation,Dropout,Flatten
from keras.utils import np_utils
from keras.layers.core import Dense
from keras.optimizers import RMSprop
from keras.preprocessing.image import load_img
from keras.preprocessing.image import load_img, img_to_array

def main():
    # ラベル
    folder = ["000_dog", "001_raccoon_dog_and_raccoon", "002_wolf", "003_fox"
          , "004_fish", "005_turtle" , "006_penguin", "007_elephant" , "008_crab", "009_panda" ]

    # 画像の読み込み(32×32にリサイズ)
    img = load_img("C:/Users/(ユーザー名)/Desktop/(テストしたい画像名).png", target_size=(32, 32))
    img = img_to_array(img)

    # 画像データの正規化
    img = img.astype('float32')/255.0
    img = np.array([img]) # 4次元配列にしないと入力できない

    # モデルの読み込み
    model = model_from_json(open('cifar10.json', 'r').read())

    # 重みの読み込み
    model.load_weights('cifar10.h5')

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

    # 10枚(0~9番目)のテスト画像を入力し、予測結果を出力
    y_pred = model.predict(img)

    # 出力をクラスベクトルから整数値に変換
    y_pred = np.argmax(y_pred, axis=1)

    # 予測結果の表示
    print('予測結果:', folder[int(y_pred)]) # 飛行機

if __name__ == '__main__':
    main()

そうするとAIが画像が何であるか判断した結果がコードの下方にフォルダ名で表示されます。自分の結果は下のようになりました。(上側の訓練のコードの # 学習で batch_size=128はそのままで nb_epoch=30 に変えて実行した結果です。)