【CNN】畳み込みニューラルネットワークを理解する③

AI実装

独自の画像データをつかった畳み込みニューラルネットワーク(CNN)学習を実行していこうと思います。とりあえずディープラーニングをやってみたい!という方におすすめな内容になっています。今回は独自データ(画像)の学習を設定し2種類の画像を見分けるAIをつくっていきます。

独自の画像を使う方法にフォーカスしていきます。学習モデルのつくり方だったり、CNNで有名なアルゴリズムの紹介は別で説明していこうと思います。

ここではローカルPCでGPUを使った学習を実施していきます。Google Colab、NeuralNetworkConsoleといったサイトでTPUを使った高速学習を実施できますが、「機密情報を外部サーバへ置けない」「社内のアクセス制限で使えない」などの問題が結構あるのでは?(少なくとも自動車業界は厳しいです)と思い、ローカルPC(windows10)での実装手順で説明していきます。ちなみにTensorFlowを使います。

CNNの基本的な中身の動作や、学習の仕組みを知りたい方は詳細を↓にまとめてありますのでよかったら参考にしてください。

こんな人におすすめ
  • とにかく速攻でディープラーニングをやってみたい
  • AI・機械学習を勉強したいけど、何からやればよいか分からない
  • 書籍が難しすぎて挫折した
  • これからデータサイエンティストを目指したい
  • 画像認識をやってみたい

TensorFlow-GPU・その他ライブラリをインストールする

まずは使用するPCスペックです。画像を使うのでGPU搭載のものがいいですが、CPU環境でも学習は可能です(5~6時間かかりますが・・・)。

使用PCスペック
OSWindows 10
CPUAMD Ryzen 7 5800
メモリ16 GB
GPUGeForce RTX3070

Anaconda(Jupyter notebook)で実施していくのであらかじめインストールしておいてください。

  • Python:3.7

GPUを使っていくので↓もインストールしていきます。CUDA toolkit関連のインストールはこのサイトに細かく掲載されています。

↓NVIDIA developerサイトよりダウンロード後インストールしてください。

  • CUDA:11.3
  • cuDNN:8.2

次にTensorFlow-gpu:2.5をインストールします。AnacondaPromptで↓を実行してください。

pip install tensorflow-gpu==2.5 tensorflow_datasets tensorflow-hub

GPUが認識されているかをチェックする方法は↓コードを実行し確認してください。

python
from tensorflow.python.client import device_lib
device_lib.list_local_devices()

↑のようなGPUとかグラフィックボードの名前(RTX****とか)が帰ってくればOKです。

その他のライブラリは↓を実行してインストールしてください。

pip install sklearn pillow matplotlib

以上でライブラリ関連の準備は完了です。

独自データ(画像)の準備

まずは画像の準備していきます。画像は何か準備してもらっても大丈夫ですが、今回はここでダウンロードしたものを使います。画像はタンポポ(dandelion)とヒナギク(daisy)の2種類、1440枚の画像で学習していきます。

画像のディレクトリ配置は↓の通りに置きます。dandelion、daisyディレクトリをつくり画像を格納してください。

CNN画像分類AIのコード説明

ここから実装するCNNモデルのコードを説明していきます。コードはAnacondaのJupyterNotebookで動作確認しています。画像を配置するときにつくったCNNディレクトリ下にNotebookを作成してください。

  • ライブラリのインポート
import tensorflow as tf
from tensorflow.keras.utils import to_categorical
import numpy as np
from sklearn.model_selection import train_test_split
from PIL import Image
import glob
import matplotlib.pyplot as plt

↑のコードをJupyterNotebookで実行しライブラリをインポートします。

  • 画像の読み込み
folder = ['daisy', 'dandelion'] #分類するクラス
image_size = 224 #インプット画像のサイズ
X = []
Y = []
for index, name in enumerate(folder): #ディレクトリの種類、画像ファイル名を繰返し取得する
    dir = "./data/train/" + name
    files = glob.glob(dir + "/*.jpg") #ファイル名の取得
    for i, file in enumerate(files): #各画像へ↓の処理を繰返し実施する
        image = Image.open(file) #画像の読み込み
        image = image.convert("RGB") #RGBに変換
        image = image.resize((image_size, image_size)) #サイズ変更
        data = np.asarray(image) #画像データを配列へ変更
        X.append(data) #画像データを繰返し追加
        Y.append(index) #daisy:0, dandelion:1の値を繰返し追加
X = np.array(X)
Y = np.array(Y)

↑のコードを実行してください。このコードで独自の画像データをCNN実装する準備を実施します。各コードの説明はコメントアウトで記載しているので確認してください。

2021/10/27追記:validationデータを作成します。下記コードを実行してください。抜けていました。すみません。

#画像データを0~1の値へ変換
X = X.astype('float32')
X = X / 255.0
#正解ラベルの形式を変換
Y = to_categorical(Y, 2)
#学習用データとテストデータへ分割
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.20)
  • CNNモデルの作成
#CNNモデル(ResNet50)のライブラリをインポート
from tensorflow.keras.applications.resnet50 import ResNet50
from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Input, Flatten, Dense

#input画像の定義
input_tensor = tf.keras.Input(shape=(image_size, image_size, 3))
#ResNet50モデルの呼出し。ここでweights="imagenet"とすることで学習済の重みを使うことができる
#include_top=Falseとすることで出力層だけを今回の学習に合わせた形で書き換えます
ResNet50 = tf.keras.applications.ResNet50(include_top=False, weights="imagenet", 
                                          input_tensor=input_tensor,classes=2,)
