こんにちは、さすを(@sasuwo0409)です。
いきなりですが、
今話題のPythonで機械学習をしてみたい!
機械学習を手軽に体験してみたい!
自動で画像を分類したい!
と思ってはいませんか?
今回の記事は、Pythonを使って、画像分類の機械学習をする方法を解説していきます。
サンプルコードも載せているので、実際に試してみることも可能です。
それでは本文をどうぞ。
機械学習で画像分類をしてみたいけど、やり方がわからなくて困ってる。
手順をサンプルコードを見ながら教えて欲しいな。
この悩みを解決します!
※0円のサンプルテキストという近道
独学よりプログラミングスクールの方が効果は出やすいですが、値段が高く、なかなか手を出しづらいですよね。techgymでは無料のサンプルテキストと解説動画をもらえるので、これを使ってお得にPythonの基礎を学ぶのもオススメです。
最短1分でできる!
機械学習で画像分類する方法【Python】
機械学習で画像分類する手順は、以下の通りです。
- 画像を格納するフォルダを作成する
- 学習する画像を集める
- ドライブの準備をする
- 画像の前処理をする
- 学習モデルの準備をする
- 学習及び精度の確認をする
- モデルとラベルを保存する
- 実際に予測をする
なお、今回はGoogle Colaboratory上でプログラムを動かしていきます。
Google Colaboratoryの使い方については「【3分で解決!】Google Colaboratoryの使い方【無料ですぐにPythonを使えます】」で解説しているので、参考にしてみてください。
その①:画像を格納するフォルダを作成する
まず初めに、画像を保存するフォルダを作成しましょう。
フォルダ構成は以下の通りです。
Google Colab
-----image_judgememt.ipynb(これから作るスクリプト)
-----sample(判別したい画像を格納するフォルダ)
----------sample.jpg
----------sample2.jpg
-----output(判別後の画像を格納するフォルダ)
----------dog(deep_learningフォルダ内のフォルダ名と同一にする)
--------------sample(複数枚の画像処理をするときに必要)
----------cat(deep_learningフォルダ内のフォルダ名と同一にする)
--------------sample(複数枚の画像処理をするときに必要)
-----img
----------deep_learning
---------------dog(機械学習させる画像フォルダ①)
---------------cat(機械学習させる画像フォルダ②)
今回はsampleフォルダに「sample.jpg」という名前で犬の画像を格納しています。
この記事の最終的なゴールは、読み込んだ画像を犬と判断し、outputフォルダの中のdogフォルダに格納されることです。
フォルダ構成を変更してもOKですが、後述するプログラムの保存先フォルダ名が変わるので注意してください。
分類したい画像は何でもOKです!
その②:学習する画像を集める
機械学習をするためには、学習する画像を大量に集める必要があります。
ここで集める画像が多ければ多いほど、機械学習の精度が上がるので、学習させる画像をどんどん「deep_learning」フォルダ下に追加していきましょう。
なお、自動で画像を集める方法は「【コピペOKです】Pythonを使って自動でGoogle画像を収集する方法を徹底解説!」で解説しているので、これから画像を準備する方は参考にしてみてください。
欲しい画像を自動で何百枚も集めることができるので、効率よく機械学習を進めることができます。
その③:ドライブの準備をする
画像を集め終わったら、ドライブの準備を行います。
今回は深層学習で計算していくので、ランタイムは、計算速度の速いGPUで行いましょう。
Google Colaboratory上で「ランタイム」→「ランタイムのタイプを変更」の順にクリックし、「ハードウェア アクセラレータ」をGPUに変更すればOKです。
ランタイムが変更できたら、ドライブをマウントし、カレントディレクトリを移動します。
#ドライブをマウントする
from google.colab import drive
drive.mount('/content/drive')
補足:
上記のコマンドを実行すると、以下の画面が現れます。手順通りに操作すればOKです。
1.URLを押下する。
2.希望のアカウントを選択する。
3.ログインを押下する。
4.コードをコピーし、「Enter your authorization code」に入力する。
#カレントディレクトリに移動
%cd "/content/drive/My Drive/Google Colab"
これで、Google Colaboratory上でプログラムを書く準備が整いました。
その④: 画像の前処理をする
ドライブの準備が終わったら、画像の前処理を行っていきます。
画像の前処理をすることで、集めた画像を機械学習できるようになります。
画像の前処理を行うプログラムはこちらです。
import os
import cv2
import numpy as np
import glob as glob
from sklearn.model_selection import train_test_split
from keras.utils import np_utils
#フォルダをクラス名にする
path = "img/deep_learning"
folders = os.listdir(path)
#フォルダ名を抽出
classes = [f for f in folders if os.path.isdir(os.path.join(path, f))]
n_classes = len(classes)
#画像とラベルの格納
X = []
Y = []
#画像を読み込みリサイズする
for label,class_name in enumerate(classes):
files = glob.glob(path + "/" + class_name + "/*.jpg")
for file in files:
img = cv2.imread(file)
img = cv2.resize(img,dsize=(224,224))
X.append(img)
Y.append(label)
#精度を上げるために正規化
X = np.array(X)
X = X.astype('float32')
X /= 255.0
#ラベルの変換
Y = np.array(Y)
Y = np_utils.to_categorical(Y,n_classes)
Y[:5]
#学習データとテストデータに分ける(テストデータ2割、学習データ8割)
X_train,X_test,Y_train,Y_test = train_test_split(X,Y,test_size=0.2)
#学習データ(8割)
print(X_train.shape)
#テストデータ(2割)
print(X_test.shape)
#学習データ(8割)
print(Y_train.shape)
#テストデータ(2割)
print(Y_test.shape)
すべてのデータを学習させると、機械学習の精度確認の結果が必ず100%になってしまうので、今回は、8割の学習データを使用し、2割の学習していないテストデータの画像を使って精度を確認することにします。
#出力結果:
(218,224,224,3)
(55,224,224,3)
(218,2)
(55,2)
ここの数値は、集めた画像の枚数と学習データ・テストデータの割合によって変わってきます!
その⑤:学習モデルの準備をする
画像の前処理が終わったら、学習モデルの準備を行っていきます。
学習モデルの準備を行うプログラムはこちらです。
from keras.applications.vgg16 import VGG16
from keras.models import Sequential
from keras.models import model_from_json
from keras.models import Model
from keras.layers import Input, Activation, merge, Dense, Flatten, Dropout
from tensorflow.keras.optimizers import Adam
#vgg16
input_tensor = Input(shape=(224,224,3))
#最後の1000の層を省く
base_model = VGG16(weights='imagenet', input_tensor=input_tensor,include_top=False)
#後付けで入れたい層の作成
top_model = Sequential()
top_model.add(Flatten(input_shape=base_model.output_shape[1:]))
top_model.add(Dense(n_classes, activation='softmax'))
#結合
model = Model(inputs=base_model.input, outputs=top_model(base_model.output))
#学習させない層
for layer in model.layers[:15]:
layer.trainable = False
print('# layers=', len(model.layers))
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
model.summary()
今回の実装では2つの画像の分類なので、VGG16の最後の1,000の層を省き、後付けで2つの層を作成し、結合させています。
また、処理時間を短くするために、最初から15層はスキップしています。
最初の15層を省いても精度は高いので問題ありません!
出力結果:
Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/vgg16/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5
58892288/58889256 [==============================] - 1s 0us/step
58900480/58889256 [==============================] - 1s 0us/step
# layers= 20
Model: "model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 224, 224, 3)] 0
block1_conv1 (Conv2D) (None, 224, 224, 64) 1792
block1_conv2 (Conv2D) (None, 224, 224, 64) 36928
block1_pool (MaxPooling2D) (None, 112, 112, 64) 0
block2_conv1 (Conv2D) (None, 112, 112, 128) 73856
block2_conv2 (Conv2D) (None, 112, 112, 128) 147584
block2_pool (MaxPooling2D) (None, 56, 56, 128) 0
block3_conv1 (Conv2D) (None, 56, 56, 256) 295168
block3_conv2 (Conv2D) (None, 56, 56, 256) 590080
block3_conv3 (Conv2D) (None, 56, 56, 256) 590080
block3_pool (MaxPooling2D) (None, 28, 28, 256) 0
block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160
block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808
block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808
block4_pool (MaxPooling2D) (None, 14, 14, 512) 0
block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808
block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808
block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808
block5_pool (MaxPooling2D) (None, 7, 7, 512) 0
sequential (Sequential) (None, 2) 50178
=================================================================
Total params: 14,764,866
Trainable params: 7,129,602
Non-trainable params: 7,635,264
後ろの5層を足すと Trainable paramの数になります!
その⑥:学習及び精度の確認をする
学習モデルの準備が終わったら、学習及び精度を確認していきましょう。
学習及び精度を確認するプログラムはこちらです。
#学習データで学習
model.fit(X_train, Y_train, epochs=20, batch_size=16)
#テストデータで精度確認
score = model.evaluate(X_test, Y_test, batch_size=16)
#出力結果
Epoch 1/20
14/14 [==============================] - 21s 451ms/step - loss: 1.2006 - accuracy: 0.5872
Epoch 2/20
14/14 [==============================] - 2s 156ms/step - loss: 0.6287 - accuracy: 0.6972
Epoch 3/20
14/14 [==============================] - 2s 156ms/step - loss: 0.6183 - accuracy: 0.6560
Epoch 4/20
14/14 [==============================] - 2s 156ms/step - loss: 0.6581 - accuracy: 0.7018
Epoch 5/20
14/14 [==============================] - 2s 157ms/step - loss: 0.9076 - accuracy: 0.6514
Epoch 6/20
14/14 [==============================] - 2s 157ms/step - loss: 0.5722 - accuracy: 0.6881
Epoch 7/20
14/14 [==============================] - 2s 156ms/step - loss: 0.4781 - accuracy: 0.7661
Epoch 8/20
14/14 [==============================] - 2s 156ms/step - loss: 0.2508 - accuracy: 0.8853
Epoch 9/20
14/14 [==============================] - 2s 156ms/step - loss: 0.1376 - accuracy: 0.9633
Epoch 10/20
14/14 [==============================] - 2s 156ms/step - loss: 0.1028 - accuracy: 0.9725
Epoch 11/20
14/14 [==============================] - 2s 156ms/step - loss: 0.0675 - accuracy: 0.9771
Epoch 12/20
14/14 [==============================] - 2s 156ms/step - loss: 0.0818 - accuracy: 0.9633
Epoch 13/20
14/14 [==============================] - 2s 155ms/step - loss: 0.0046 - accuracy: 1.0000
Epoch 14/20
14/14 [==============================] - 2s 157ms/step - loss: 0.0405 - accuracy: 0.9862
Epoch 15/20
14/14 [==============================] - 2s 156ms/step - loss: 0.1864 - accuracy: 0.9495
Epoch 16/20
14/14 [==============================] - 2s 157ms/step - loss: 0.1001 - accuracy: 0.9679
Epoch 17/20
14/14 [==============================] - 2s 158ms/step - loss: 0.0164 - accuracy: 0.9954
Epoch 18/20
14/14 [==============================] - 2s 157ms/step - loss: 0.0322 - accuracy: 0.9908
Epoch 19/20
14/14 [==============================] - 2s 156ms/step - loss: 0.0173 - accuracy: 0.9954
Epoch 20/20
14/14 [==============================] - 2s 156ms/step - loss: 0.0033 - accuracy: 1.0000
4/4 [==============================] - 4s 1s/step - loss: 0.3133 - accuracy: 0.9273
出力結果を見ると、学習回数が増えるほど、正答率である「accracy」が上がっていることがわかります。
そして、最後の2行は、学習していない画像を実際に分類させたときの正答率です。
つまり、この出力結果からは、学習データを20周させたときの画像分類の正答率は100%、テストデータの画像分類の正答率は92.73%ということがわかります。
学習していたデータに比べると、テストデータの精度は落ちることが多いです!
その⑦:モデルとラベルを保存する
学習及び精度の確認が終わったら、モデルとラベルを保存します。
ここには機械学習済みのデータが残っているので、これから予測するときは、このファイルを読み込むだけでできるようになります。
import pickle
#クラス名の保存
pickle.dump(classes, open('classes.sav', 'wb'))
#モデルの保存
model.save('cnn.h5')
フォルダを見ると実際に保存されているのが確認できます!
その⑧:実際に予測をする
ここまできたら、実際に予測をしていきましょう。
保存したモデルとラベル、画像を読み込み、実際に画像を分類していきます。
画像を分類するプログラムはこちらです。
from keras.models import load_model
import pickle
import cv2
#モデルとクラス名の読み込み
model = load_model('cnn.h5')
classes = pickle.load(open('classes.sav', 'rb'))
#sample画像の前処理
img = cv2.imread('sample/sample.jpg')
img = cv2.resize(img,dsize=(224,224))
img = img.astype('float32')
img /= 255.0
img = img[None, ...]
img = cv2.imread('sample/sample.jpg')
cv2.imwrite('output/' + str(classes[pred])+ '/sample.jpg',img)
実行結果:
無事に、読み込んだ画像を犬と判断し、outputフォルダの中のdogフォルダに格納されることを確認できました。
複数枚の画像分類をしたいときはこのようにすればOKです!
from keras.models import load_model
import pickle
import cv2
import glob
#モデルとクラス名の読み込み
model = load_model('cnn.h5')
classes = pickle.load(open('classes.sav', 'rb'))
#sample画像の前処理
files = glob.glob('sample/*')
box = []
for file in files:
img = cv2.imread(file)
img = cv2.resize(img,dsize=(224,224))
img = img.astype('float32')
img /= 255.0
img = img[None, ...]
result = model.predict(img)
#確率が一番大きいクラス
pred = result.argmax()
img = cv2.imread(file)
cv2.imwrite('output/' + str(classes[pred]) + '/' + file,img)
画像分類の結果を書き込むこともできる
OpenCVを使って、分類した結果を画像内に書き込むこともできます。
import cv2 as cv
#確率が一番大きいクラス
pred = result.argmax()
img = cv.imread('sample/sample.jpg')
cv.putText(img,classes[pred] + ' ' + str(result[0][pred] * 100) + '%' ,(0,50), cv.FONT_HERSHEY_PLAIN, 4, (255,255,255), 5, cv.LINE_AA)
cv.imwrite('output/sample_.jpg',img)
最後に:自分の労力を減らしていこう
Pythonを使って画像分類の機械学習をする方法を解説してきました。
今回のサンプルプログラムのように、1枚の画像分類であれば手動でも良いですが、これが100万枚になったら、想像を絶するコストと労力、時間がかかってしまいます。
機械学習は、そんな苦痛から人間を救うためのありがたいツールなのかもしれませんね。
すこし宗教染みたことを言ってしまいましたが、要は「人間よりも早くて正確な機械に丸投げしてのんびりしましょ」ということです。
というわけで、これからもめんどうな作業を減らせるようにコツコツとプログラムを書いていこうと思います。
この記事が少しでも役に立っていたらうれしいです!
それでは!
最短1分でできる!
コメント
大半参考になりました!
よければ大量の画像を分類するときの変更点も教えていただきたいです。
自分でやってみましたがうまく行きません…。
さとうさん
大量の画像を分類するときの変更点を追加しました!
記事の通りに行うのであればdogフォルダとcatフォルダのそれぞれにsampleフォルダを作成すると、自動で画像が格納されていきます。
パスはさとうさんの環境に合わせて変更していただけたらと思います。
コメントありがとうございました!