Python

【コピペOKです】機械学習で画像分類する方法【Pythonで気軽に体験できます】

【コピペOKです】機械学習で画像分類する方法【Pythonで気軽に体験できます】
スポンサーリンク

こんにちは、さすを(@sasuwo0409)です。

いきなりですが、

今話題のPythonで機械学習をしてみたい!

機械学習を手軽に体験してみたい!

自動で画像を分類したい!

と思ってはいませんか?

今回の記事は、Pythonを使って、画像分類の機械学習をする方法を解説していきます。

サンプルコードも載せているので、実際に試してみることも可能です。

それでは本文をどうぞ。

困っている人
困っている人

機械学習で画像分類をしてみたいけど、やり方がわからなくて困ってる。

手順をサンプルコードを見ながら教えて欲しいな。

さすを
さすを

この悩みを解決します!

この記事を読むとわかること:

Pythonの機械学習で画像分類をする方法

筆者の情報:

  • 現役システムエンジニア 兼 ブロガー
  • 過去に6,000万のPython案件を受注
  • 最近ハマっていることは機械学習

※0円のサンプルテキストという近道

独学よりプログラミングスクールの方が効果は出やすいですが、値段が高く、なかなか手を出しづらいですよね。techgymでは無料のサンプルテキストと解説動画をもらえるので、これを使ってお得にPythonの基礎を学ぶのもオススメです。

スポンサーリンク

機械学習で画像分類する方法【Python】

機械学習で画像分類する方法【Python】

機械学習で画像分類する手順は、以下の通りです。

  1. 画像を格納するフォルダを作成する
  2. 学習する画像を集める
  3. ドライブの準備をする
  4. 画像の前処理をする
  5. 学習モデルの準備をする
  6. 学習及び精度の確認をする
  7. モデルとラベルを保存する
  8. 実際に予測をする

なお、今回は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」という名前で犬の画像を格納しています。

図1:分類するサンプル画像(sample.jpg)
図1:分類するサンプル画像(sample.jpg)

この記事の最終的なゴールは、読み込んだ画像を犬と判断し、outputフォルダの中のdogフォルダに格納されることです。

フォルダ構成を変更してもOKですが、後述するプログラムの保存先フォルダ名が変わるので注意してください。

さすを
さすを

分類したい画像は何でもOKです!

その②:学習する画像を集める

機械学習をするためには、学習する画像を大量に集める必要があります。

ここで集める画像が多ければ多いほど、機械学習の精度が上がるので、学習させる画像をどんどん「deep_learning」フォルダ下に追加していきましょう。

なお、自動で画像を集める方法は「【コピペOKです】Pythonを使って自動でGoogle画像を収集する方法を徹底解説!」で解説しているので、これから画像を準備する方は参考にしてみてください。

欲しい画像を自動で何百枚も集めることができるので、効率よく機械学習を進めることができます。

その③:ドライブの準備をする

画像を集め終わったら、ドライブの準備を行います。

今回は深層学習で計算していくので、ランタイムは、計算速度の速いGPUで行いましょう。

Google Colaboratory上で「ランタイム」「ランタイムのタイプを変更」の順にクリックし、「ハードウェア アクセラレータ」GPUに変更すればOKです。

図2:ランタイムの変更
図2:ランタイムの変更

ランタイムが変更できたら、ドライブをマウントし、カレントディレクトリを移動します。

#ドライブをマウントする
from google.colab import drive
drive.mount('/content/drive')

補足:
上記のコマンドを実行すると、以下の画面が現れます。手順通りに操作すればOKです。

1.URLを押下する。

図3:マウントの手順①
図3:マウントの手順①

2.希望のアカウントを選択する。

図4:マウントの手順②
図4:マウントの手順②

3.ログインを押下する。

図5:マウントの手順③
図5:マウントの手順③

4.コードをコピーし、「Enter your authorization code」に入力する。

