【解説】オリジナルデータセットで自作画像認識AI入門 | CNNサンプルコード – Colaboratory・Keras・Python
Google ColaboratoryでKerasを使って、自作・自前画像のオリジナルデータセットを活用して、ディープラーニング(深層学習)でおなじみの「畳み込みニューラルネットワーク」(CNN:Convolutional Neural Network)を実装出来るようにしたサンプルコードを作成し、コードの解説をしてみました。
* Keras:Pythonで書かれているTensorFlow上等で実行可能な高水準のニューラルネットワークライブラリ
「 機械学習プログラミングを始めたものの、自前データセットの壁が超えられない・・・ 」
「 オリジナルデータで自分の好きな画像認識に挑戦してみたい!」
と考えている方の、何かしらのきっかけになることがありましたら幸いです。
オリジナルデータセットを使って自作画像認識AIを作ってみましょう。
尚、内容に関しては正確に記載するように努めておりますが、個人で学習した範囲の情報ですので、正確な情報等の詳細に関してはご自身でもよくお調べください。
【情報】
この記事のサンプルコードを理解するために必要な画像認識関連の深層学習プログラミングの知識を学ぶ上で補助教材となりそうな書籍のレビューや数学・数式関連の情報をまとめておきました。日々の学習の一助になることがありましたら幸いです。
:【1周目 – 学習レビュー】Pythonで動かして学ぶ!あたらしい深層学習の教科書 機械学習の基本から深層学習まで(Aidemy公式教科書)
:「Pythonで動かして学ぶ!あたらしい深層学習の教科書 機械学習の基本から深層学習まで」を読むためのギリシャ文字・数学記号
Flaskで機械学習Webアプリ開発ができる日本語チュートリアルの公開を開始しました。
:Flask(Python)Web機械学習アプリ開発入門
2021年2月8日時点で、Google Colaboratoryに公開中のサンプルコードで初回実行時に警告表示などが出ないように修正しておきました。
2021年6月7日時点で、Google Colaboratoryに公開中のサンプルコードでエラーが出ないように修正しておきました。
2021年9月6日時点で、Google Colaboratoryに公開中のサンプルコードでエラーが出ないように修正しておきました。
2023年2月14日時点で、Google Colaboratoryに公開中のサンプルコードでエラーが出ないように修正しておきました。
このページのコードを活用した、オリジナルデータセット編のFlask(Python)Web機械学習アプリ開発サンプルコードの日本語解説も公開しました。
:【コード解説】自作画像認識編 Flask(Python)Web機械学習アプリ開発入門:画像アップロード判定プログラム
このページのコードを改変して7セグメントのデジタル数字画像認識に挑戦
:【4桁 – 7セグメント編】連続デジタル数字画像認識プログラミング入門(Python・OpenCV・Keras・CNN)
このページのコードを改変して日本語OCRに挑戦
:【日本語手書きOCR編】連続文字画像認識プログラミング入門(Python・OpenCV・Keras・CNN
【コード全体の概略】自作画像認識AIプログラミング用データセット・サンプルコード・サンプルソース
【Google Colaboratory用のサンプルコードリンク | Python・Keras:自作データセットでCNNで学習・分類用】
実行環境 – Google Colaboratory
:program_Keras_cnn_originaldataset_basic.ipynb | Google Colaboratory共有リンク
サンプルコードで利用しているオリジナルデータセット(zip形式)
サンプルコードで、CNN学習モデルの結果を使い画像認識している○×画像
2020年9月30日以前の状態では、ファイル圧縮の兼ね合いで各画像(1.png・2.png)をダウンロード後に、パソコンで画像を開こうとしても正常に描画されていませんでしたので修正しておきました。
丸バツ判定AIできました。
【人工知能・機械学習プログラミングの進捗状況を報告】
Colaboratory・Keras・自前データセット(動画)
視聴時間:2分11秒
サンプルコードの動かし方がわからない方は、参考にしてみてください。
動画では、データセットの構造例や、Colaboratoryの環境にフォルダをアップロードする方法例を解説してあります。
今回のプログラムを動かすために必要なデータセットの構造例(機械学習用データセットの作り方)
dataset(フォルダ名)
— circle(datasetフォルダ内のフォルダ名 – ラベル情報)
— cross(datasetフォルダ内のフォルダ名 – ラベル情報)
* データセットの作り方は簡単です。「circle」「cross」の各フォルダ内に、対応する画像を配置するだけです。
* 画像の大きさは、特に指定はありません。バラバラの大きさでも実行できるようですが、必要に応じて調整してみてください。
Google Colaboratoryでプログラムを実行する際には、Googleアカウントが必要です。GPUも無料で使えるのでありがたいですね。
Google Colaboratory用のサンプルコードリンク先では、GPUを設定しています。
***以下:サンプルコード***
#① zipファイルをGoogle Colaboratoryにアップロードし、フォルダ化
!unzip dataset.zip #解凍:ここを変更。「dataset」のところをアップロードしたzipファイル名に変更してください。 - ファイルを消す場合「!rm dataset.zip」
#② 用意した自前画像で学習(畳み込みニューラルネットワーク:CNN)
#このプログラムでは、「判別したい “ラベル情報(フォルダ名)” と “画像” をセットにしたフォルダ」をアップロードすると動くようにしてあります。
#1 ライブラリのインポート等
import keras
import glob
import numpy as np
from sklearn.model_selection import train_test_split
# from keras.preprocessing.image import load_img, img_to_array #ここでエラーとなるので以下のコードに変更
from tensorflow.keras.utils import load_img, img_to_array
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Dense, Dropout, Flatten
#from keras.utils import plot_model #これはKerasのバージョンなどにより使えないのでコメントアウト
from keras.utils import np_utils #keras.utils.to_categoricalでエラーが出るので追加
# from keras.optimizers import Adam # ここでエラーとなるので以下のコードに変更
from tensorflow.keras.optimizers import Adam # 「tensorflow.」を追加
import matplotlib.pyplot as plt
import time
#2 各種設定
train_data_path = 'dataset' # ここを変更。Colaboratoryにアップロードしたzipファイルを解凍後の、データセットのフォルダ名を入力
image_size = 28 # ここを変更。必要に応じて変更してください。「28」を指定した場合、縦28横28ピクセルの画像に変換します。
color_setting = 1 #ここを変更。データセット画像のカラー:「1」はモノクロ・グレースケール。「3」はカラー。
folder = ['circle', 'cross'] # ここを変更。データセット画像のフォルダ名(クラス名)を半角英数で入力
class_number = len(folder)
print('今回のデータで分類するクラス数は「', str(class_number), '」です。')
#3 データセットの読み込みとデータ形式の設定・正規化・分割
X_image = []
Y_label = []
for index, name in enumerate(folder):
read_data = train_data_path + '/' + name
files = glob.glob(read_data + '/*.png') #ここを変更。png形式のファイルを利用する場合のサンプルです。
print('--- 読み込んだデータセットは', read_data, 'です。')
for i, file in enumerate(files):
if color_setting == 1:
img = load_img(file, color_mode = 'grayscale' ,target_size=(image_size, image_size))
elif color_setting == 3:
img = load_img(file, color_mode = 'rgb' ,target_size=(image_size, image_size))
array = img_to_array(img)
X_image.append(array)
Y_label.append(index)
X_image = np.array(X_image)
Y_label = np.array(Y_label)
X_image = X_image.astype('float32') / 255
#Y_label = keras.utils.to_categorical(Y_label, class_number) #Kerasのバージョンなどにより使えないのでコメントアウト
Y_label = np_utils.to_categorical(Y_label, class_number) #上記のコードのかわり
train_images, valid_images, train_labels, valid_labels = train_test_split(X_image, Y_label, test_size=0.10)
x_train = train_images
y_train = train_labels
x_test = valid_images
y_test = valid_labels
#4 機械学習(人工知能)モデルの作成 – 畳み込みニューラルネットワーク(CNN)・学習の実行等
model = Sequential()
model.add(Conv2D(16, (3, 3), padding='same',
input_shape=(image_size, image_size, color_setting), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(128, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(256, (3, 3), padding='same', activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.25))
model.add(Dense(class_number, activation='softmax'))
model.summary()
#plot_model(model, to_file='model.png') #ここはKerasのバージョンなどにより使えないのでコメントアウト
model.compile(loss='categorical_crossentropy',
optimizer=Adam(),
metrics=['accuracy'])
start_time = time.time()
# ここを変更。必要に応じて「batch_size=」「epochs=」の数字を変更してみてください。
history = model.fit(x_train,y_train, batch_size=2, epochs=5, verbose=1, validation_data=(x_test, y_test))
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.grid()
plt.legend(['Train', 'Validation'], 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.grid()
plt.legend(['Train', 'Validation'], loc='upper left')
plt.show()
open('cnn_model.json','w').write(model.to_json())
model.save_weights('cnn_weights.h5')
#model.save('cnn_model_weight.h5') #モデル構造と重みを1つにまとめることもできます
score = model.evaluate(x_test, y_test, verbose=0)
print('Loss:', score[0], '(損失関数値 - 0に近いほど正解に近い)')
print('Accuracy:', score[1] * 100, '%', '(精度 - 100% に近いほど正解に近い)')
print('Computation time(計算時間):{0:.3f} sec(秒)'.format(time.time() - start_time))
#③ 自前画像で判定(○×判定等)
#1 ライブラリのインポート等
import cv2
import matplotlib.pyplot as plt
import numpy as np
from keras.models import model_from_json
#from keras.models import load_model #model = load_model('cnn_model_weight.h5') #model.save('cnn_model_weight.h5') で保存したファイルを読み込む場合に使用
#2 各種設定
recognise_image = '1.png' #ここを変更。画像認識したい画像ファイル名。(実行前に認識したい画像ファイルを1つアップロードしてください)
folder = ['○:丸', '×:バツ'] #ここを変更。今回は日本語の表示にしたかったので、folder = ['circle', 'cross'] の順番で日本語にしています。
image_size = 28 # ここを変更。「28」を指定した場合、縦28横28ピクセルの画像に変換
# 「② 用意した自前画像で学習」と同じにする。
color_setting = 1 # ここを変更。画像認識する画像のカラー。「1」はモノクロ・グレースケール。「3」はカラー
# 「② 用意した自前画像で学習」と同じにする。
#3 各種読み込み
model = model_from_json(open('cnn_model.json', 'r').read())
model.load_weights('cnn_weights.h5')
#model = load_model('cnn_model_weight.h5') #model.save('cnn_model_weight.h5') で保存したファイルを読み込む場合に使用
#4 画像の表示・各種設定等
img = cv2.imread(recognise_image, 0) #ここを変更。モノクロ・グレースケールの場合は「0」。カラーの場合は「1」 。
img = cv2.resize(img, (image_size, image_size))
plt.imshow(img)
plt.gray() #ここを変更。カラーの場合は「plt.gray()」を消す。モノクロ・グレースケールの場合は「plt.gray()」が無いと変な色になります。
plt.show()
img = img.reshape(image_size, image_size, color_setting).astype('float32')/255
#5 予測と結果の表示等
prediction = model.predict(np.array([img]), batch_size=2, verbose=1)
result = prediction[0]
for i, accuracy in enumerate(result):
print('画像認識AIは「', folder[i], '」の確率を', int(accuracy * 100), '% と予測しました。')
print('-------------------------------------------------------')
print('画像認識AI:○ or × の予測結果は、「', folder[result.argmax()],'」です。')
***終わり:サンプルコード***
【コードの解説】自作画像認識AIプログラミング用サンプルコード・サンプルソース
① zipファイルをGoogle Colaboratoryにアップロードし、フォルダ化
!unzip dataset.zip
!unzip dataset.zip
#コード解説
:zip形式ファイルの解凍(フォルダ化)。「dataset」のところをアップロードしたzipファイル名に変更して、プログラムを実行してください。
ファイルを消す場合「!rm dataset.zip」。
② 用意した自前画像で学習(畳み込みニューラルネットワーク:CNN)
このプログラムでは、「判別したい “ラベル情報(フォルダ名)” と “画像” をセットにしたフォルダ」をアップロードすると動くようにしてあります。
今回のプログラムを動かすために必要なデータセットの構造例
(機械学習用データセットの作り方)
dataset(フォルダ名)
– circle(datasetフォルダ内のフォルダ名 – ラベル情報)
— cross(datasetフォルダ内のフォルダ名 – ラベル情報)
データセットの作り方は簡単です。「circle」「cross」の各フォルダ内に、対応する画像を配置するだけです。これならすぐに自作画像認識AIが作れそうですね。 画像の大きさは、特に指定はありません。バラバラの大きさでも実行できるようですが、必要に応じて調整してみてください。
#1 ライブラリのインポート等
import keras
import glob
import numpy as np
from sklearn.model_selection import train_test_split
# from keras.preprocessing.image import load_img, img_to_array #ここでエラーとなるので以下のコードに変更
from tensorflow.keras.utils import load_img, img_to_array
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D
from keras.layers import Dense, Dropout, Flatten
#from keras.utils import plot_model #これはKerasのバージョンなどにより使えないのでコメントアウト
from keras.utils import np_utils #keras.utils.to_categoricalでエラーが出るので追加
# from keras.optimizers import Adam # ここでエラーとなるので以下のコードに変更
from tensorflow.keras.optimizers import Adam # 「tensorflow.」を追加
import matplotlib.pyplot as plt
import time
まずは、今回の機械学習プログラムで必要なライブラリ等をインポートします。
Google ColaboratoryのJupyterノートブックの環境で コードを入力後にプログラムを実行してみてエラー表示がでたものを上記のように記載しました。現在書籍や、インターネット上に公開されているサンプルコードによっては、プラスアルファの内容の追記もあるのではないかと思います。
import keras
#コード解説
:kerasのインポート。
import glob
#コード解説
:globモジュールのインポート。引数に指定されたパターンに合うファイルパス名を取得出来る。(‘ *.png’) 等。
import numpy as np
#コード解説
:NumPyモジュールのインポート。ここでは「np」という名前でインポート。行列・ベクトル等、多次元配列の数値計算も行える拡張モジュール。
from sklearn.model_selection import train_test_split
#コード解説
:scikit-learnからtrain_test_splitをインポート。データセットを分割出来る。
from keras.preprocessing.image import load_img, img_to_array
#コード解説
:keras(keras.preprocessing.imageパッケージ)からload_img・img_to_arrayをインポート。
load_img関数:画像ファイルをPIL 形式(Pillow:Python Imaging Libraryから分岐した画像ライブラリのデータフォーマット)で読み込む。
img_to_array関数:PIL 形式からndarrayへ変換。
* 注:「keras.preprocessing API」は「Tensorflow 2.9.1」で廃止
from keras.preprocessing.image import load_img, img_to_array でエラーとなるので以下のコードに変更
from tensorflow.keras.utils import load_img, img_to_array
from keras.models import Sequential
#コード解説
:Sequential – モデル層を積み重ねる。.addメソッドで簡単に層を追加。
from keras.layers import Conv2D, MaxPooling2D
#コード解説
:Conv2d – 2次元畳み込み層のモジュール。MaxPooling2D – 2次元最大プーリング層のモジュール。
from keras.layers import Dense, Dropout, Flatten
#コード解説
:Dense – 全結合層。Dropout – ドロップアウト。Flatten – 入力を平滑化(平坦化:次元削減)。
from keras.utils import plot_model
#コード解説
:plot_modelのインポート。学習モデルの可視化が出来る。
* Kerasのバージョンによってkeras.utils.to_categoricalでエラーが出るので最新版では使用していません。
from keras.utils import np_utils
#コード解説
:Numpyユーティリティのインポート。2021年6月時点の最新版では、keras.utils.to_categoricalでエラーが出るので追加しました。
from keras.optimizers import Adam
→ 修正:from tensorflow.keras.optimizers import Adam
#コード解説
:Adam(Adaptive moment estimation)– 学習の最適化手法の1つ。最適化関数。
import matplotlib.pyplot as plt
#コード解説
:matplotlibというライブラリのpyplotモジュールをインポート。ここでは「plt」という名前でインポート。グラフの描画に利用。
import time
#コード解説
:timeモジュール。処理速度計測で利用。
#2 各種設定
train_data_path = 'dataset'
image_size = 28
color_setting = 1
folder = ['circle', 'cross']
class_number = len(folder)
print('今回のデータで分類するクラス数は「', str(class_number), '」です。')
train_data_path = ‘dataset’
#コード解説
:データセット画像の入ったフォルダの読み込み(ルート)。自分で作成したオリジナルデータセットを使う場合は、Colaboratoryにアップロードしたzipファイルを解凍後のデータセットのフォルダ名を入力します。 (’dataset’を変更します)
image_size = 28
#コード解説
:入力画像サイズ。ピクセル(画像サイズを正方形に変換します)。オリジナルデータセットを使う場合は、ここを必要に応じて変更してください。「28」を指定した場合、縦28横28ピクセルの画像に変換します。
*補足:「28」の所はプログラムの記述順としては(width 横, height 縦)のようです。
color_setting = 1
#コード解説
:データセット画像のカラー(「1」はモノクロ・グレースケール。「3」はカラー)。オリジナルデータセットを使う場合は、ここを必要に応じて変更してください。
folder = [‘circle’, ‘cross’]
#コード解説
:データセット画像のフォルダ名(クラス名)。データセット画像のフォルダ名(クラス名)を半角英数で入力します。オリジナルデータセットを使う場合は、ここを必要に応じて変更してください。正解ラベルデータに相当します。
class_number = len(folder)
print(‘今回のデータで分類するクラス数は「’, str(class_number), ‘」です。’)
#コード解説
:オリジナルデータセットのクラス数の取得(判別するラベル)と、取得したクラス数の表示。
#3 データセットの読み込みとデータ形式の設定・正規化・分割
X_image = []
Y_label = []
for index, name in enumerate(folder):
read_data = train_data_path + '/' + name
files = glob.glob(read_data + '/*.png')
print('--- 読み込んだデータセットは', read_data, ‘です。’)
for i, file in enumerate(files):
if color_setting == 1:
img = load_img(file, color_mode = 'grayscale' ,target_size=(image_size, image_size))
elif color_setting == 3:
img = load_img(file, color_mode = 'rgb' ,target_size=(image_size, image_size))
array = img_to_array(img)
X_image.append(array)
Y_label.append(index)
X_image = np.array(X_image)
Y_label = np.array(Y_label)
X_image = X_image.astype('float32') / 255
#Y_label = keras.utils.to_categorical(Y_label, class_number) #Kerasのバージョンなどにより使えないのでコメントアウト
Y_label = np_utils.to_categorical(Y_label, class_number) #上記のコードのかわり
train_images, valid_images, train_labels, valid_labels = train_test_split(X_image, Y_label, test_size=0.10)
x_train = train_images
y_train = train_labels
x_test = valid_images
y_test = valid_labels
X_image = []
Y_label = []
for index, name in enumerate(folder):
read_data = train_data_path + ‘/’ + name
files = glob.glob(read_data + ‘/*.png’)
print(‘— 読み込んだデータセットは’, read_data, ‘です。’)
#コード解説
:事前にアップロードしたオリジナルデータセットのフォルダの画像データ・正解ラベルデータを順番に読み込みます。
画像データを「X_image = []」、正解ラベルデータ(各フォルダ名・クラス名)を「Y_label = []」としています。
「read_data = train_data_path + ‘/’ + name」でフォルダの名前を読み込みます。
「files = glob.glob(read_data + ‘/*.png’) 」でフォルダ内の画像を読み込みます。
今回のプログラムでは、分かりやすいように「print( read_data)」で読み込んだデータセットを表示しています。
for i, file in enumerate(files):
if color_setting == 1:
img = load_img(file, color_mode = ‘grayscale’ ,target_size=(image_size, image_size))
elif color_setting == 3:
img = load_img(file, color_mode = ‘rgb’ ,target_size=(image_size, image_size))
array = img_to_array(img)
X_image.append(array)
Y_label.append(index)
#コード解説
:「モノクロ・グレースケール画像」の場合と、「カラー画像」の場合に分けて #2各種設定 のところで設定した「color_setting = 1 or 3」に合わせて、自動で読み込み方法を変えられるようにしています。「color_mode = 」の指定を「grayscale or rgb」に変えています。
画像のサイズも #2各種設定 のところで設定した「image_size = 28」を指定しています。
array = img_to_array(img)
#コード解説
:読み込んだ画像をPIL 形式(Pillow:Python Imaging Libraryから分岐した画像ライブラリのデータフォーマット)からndarray(NumPyの独自のデータ構造。多次元配列)に変換。
X_image.append(array)
#コード解説
:読み込んだ画像データを追加。
Y_label.append(index)
#コード解説
:読み込んだ正解ラベルデータを追加。
X_image = np.array(X_image)
Y_label = np.array(Y_label)
#コード解説
:Kerasで扱えるように、Numpy配列に変換します。
X_image = X_image.astype(‘float32’) / 255
#コード解説
:整数値(int型)から実数値(float型)に変換し、画像データを正規化。
色の変化を0〜255で表現しているので、255で割ることでデータを0〜1の範囲に正規化。float型にすることで実数値で表現。
正規化前「0〜255」(整数値:0・1・2 …)
正規化実施後「0〜1の範囲」(実数値:0.0・0.1・0.2…)
Y_label = keras.utils.to_categorical(Y_label, class_number)
#コード解説
:正解ラベルのデータ形式をOne-hotベクトル(1-of-k表記法)に変換。ラベルデータの整数値を2値クラスの行列に変換。
例 – 「整数 0」を「1, 0」と表現。「整数 1」を「0, 1」と表現。
2021年6月時点では、Kerasのバージョンなどにより上記のコードでは実行できないようでした。そのため
Y_label = np_utils.to_categorical(Y_label, class_number)
を利用することにしました。
(Y_label, class_number)
#コード解説
:サンプルプログラムのオリジナルデータセットでは、「circle」「cross」のデータのため2クラス。
このような形式にすることで、出力結果が「0.1 , 0.9」(「0:circle」の確率10%。「1:cross」の確率90%)を得られる。
画像データが機械学習モデルで、どういう判定結果となっているか?という情報を取得できる。
train_images, valid_images, train_labels, valid_labels = train_test_split(X_image, Y_label, test_size=0.10)
#コード解説
:訓練データ(train_images, train_labels)と検証データ(valid_images, valid_labels)に分割。「test_size=0.10」で9割を訓練データにする。1割を検証データにする。
データ分割に関しては、
・訓練データ(test data)
:機械学習のモデルを学習(調整)するために利用。
・検証データ(validation data)
:学習に使用していないデータで学習結果を評価。
・テストデータ(test data)
:機械学習モデルの学習が完了後に、訓練データ・検証データに使用していないテスト
データを使用し、最終的な精度・予測結果を評価。
等があるようですが、今回はモデルの学習のところでは検証データ(validation data)とテストデータ(test data)を同じものとして扱っています。厳密には、検証データ(validation data)への過学習予防のために、検証データ(validation data)・テストデータ(test data)を分けた方が良いようです。
x_train = train_images
y_train = train_labels
x_test = valid_images
y_test = valid_labels
#コード解説
:「x_train」「y_train」「x_test」「y_test」を定義。
学習データは多次元のため、行列を大文字で表記することが多い数学の慣習から、(X_train, y_train), (X_test, y_test)等と学習データを表記する際の「エックス」が大文字のサンプルコードを見かけることもあるのではないかと思います。今回は、学習データ・クラスラベル(正解ラベル)共に小文字を利用しています。
#4 機械学習(人工知能)モデルの作成 – CNN・学習の実行等
model = Sequential()
model.add(Conv2D(16, (3, 3), padding='same',
input_shape=(image_size, image_size, color_setting), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(128, (3, 3), padding='same', activation='relu'))
model.add(Conv2D(256, (3, 3), padding='same', activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.25))
model.add(Dense(class_number, activation=‘softmax'))
model.summary()
plot_model(model, to_file='model.png')
model.compile(loss='categorical_crossentropy',
optimizer=Adam(),
metrics=['accuracy'])
start_time = time.time()
history = model.fit(x_train, y_train, batch_size=2, epochs=5, verbose=1, validation_data=(x_test, y_test))
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('Model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.grid()
plt.legend(['Train', 'Validation'], 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.grid()
plt.legend(['Train', 'Validation'], loc='upper left')
plt.show()
open('cnn_model.json','w').write(model.to_json())
model.save_weights('cnn_weights.h5')
#model.save('cnn_model_weight.h5') #モデル構造と重みを1つにまとめることもできます
score = model.evaluate(x_test, y_test, verbose=0)
print('Loss:', score[0], '(損失関数値 - 0に近いほど正解に近い)')
print('Accuracy:', score[1] * 100, '%', '(精度 - 100% に近いほど正解に近い)')
print('Computation time(計算時間):{0:.3f} sec(秒)'.format(time.time() - start_time))
*注:model.add(Dense(class_number, activation=‘softmax’))以降のハイライトが失敗していますがご了承ください。
model = Sequential()
model.add(Conv2D(16, (3, 3), padding=’same’,
input_shape=(28, 28, color_setting), activation=’relu’))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(128, (3, 3), padding=’same’, activation=’relu’))
model.add(Conv2D(256, (3, 3), padding=’same’, activation=’relu’))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.5))
model.add(Flatten())
model.add(Dense(128, activation=’relu’))
model.add(Dropout(0.25))
model.add(Dense(class_number, activation=‘softmax’))
model.summary()
plot_model(model, to_file=’model.png’) #ここはKerasのバージョンなどにより使えないのでコメントアウト
「Conv2D」を使ってディープラーニング技術でおなじみの「畳み込みニューラルネットワーク」(CNN)を実装しています。
model = Sequential()
#コード解説
:Sequential – モデル層を積み重ねる形式の記述方法。.addメソッドで簡単に層を追加できます。
model.add(Conv2D(16, (3, 3), padding=’same’,
input_shape=(28, 28, color_setting), activation=’relu’))
#コード解説
:空間フィルタ – 畳み込み演算層。
Conv2D(16, (3, 3)の解説
:「3×3」の大きさのフィルタを16枚使うという意味です。「5×5」「7×7」等と、中心を決められる奇数が使いやすいようです。
フィルタ数は、「16・32・64・128・256・512枚」等が使われる傾向にあるようですが、複雑そうな問題ならフィルタ数を多めに、簡単そうな問題ならフィルタ数を少なめで試してみるようです。
padding=’same’の解説
:今回は出力画像のサイズが変わらないように「padding=’same’」でパディングを実施。フィルタを適用前に0等の要素で周囲を増やすようです。(ゼロパディング)
その他にも「stride=(1,1)」(横に1ピクセル・縦に1ピクセルずつフィルタを適用)等とストライドの追加も可能。strideを指定しない場合(デフォルト)は縦・横1ピクセルずつフィルタが適用されるようです。(「stride=(1,1)」の意味)
input_shape=(image_size, image_size, color_setting)の解説
:画像のサイズは #2各種設定 のところで設定した「image_size = 28」の設定が反映されます。「color_setting」は #2各種設定 のところで設定した「モノクロ・グレースケール画像」(color_setting = 1)、「カラー画像」(color_setting = 3)の設定が反映されます。今回のサンプルコードでは、縦28・横28ピクセルのモノクロ・グレースケール(白黒画像)を入力しています。
activation=’relu’の解説
:活性化関数「ReLU(Rectified Linear Unit)- ランプ関数」。フィルタ後の画像に実施。入力が0以下の時は出力0。入力が0より大きい場合はそのまま出力する。
model.add(MaxPooling2D(pool_size=(2, 2)))
#コード解説
:「2×2」の大きさの最大プーリング層。入力画像内の「2×2」の領域で最大の数値を出力する。
model.add(Conv2D(128, (3, 3), padding=’same’, activation=’relu’))
#コード解説
:空間フィルタ – 畳み込み演算層。「3×3」の大きさのフィルタを128枚使う。出力画像のサイズが変わらないように「padding=’same’」でパディングを実施。
活性化関数「ReLU(Rectified Linear Unit)- ランプ関数」。フィルタ後の画像に実施。入力が0以下の時は出力0。入力が0より大きい場合はそのまま出力する。
model.add(Conv2D(256, (3, 3), padding=’same’, activation=’relu’))
#コード解説
:空間フィルタ – 畳み込み演算層。「3×3」の大きさのフィルタを256枚使う。出力画像のサイズが変わらないように「padding=’same’」でパディングを実施。
活性化関数「ReLU(Rectified Linear Unit)- ランプ関数」。フィルタ後の画像に実施。入力が0以下の時は出力0。入力が0より大きい場合はそのまま出力する。
model.add(MaxPooling2D(pool_size=(2, 2)))
#コード解説
:「2×2」の大きさの最大プーリング層。入力画像内の「2×2」の領域で最大の数値を出力する。
model.add(Dropout(0.5))
#コード解説
:ドロップアウト – 過学習予防。今回は、全結合の層とのつながりを「50%」無効化しています。
model.add(Flatten())
#コード解説
:平坦化(次元削減) – 1次元ベクトルに変換する。
model.add(Dense(128, activation=’relu’))
#コード解説
:全結合層。出力128。
活性化関数「ReLU(Rectified Linear Unit)- ランプ関数」。入力が0以下の時は出力0。入力が0より大きい場合はそのまま出力する。
model.add(Dropout(0.25))
#コード解説
:ドロップアウト – 過学習予防。全結合の層とのつながりを「25%」無効化しています。
model.add(Dense(class_number, activation=’softmax’))
#コード解説
:全結合層。Denseのところで、畳み込みニューラルネットワーク(CNN)の最終的な全結合層の出力次元数の決め方は、判定するクラス数を指定します。そのため、出力数は #2各種設定 のところで設定した「class_number」の値を指定(「サンプルプログラムのオリジナルデータセットでは、「circle」「cross」のデータ」の2クラス判定のため、最終的な全結合層の出力次元数が「2」になります。)
Softmax関数で総和が1となるように、各出力の予測確率を計算。
例「0.1, 0.9」(0:circleの確率10%。1:crossの確率90%)
model.summary()
#コード解説
:機械学習モデルの詳細を表示します。サンプルコードでは「畳み込みニューラルネットワーク」(CNN)モデルの表示。
Model:sequential(画像)
plot_model(model, to_file=’model.png’)
#コード解説
:機械学習モデルの流れのイメージを保存します。サンプルコードでは「model.png」という名前のpng画像が、実行中のGoogle Colaboratoryの「ファイル」内に保存されます。
2021年6月時点では、Kerasのバージョンなどにより「plot_model」が使えないようでしたのでコメントアウト(コードの無効化)をしました。
model.png(画像)
実行中のGoogle Colaboratoryの「ファイル」内に保存(画像)
model.compile(loss=’categorical_crossentropy’,
optimizer=Adam(),
metrics=[‘accuracy’])
損失関数・最適化関数・評価関数等を指定してモデルをコンパイル(コンピュータが実行可能な形式に変換)。
loss=’categorical_crossentropy’
#コード解説
:損失化関数 – 交差エントロピー誤差を指定しています。今回のような分類問題(識別問題)等で使われるようです。
optimizer=Adam()
#コード解説
:最適化関数 – Adam(Adaptive moment estimation)を指定しています。学習の最適化手法の1つのようです。
metrics=[‘accuracy’]
#コード解説
:評価関数 – 訓練時と検証時にモデルにより評価される評価関数。学習の評価として正解率も計算します。
start_time = time.time()
#コード解説
:今回は、計算にかかった時間のスピード計測もするため処理を始めた時間を記録(取得)します。
history = model.fit(x_train, y_train, batch_size=2, epochs=5,
verbose=1, validation_data=(x_test, y_test))
#コード解説
:訓練データで学習を実行します。
x_train, y_train
#コード解説
:訓練データ(画像とラベルデータ)を使用。
batch_size=2
#コード解説
:バッチサイズは機械学習分野の慣習として、「2のn乗」(32, 64, 128, 256, 512, 1024, 2048)が使われることが多いようです。
公開されているサンプルコードによっては「1000」等のきりの良い数字を使っている場合もあるのではないかと思います。
バッチサイズのように、サブセットに分けて学習する理由として、学習する際の異常値の影響を小さくするためのようです。今回は、データ数は少ないので小さめの値を指定しています。
epochs=5
#コード解説
:学習する回数を指定します。
学習回数を増やすと計算するのに時間がかかります。Google Colaboratoryではインターネット接続環境で無料で学習を実行できるので、回数を調整する際もありがたいです。
「Early Stopping」という手法もあるようですが、個人で情報収集してみた範囲では、学習回数に関して最終的には試行錯誤のようです。
verbose
#コード解説
:ログ出力の指定。「1」だとログが表示されます。 「0」だとログが出ないの設定。
validation_data=(x_test, y_test)
#コード解説
:検証用データの指定。
(x_test, y_test)で検証用データ(validation_data)を指定しています。
学習結果「Train・validation数の表示」「各学習結果の表示」(画像)
score = model.evaluate(x_test, y_test, verbose=0)
plt.plot(history.history[‘accuracy’])
plt.plot(history.history[‘val_accuracy’])
plt.title(‘Model accuracy’)
plt.ylabel(‘Accuracy’)
plt.xlabel(‘Epoch’)
plt.grid()
plt.legend([‘Train’, ‘Validation’], 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.grid()
plt.legend([‘Train’, ‘Validation’], loc=’upper left’)
plt.show()
open(‘cnn_model.json’,’w’).write(model.to_json())
model.save_weights(‘cnn_weights.h5′)
print(‘Loss:’, score[0])
print(‘ Accuracy:’, score[1] * 100, ‘%’, ‘(精度 – 100% に近いほど正解に近い)’)
print(‘Computation time:{0:.3f} sec’.format(time.time() – start_time))
score = model.evaluate(x_test, y_test, verbose=0)
#コード解説
:「x_test = valid_images」「y_test = valid_labels」のデータ画像・正解ラベルで学習モデルの評価を実施。
verbose
#コード解説
:ログ出力の指定。ログ出力の指定。「1」だとログが表示されます。「0」だとログが出ないの設定。
plt.plot(history.history[‘accuracy’])
plt.plot(history.history[‘val_accuracy’])
plt.title(‘Model accuracy’)
plt.ylabel(‘Accuracy’)
plt.xlabel(‘Epoch’)
plt.grid()
plt.legend([‘Train’, ‘Validation’], loc=’upper left’)
plt.show()
matplotlibライブラリのモジュールのpyplotのplot関数で、以下のグラフを表示します。
plt.plot(history.history[‘accuracy’])
plt.plot(history.history[‘val_accuracy’])
#コード解説
:「accuracy:訓練データ(train data)の精度」「val_accuracy:検証データ(validation data)での精度」の記録をグラフ上にプロット(描き入れる)。
plt.title(‘Model accuracy’)
#コード解説
:タイトルの表記。機械学習モデルの精度。
plt.ylabel(‘Accuracy’)
#コード解説
:グラフのY軸(縦軸)の表記。精度。
plt.xlabel(‘Epoch’)
#コード解説
:グラフのX軸(横軸)の表記。エポック数(訓練データを学習させる回数)。
plt.grid()
#コード解説
:グリッド(メモリ線)をプロット(描き入れる)。
plt.legend([‘Train’, ‘Validation’], loc=’upper left’)
#コード解説
:ラベル(凡例)の表記。
「[‘Train’, ‘Validation’], loc=’upper left’:Train・Validationのラベルを左上にプロット(描き入れる)」
plt.show()
#コード解説
:グラフを表示する。
plt.plot(history.history[‘loss’])
plt.plot(history.history[‘val_loss’])
plt.title(‘Model loss’)
plt.ylabel(‘Loss’)
plt.xlabel(‘Epoch’)
plt.grid()
plt.legend([‘Train’, ‘Validation’], loc=’upper left’)
plt.show()
matplotlibライブラリのモジュールのpyplotのplot関数で、以下のグラフを表示します。
plt.plot(history.history[‘los’])
plt.plot(history.history[‘val_los’])
#コード解説
:「los:訓練データ(train data)の損失関数」「val_los:検証データ(validation data)での損失関数」の記録をグラフ上にプロット(描き入れる)。
plt.title(‘Model loss’)
#コード解説
:タイトルの表記。機械学習モデルの損失関数。
plt.ylabel(‘Accuracy’)
#コード解説
:グラフのY軸(縦軸)の表記。精度。
plt.xlabel(‘Epoch’)
#コード解説
:グラフのX軸(横軸)の表記。エポック数(訓練データを学習させる回数)。
plt.grid()
#コード解説
:グリッド(メモリ線)をプロット(描き入れる)。
plt.legend([‘Train’, ‘Validation’], loc=’upper left’)
#コード解説
:ラベル(凡例)の表記。
「[‘Train’, ‘Validation’], loc=’upper left’:Train・Validationのラベルを左上にプロット(描き入れる)」
plt.show()
#コード解説
:グラフを表示する。
open(‘cnn_model.json’,’w’).write(model.to_json())#変更コード サンプルコードではコメントアウトしています。
#コード解説
:機械学習モデルの保存。今回は「cnn_model.json」という名前で保存しています。実行中のGoogle Colaboratoryの「ファイル」内に保存されます。
model.save_weights(‘cnn_weights.h5’)#変更コード サンプルコードではコメントアウトしています。
#コード解説
:機械学習モデルの重みを保存。今回は「cnn_weights.h5」という名前で保存しています。実行中のGoogle Colaboratoryの「ファイル」内に保存されます。
model.save(‘cnn_model_weight.h5’)
#コード解説
:機械学習の「モデル構造」と学習済みの「重み」を1つのファイルに保存できるmodel.saveを使う方法もあります。
実行中のGoogle Colaboratoryの「ファイル」内に保存されます。
実行中のGoogle Colaboratoryの「ファイル」内に保存(画像)
* model.save(‘cnn_model_weight.h5’) で学習済みモデルを保存した際の例
print(‘Loss:’, score[0])
print(‘ Accuracy:’, score[1] * 100, ‘%’, ‘(精度 – 100% に近いほど正解に近い)’)
print(‘Computation time:{0:.3f} sec’.format(time.time() – start_time))
print(‘Loss:’, score[0])
#コード解説
:score[0] – 検証用データの交差エントロピー誤差を表示します。
print(‘Accuracy:’, score[1] * 100, ‘%’, ‘(テストデータに対する精度 – 100% に近いほど正解に近い)’)
#コード解説
:score[1] – 最終的な検証用データの正解率(精度)を表示します。今回は100を掛けて%表示しています。
print(‘Computation time:{0:.3f} sec’.format(time.time() – start_time))
#コード解説
:計算処理にかかった時間を表示します。
{0:.3f}
:{通し番号:float型の小数点以下3桁まで表示}
(time.time() – start_time)
:結果出力時の時間 – 学習スタート時の時間
③ 自前画像で判定(○×判定等)
作成した画像認識AIを使って、画像認識に挑戦してみます。
今回のサンプルコードでは、機械学習の「モデル」(cnn_model.json)の読み込みと、機械学習の「重み」(cnn_weights.h5)の読み込みを行い画像認識AIを作成しています。
上手く認識出来るでしょうか?
#1 ライブラリのインポート等
import cv2
import matplotlib.pyplot as plt
import numpy as np
from keras.models import model_from_json
#from keras.models import load_model #model = load_model('cnn_model_weight.h5') #model.save('cnn_model_weight.h5') で保存したファイルを読み込む場合に使用
import cv2
#コード解説
:コンピュータビジョン向けライブラリのOpenCVのインポート。
import matplotlib.pyplot as plt
#コード解説
:matplotlibというライブラリのpyplotモジュールをインポート。ここでは「plt」という名前でインポート。グラフの描画に利用。
import numpy as np
#コード解説
:NumPyモジュールのインポート。ここでは「np」という名前でインポート。行列・ベクトル等、多次元配列の数値計算も行える拡張モジュール。
from keras.models import model_from_json
#コード解説
:model_from_jsonのインポート。json形式のモデルの読み込みに利用。
from keras.models import load_model
#コード解説
:機械学習の「モデル構造」と学習済みの「重み」を1つのファイルに保存できるmodel.saveで保存されたファイルの読み込みのためload_modelをインポート。cnn_model_weight.h5の読み込み用です。
#2 各種設定
recognise_image = '1.png'
folder = ['○:丸', '×:バツ']
image_size = 28
color_setting = 1
recognise_image = ‘1.png’
#コード解説
:画像認識したい画像ファイル名。
(実行前に認識したい画像ファイルを1つアップロードしてください。)
folder = [‘○:丸’, ‘×:バツ’]
#コード解説
:フォルダ名の設定。学習の際のモデルでは、データセット画像のフォルダ名(クラス名)を「folder = [‘circle’, ‘cross’]」で設定しています。今回は、日本語の表示をしたいので「folder = [‘circle’, ‘cross’]」の順番に「folder = [‘○:丸’, ‘×:バツ’] 」を設定し、日本語の表示が出来るようにしています。
image_size = 28
#コード解説
:入力画像サイズ(画像サイズは正方形)。「28」を指定した場合、縦28横28ピクセルの画像に変換。畳み込みニューラルネットワーク(CNN)の機械学習モデルを訓練した際の設定と同じにする。
color_setting = 1
#コード解説
:入力画像(インプットイメージ)のカラーモード。
「1」はモノクロ・グレースケール。「3」はカラー。
畳み込みニューラルネットワーク(CNN)の機械学習モデルを訓練した際の設定と同じにする。
#3 各種読み込み
model = model_from_json(open('cnn_model.json', 'r').read())
model.load_weights('cnn_weights.h5')
#model = load_model('cnn_model_weight.h5')
model = model_from_json(open(‘cnn_model.json’, ‘r’).read())
#コード解説
:機械学習の「モデル」の読み込み。「cnn_model.json」のファイルを読み込みます。
model.load_weights(‘cnn_weights.h5’)
#コード解説
:機械学習の「重み」の読み込み。「cnn_weights.h5」のファイルを読み込みます。
model = load_model(‘cnn_model_weight.h5’)
#コード解説
:機械学習の「モデル構造」と学習済みの「重み」を1つのファイルに保存できるmodel.saveで作成したファイルの読み込む場合に使います。
#4 画像の表示・各種設定等
img = cv2.imread(recognise_image, 0)
img = cv2.resize(img, (image_size, image_size))
plt.imshow(img)
plt.gray()
plt.show()
img = img.reshape(image_size, image_size, color_setting).astype('float32')/255
img = cv2.imread(recognise_image, 0)
#コード解説
:認識したい画像をモノクロ・グレースケールや、カラーを指定して読み込み。
モノクロ・グレースケールの場合は「0」。カラーの場合は「1」 。
img = cv2.resize(img, (image_size, image_size))
#コード解説
:画像を指定した大きさにリサイズ。今回は縦28ピクセル・横28ピクセル。
plt.imshow(img)
#コード解説
:認識したい画像の出力。ここに「plt.imshow(img)」を入れるとコード実行時の一番始めに画像が表示されるようでした。
plt.gray()
#コード解説
:モノクロ・グレースケールの場合は「plt.gray()」が無いと変な色になります。カラーの場合は「plt.gray()」を消してください。
plt.show()
#コード解説
:認識したい画像を表示。「plt.imshow(img)」の後に「plt.show()」を入れるとコード実行時の一番始めに画像が表示されるようでした。
img = img.reshape(image_size, image_size, color_setting).astype(‘float32’)/255
#コード解説
:畳み込みニューラルネットワーク(CNN)の機械学習モデルで訓練した際の画像データに合わせる。
#5 予測と結果の表示等
prediction = model.predict(np.array([img]), batch_size=2, verbose=1)
result = prediction[0]
for i, accuracy in enumerate(result):
print('画像認識AIは「', folder[i], '」の確率を', int(accuracy * 100), '% と予測しました。')
print('-------------------------------------------------------')
print('画像認識AI:○ or × の予測結果は、「', folder[result.argmax()],'」です。')
prediction = model.predict(np.array([img]), batch_size=2, verbose=1)
result = prediction[0]
#コード解説
:画像を予測する。「batch_size=」は、畳み込みニューラルネットワーク(CNN)の機械学習モデルで訓練した際の「batch_size=」に合わせる。「verbose=」でログ出力の指定。「1」だとログが表示されます。「0」だとログが出ないの設定。
for i, accuracy in enumerate(result):
print(‘画像認識AIは「’, folder[i], ‘」の確率を’, int(accuracy * 100), ‘% と予測しました。’)
#コード解説
:予測結果の表示(確率)。今回は%表示にするために 100を掛けています。
print(‘——————————————————-‘)
print(‘画像認識AI:○ or × の予測結果は、「’, folder[result.argmax()],’」です。’)
#コード解説
:判別結果の表示。「result.argmax」で配列の最大要素のインデックスを返します。
(予測確率が一番高い正解ラベルを出力)
気がつけば大量のページ数となってしまいました… ここまで読んでくださりありがとうございました。
以上、簡単ではありますがコードの解説です。
1回読んだだけでは、意味が分からないのではないかと思いますが、適宜、用語を調べつつ読み返すことで身につくのではないかと思います。とりあえずはオリジナルデータセットを作成しコードを試してみてください。
印刷用PDF:【コード解説】自作画像認識AI:畳み込みニューラルネットワーク(CNN)サンプルコード – Colaboratory・Keras・Python
学習の利便性を考え、印刷しやすいようにPDFも作成しておきました。
プリンタの印刷設定で、ブックレット等の冊子風に印刷すると読みやすいのではないかと思います。
【コード解説】自作画像認識AI:Keras・CNN・Pythonオリジナルデータセット対応の機械学習サンプルコード by 日本人のための人工知能プログラマー入門講座(2019年12月22日版)| PDF無料ダウンロード
初版:2019年12月16日(最終更新:2019年12月22日)
* 2021年2月8日時点のこの記事では「acc」「vall_acc」の記述を、「accuracy」「val_accuracy」に変更しています。
PDF版では変更されていませんので、読み替えて頂けますと幸いです。
* 2021年6月7日〜2023年2月14日時点のこの記事では
#1 ライブラリのインポート等
#from keras.utils import plot_model #これはKerasのバージョンなどにより使えないのでコメントアウト
from keras.utils import np_utils #keras.utils.to_categoricalでエラーが出るので追加
# from keras.optimizers import Adam # ここでエラーとなるので以下のコードに変更
from tensorflow.keras.optimizers import Adam # 「tensorflow.」を追加
# from keras.preprocessing.image import load_img, img_to_array #ここでエラーとなるので以下のコードに変更
from tensorflow.keras.utils import load_img, img_to_array
#3 データセットの読み込みとデータ形式の設定・正規化・分割
#Y_label = keras.utils.to_categorical(Y_label, class_number) #Kerasのバージョンなどにより使えないのでコメントアウト
Y_label = np_utils.to_categorical(Y_label, class_number) #上記のコードのかわり
#4 機械学習(人工知能)モデルの作成 – 畳み込みニューラルネットワーク(CNN)・学習の実行等
#plot_model(model, to_file=’model.png’) #ここはKerasのバージョンなどにより使えないのでコメントアウト
等の変更がありますが、PDF版では変更されていませんので、ご了承ください。
Webアプリ化に挑戦
:【コード解説】自作画像認識編 Flask(Python)Web機械学習アプリ開発入門:画像アップロード判定プログラム