#出力層の書換え。今回は2種類の画像分類のモデルを作成。
top_model = Sequential()
top_model.add(Flatten(input_shape = ResNet50.output_shape[1:]))
top_model.add(Dense(2, activation = 'sigmoid'))
model = Model(inputs=ResNet50.inputs, outputs=top_model(ResNet50.outputs))

↑のコードを実行してください。本来モデルをつくるときは長いコードが必要なのですが、TensorFlow.kerasライブラリを利用することで、わずかなコードでモデルを呼び出すことができます。今回はResNet50(2015年のILSVRC優勝モデル)を使用します。

今回はTensorFlow.kerasにあらかじめImageNetというデータセット学習されているモデルと重みがありますので、これを利用した転移学習という手法で学習していきます。出力に影響するtop_modelのみを2種類の画像分類モデルにあわせて書き換えています。モデルに関する説明は別の機会に詳しくやっていこうと思います。長くなりそうなんで・・・

  • 学習実施
from tensorflow.keras import optimizers
model.compile(loss='binary_crossentropy', optimizer=optimizers.Adam(lr=0.01),metrics=['accuracy'])
history = model.fit(X_train, y_train, validation_data = (X_test, y_test), batch_size=32, 
                    steps_per_epoch=1440//32, epochs=100)

↑のコードを実行すると学習がはじまります。batch_size=32、epochs=100で学習しています。メモリの関係で学習ができない場合は、batch_sizeの値を小さくすると使用メモリを減らすことができます(学習時間は伸びます)。学習がはじまると↓のような表示がでてきます。

ここで、lossが減少しない、accuracyが増加しないなど、学習が進まない問題が発生することがあります。↑のコード「optimizer=optimizers.Adam(lr=0.01)」の0.01を変化させると良いです。0.001とか0.0001とか。これはいわゆるハイパーパラメータというやつで、入力データ、分類モデルにあわせいろいろ変える必要があります。

  • 学習履歴の可視化
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()

plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()

↑のコードでモデルの精度と損失関数のグラフを表示できます。今回の学習結果は↓になります。

グラフ横軸が学習ステップとなっており、学習が進むにつれAccuracyは増加し最終的に0.88となっています。lossも学習の進捗に伴い減少しているので学習はうまく進んだと評価できます。

以上が独自画像データをつかったCNN学習の一例になります。CNNは多くのモデルが提案されているので、課題にあったモデルを選んだり、自分でモデルをつくる必要があります。その辺りは、また別の機会に!

まとめ

  • 独自の画像データをつかった2値分類CNNモデルをつくった
  • 独自画像の学習準備を詳しく説明した
  • TensorFlow.kerasライブラリをつかうとモデルをつくるのが簡単
  • とにかくCNNをやってみたいという方は↓コード全文をコピペしてください!

コード全文

import tensorflow as tf
from tensorflow.keras.utils import to_categorical
import numpy as np
from sklearn.model_selection import train_test_split
from PIL import Image
import glob
import matplotlib.pyplot as plt
folder = ['daisy', 'dandelion'] #分類するクラス
image_size = 224 #インプット画像のサイズ
X = []
Y = []
for index, name in enumerate(folder): #ディレクトリの種類、画像ファイル名を繰返し取得する
    dir = "./data/train/" + name
    files = glob.glob(dir + "/*.jpg") #ファイル名の取得
    for i, file in enumerate(files): #各画像へ↓の処理を繰返し実施する
        image = Image.open(file) #画像の読み込み
        image = image.convert("RGB") #RGBに変換
        image = image.resize((image_size, image_size)) #サイズ変更
        data = np.asarray(image) #画像データを配列へ変更
        X.append(data) #画像データを繰返し追加
        Y.append(index) #daisy:0, dandelion:1の値を繰返し追加
X = np.array(X)
Y = np.array(Y)

#画像データを0~1の値へ変換
X = X.astype('float32')
X = X / 255.0
#正解ラベルの形式を変換
Y = to_categorical(Y, 2)
#学習用データとテストデータへ分割
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.20)

#CNNモデル(ResNet50)のライブラリをインポート
from tensorflow.keras.applications.resnet50 import ResNet50
from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.layers import Input, Flatten, Dense

#input画像の定義
input_tensor = tf.keras.Input(shape=(image_size, image_size, 3))
#ResNet50モデルの呼出し。ここでweights="imagenet"とすることで学習済の重みを使うことができる
#include_top=Falseとすることで出力層だけを今回の学習に合わせた形で書き換えます
ResNet50 = tf.keras.applications.ResNet50(include_top=False, weights="imagenet", 
                                          input_tensor=input_tensor,classes=2,)
#出力層の書換え。今回は2種類の画像分類のモデルを作成。
top_model = Sequential()
top_model.add(Flatten(input_shape = ResNet50.output_shape[1:]))
top_model.add(Dense(2, activation = 'sigmoid'))
model = Model(inputs=ResNet50.inputs, outputs=top_model(ResNet50.outputs))

from tensorflow.keras import optimizers
model.compile(loss='binary_crossentropy', optimizer=optimizers.Adam(lr=0.01),metrics=['accuracy'])
history = model.fit(X_train, y_train, validation_data = (X_test, y_test), batch_size=32, 
                    steps_per_epoch=1440//32, epochs=100)

結果グラフ化は下記

plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()

plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()

コメント

タイトルとURLをコピーしました