図6:マウントの手順④
図6:マウントの手順④
#カレントディレクトリに移動
%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)
  • (218,224,224,3) → 学習データが218枚ということ
  • (55,224,224,3) → テストデータが55枚ということ
  • (218,2) → 218枚の学習データが犬か猫かの2種類ということ
  • (55,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()

VGG16:
「ImageNet」と呼ばれる大規模画像データセットで学習された、16層からなるCNNモデルのこと。有名な学習済みモデルの1つ。

図7:VGG16とは何ですか?—VGG16の概要
図7:VGG16とは何ですか?—VGG16の概要

今回の実装では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
  • Total params:トレーニングできるすべての数
  • Trainable params:トレーニングする数
  • Non-trainable params:トレーニングしない数(最初の15層)
さすを
さすを

後ろの5層を足すと Trainable paramの数になります!

その⑥:学習及び精度の確認をする

学習モデルの準備が終わったら、学習及び精度を確認していきましょう。

学習及び精度を確認するプログラムはこちらです。

#学習データで学習
model.fit(X_train, Y_train, epochs=20, batch_size=16)

#テストデータで精度確認
score = model.evaluate(X_test, Y_test, batch_size=16)
  • epochs:学習を何回繰り返すか設定する項目
  • batch_size:計算するときに使用するトレーニング例の数(少ないと精度が落ち、多いと時間がかかってしまう)
#出力結果
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
  • loss:損失関数の評価値
  • accracy:学習させたときの正答率

出力結果を見ると、学習回数が増えるほど、正答率である「accracy」が上がっていることがわかります。

そして、最後の2行は、学習していない画像を実際に分類させたときの正答率です。

つまり、この出力結果からは、学習データを20周させたときの画像分類の正答率は100%、テストデータの画像分類の正答率は92.73%ということがわかります。

さすを
さすを

学習していたデータに比べると、テストデータの精度は落ちることが多いです!

その⑦:モデルとラベルを保存する

学習及び精度の確認が終わったら、モデルとラベルを保存します。

ここには機械学習済みのデータが残っているので、これから予測するときは、このファイルを読み込むだけでできるようになります。

import pickle
#クラス名の保存
pickle.dump(classes, open('classes.sav', 'wb'))
#モデルの保存
model.save('cnn.h5')
さすを
さすを

フォルダを見ると実際に保存されているのが確認できます!

図8:クラスとモデルの保存
図8:クラスとモデルの保存

その⑧:実際に予測をする

ここまできたら、実際に予測をしていきましょう。

保存したモデルとラベル、画像を読み込み、実際に画像を分類していきます。

画像を分類するプログラムはこちらです。

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)

実行結果:

図9:画像分類の結果
図9:画像分類の結果

無事に、読み込んだ画像を犬と判断し、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)
図10:分類結果を追記した画像
図10:分類結果を追記した画像

最後に:自分の労力を減らしていこう

Pythonを使って画像分類の機械学習をする方法を解説してきました。

今回のサンプルプログラムのように、1枚の画像分類であれば手動でも良いですが、これが100万枚になったら、想像を絶するコストと労力、時間がかかってしまいます。

機械学習は、そんな苦痛から人間を救うためのありがたいツールなのかもしれませんね。

すこし宗教染みたことを言ってしまいましたが、要は「人間よりも早くて正確な機械に丸投げしてのんびりしましょ」ということです。

というわけで、これからもめんどうな作業を減らせるようにコツコツとプログラムを書いていこうと思います。

この記事が少しでも役に立っていたらうれしいです!

それでは!

参考にした動画:Pythonでサクッと画像分類して見んべよ【GoogleColab】

コメント

  1. さとう より:

    大半参考になりました!
    よければ大量の画像を分類するときの変更点も教えていただきたいです。
    自分でやってみましたがうまく行きません…。

    • さすを より:

      さとうさん
      大量の画像を分類するときの変更点を追加しました!
      記事の通りに行うのであればdogフォルダとcatフォルダのそれぞれにsampleフォルダを作成すると、自動で画像が格納されていきます。

      パスはさとうさんの環境に合わせて変更していただけたらと思います。

      コメントありがとうございました!

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