Tensorflow・kerasで画像認識モデル作成|深層学習×Pythonの畳み込みニューラルネットワーク(CNN)

こんにちは、Kosei(@kay_diacc2)です!

サマリー

ディープラーニングの画像認識に興味がある方向けに、Tensorflow(Keras)を用いてモデルを作成する方法について解説します。

目次

畳み込みニューラルネットワーク(CNN)とは

CNNは多次元配列データを扱うことに特化したニューラルネットワークであり、画像認識や動体検知の分野で広く応用されています。

CNNは「畳み込み層」「プーリング層」「全結合層」で構成されるのが特徴です。畳み込み層で画像の特徴を抽出し、プーリング層で特徴データを圧縮します。この操作を繰り返した後、結合層で分類結果を出力します。

【参考】ディープラーニングモデル最適化の仕組み

ディープラーニングの仕組みについて詳しく知りたい方はこちらの記事をご覧下さい。

【参考】Kerasを用いた深層学習プログラミング

Kerasでディープラーニングモデルを構築する方法を詳しく知りたい方向けにおすすめ教材をご紹介します。

【深層学習】画像認識AIモデルの作成概要

AI画像認証モデルの作成に際して、本記事では「りんご」「ぶどう」「みかん」を分類することを目的としたモデル作成を試みます。なお、上記画像以外の分類にも横展開できるようなスクリプト構成としていますため、お好みの用途にもご活用ください。

画像認識モデルの作成手順

次のような手順のもと、画像認証AIを作成します。

  1. データ前処理|データセットの読込・加工
  2. モデル学習・評価|CNN
  3. モデル推論

事前準備

トレーニング・テストデータを格納した画像フォルダ(data)とpythonスクリプトを記述したファイル(pythonファイル)を同ディレクトリに配置します。

サンプルの画像データは、fruits-sample-datasetからダウンロードできますためご活用ください。

【Python×Keras】画像認証AIの構築|ディープラーニング実践

それでは実際に画像認証AIモデルを構築していきましょう!

データ前処理|データセットの読込・加工

指定の画像ファイルを読み込み、3色(RGB)の数値配列に変換した後、モデル学習・評価用のトレーニングデータとテストデータを作成する方法を以下に示します。

from PIL import Image
import numpy as np
import os,glob

# クラスラベル
labels = ["grape","apple","orange"]
# ディレクトリ
dataset_dir = "data/dataset.npy" # 前処理済みデータ
model_dir   = "data/cnn_h5"      # 学習済みモデル
# リサイズ設定
resize_settings = (50,50)

# 画像データ
X_train = [] # 学習
y_train = [] # 学習ラベル
X_test  = [] # テスト
y_test  = [] # テストラベル

for class_num, label in enumerate(labels):
    
    # 写真のディレクトリ
    photos_dir = "data/" + label
    
    # 画像データを取得
    files = glob.glob(photos_dir + "/*.jpg")
    
    #写真を順番に取得
    for i,file in enumerate(files):
        
        # 画像を1つ読込
        image = Image.open(file)
        
        # 画像をRGBの3色に変換
        image = image.convert("RGB")
        
        # 画像のサイズを揃える
        image = image.resize(resize_settings)
        
        # 画像を数字の配列変換
        data  = np.asarray(image) 

        # テストデータ追加
        if i%4 ==0:
            X_test.append(data)
            y_test.append(class_num)
            
        # 学習データ傘増し
        else:            
            # -20度から20度まで4度刻みで回転したデータを追加
            for angle in range(-25,20,5):
                # 回転
                img_r = image.rotate(angle)
                # 画像 → 数字の配列変換
                data  = np.asarray(img_r)
                # 追加
                X_train.append(data)
                y_train.append(class_num)
                # 画像左右反転
                img_trans = image.transpose(Image.FLIP_LEFT_RIGHT)
                data      = np.asarray(img_trans)
                X_train.append(data)
                y_train.append(class_num)        
        
        
# X,YがリストなのでTensorflowが扱いやすいようnumpyの配列に変換
X_train = np.array(X_train)
X_test  = np.array(X_test)
y_train = np.array(y_train)
y_test  = np.array(y_test)


# 前処理済みデータを保存
dataset = (X_train,X_test,y_train,y_test)
np.save(dataset_dir,dataset)

上記実行後、dataset.npyという数値配列からなるトレーニング・テストデータがdataフォルダ直下に作成されます。

モデル学習・評価|CNN

前述で作成したdataset.npyを読み込み、畳み込みニューラルネットワーク(CNN)のモデルを学習・評価するスクリプトを以下に示します。

import tensorflow
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation,Dropout,Flatten,Dense
from keras.utils  import np_utils
import numpy as np

# クラスラベル
labels = ["grape","apple","orange"]
# ディレクトリ
dataset_dir = "data/dataset.npy" # 前処理済みデータ
model_dir   = "data/cnn_h5"      # 学習済みモデル
# リサイズ設定
resize_settings = (50,50)

# メインの関数定義
def main():
    """
    ①データの前処理(エンコーディング)
    """
    # 保存したnumpyデータ読み込み
    X_train,X_test,y_train,y_test = np.load(dataset_dir, allow_pickle=True)
    
    # 0~255の整数範囲になっているため、0~1間に数値が収まるよう正規化
    X_train = X_train.astype("float") / X_train.max()
    X_test  = X_test.astype("float") /  X_train.max()
    
    # クラスラベルの正解値は1、他は0になるようワンホット表現を適用
    y_train = np_utils.to_categorical(y_train,len(labels))
    y_test  = np_utils.to_categorical(y_test,len(labels))
    """
    ②モデル学習&評価
    """
    #モデル学習
    model = model_train(X_train,y_train)
    
    #モデル評価
    evaluate(model,X_test, y_test)
    
  
    
#モデル学習関数
def model_train(X_train,y_train):
    
    #インスタンス
    model = Sequential()
    
    # 1層目 (畳み込み)
    model.add(Conv2D(32,(3,3),padding="same", input_shape=X_train.shape[1:]))
    model.add(Activation('relu'))
    # 2層目(Max Pooling)
    model.add(Conv2D(32,(3,3)))
    model.add(Activation('relu'))
    # 3層目 (Max Pooling)
    model.add(MaxPooling2D(pool_size=(2,2)))                     
    model.add(Dropout(0.3))                     
    # 4層目 (畳み込み)
    model.add(Conv2D(64,(3,3),padding="same"))                   
    model.add(Activation('relu'))
    # 5層目 (畳み込み)
    model.add(Conv2D(64,(3,3))) 
    model.add(Activation('relu'))
    # 6層目 (Max Pooling)
    model.add(MaxPooling2D(pool_size=(2,2)))
    # データを1次元化
    model.add(Flatten())
    # 7層目 (全結合層)
    model.add(Dense(512))                                       
    model.add(Activation('relu'))
    model.add(Dropout(0.5))
    # 出力層(softmaxで0〜1の確率を返す)
    model.add(Dense(3)) 
    model.add(Activation('softmax'))
    # 最適化アルゴリズム
    opt = tensorflow.keras.optimizers.RMSprop(lr=0.005, decay=1e-6)
    # 損失関数
    model.compile(loss="categorical_crossentropy",
                  optimizer=opt,
                  metrics=["accuracy"]
                 )
                  
    # モデル学習
    model.fit(X_train,y_train,batch_size=10,epochs=150)
    # モデルの結果を保存
    model.save(model_dir)
    return model
    

# 評価用関数
def evaluate(model,X_test,y_test):
    # モデル評価
    scores = model.evaluate(X_test,y_test,verbose=1)
    print("Test Loss: ", scores[0])
    print("test Accuracy: ", scores[1])

モデル学習および評価の際は以下を追記し、実行してみましょう。

モデル学習完了後、dataフォルダ直下にcnn_h5(学習済モデルを格納したフォルダ)が作成されます。

# モデル学習実行
model = main()

今回畳み込みニューラルネットワークのレイヤーには次のようなものを定義しています。詳しくはKeras Documentationをご覧下さい。

レイヤー概要
Conv2D畳み込み層
MaxPooling2Dプーリング層
Activation活性化関数
Dropoutドロップアウト
Flatten多次元配列を1次元のベクトルに変換
Dense全結合層

モデル推論

学習済モデルを用いて推論を実施するためのスクリプトを以下に示します。

import tensorflow
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Activation,Dropout,Flatten,Dense
from keras.utils  import np_utils
import sys
import numpy as np
from PIL import Image
from tensorflow import keras

# クラスラベル
labels = ["grape","apple","orange"]
# ディレクトリ
dataset_dir = "data/dataset.npy" # 前処理済みデータ
model_dir   = "data/cnn_h5"      # 学習済みモデル
# リサイズ設定
resize_settings = (50,50)

# 推論用モデル
def predict():
    
    #インスタンス
    model = Sequential()
    # 1層目 (畳み込み)
    model.add(Conv2D(32,(3,3),padding="same", input_shape=X_train.shape[1:]))
    model.add(Activation('relu'))
    # 2層目(Max Pooling)
    model.add(Conv2D(32,(3,3)))
    model.add(Activation('relu'))
    # 3層目 (Max Pooling)
    model.add(MaxPooling2D(pool_size=(2,2)))                     
    model.add(Dropout(0.3))                     
    # 4層目 (畳み込み)
    model.add(Conv2D(64,(3,3),padding="same"))                   
    model.add(Activation('relu'))
    # 5層目 (畳み込み)
    model.add(Conv2D(64,(3,3))) 
    model.add(Activation('relu'))
    # 6層目 (Max Pooling)
    model.add(MaxPooling2D(pool_size=(2,2)))
    # データを1列に並べる
    model.add(Flatten())
    # 7層目 (全結合層)
    model.add(Dense(512))                                       
    model.add(Activation('relu'))
    model.add(Dropout(0.5))
    # 出力層(softmaxで確率を渡す:当てはまるものを1で返す)
    model.add(Dense(3)) 
    model.add(Activation('softmax'))
    # 最適化の手法
    opt = tensorflow.keras.optimizers.RMSprop(lr=0.005, decay=1e-6)
    # 損失関数
    model.compile(loss="categorical_crossentropy",
                  optimizer=opt,
                  metrics=["accuracy"]
                 )
                  

    # モデル学習(推論では不要のためコメントアウト)
    # model.fit(X_train,y_train,batch_size=10,epochs=150) 
    
    # モデルを読み込み
    model = keras.models.load_model("data/cnn_h5")
    
    return model


# 実行関数
def main(path):
    X     = []                               # 推論データ格納
    image = Image.open(path)                 # 画像読み込み
    image = image.convert("RGB")             # RGB変換
    image = image.resize(resize_settings)    # リサイズ
    data  = np.asarray(image)                # 数値の配列変換
    X.append(data)
    X     = np.array(X)
    
    # モデル呼び出し
    model = predict()
    
    # numpy形式のデータXを与えて予測値を得る
    model_output = model.predict([X])[0]
    # 推定値 argmax()を指定しmodel_outputの配列にある推定値が一番高いインデックスを渡す
    predicted = model_output.argmax()
    # アウトプット正答率
    accuracy = int(model_output[predicted] *100)
    print("{0} ({1} %)".format(labels[predicted],accuracy))

推論の際は、以下を追記し実行してみましょう。

# 推論
path = "推論用画像のファイルパス"
image = Image.open(path)

main(path)

AI・機械学習まとめ

最後までご覧いただきありがとうございました。当サイトでは機械学習・深層学習における理論やPythonを用いた実装方法の解説記事を多数取り扱っております。

【初学者向け】データサイエンス・人工知能(AI)開発のおすすめ学習方法も解説してます。

ディープラーニングを学ぶ上でおすすめの教材はこちらで紹介しています。

最後に

この記事が気に入ったら
フォローしてね!

本記事をシェア!
URLをコピーする
URLをコピーしました!
目次
閉じる