見出し画像

python:機械学習で梨と林檎を分類する

梨と林檎の画像を機械に分類してもらいます。こちらの記事を参考にしました。


学習用の画像とテスト用の画像を準備する

キャプチャ

キャプチャ

Googleから梨と林檎を検索して、適当に画像をダウンロードして、フォルダに入れ込みます。

C:\Users\user\Desktop\train\学習用りんご画像

C:\Users\user\Desktop\train\学習用梨画像

C:\Users\user\Desktop\test\テスト用りんご画像

C:\Users\user\Desktop\test\テスト用梨画像

( 学習用は15枚、テスト用は5枚 ) * 2セット を用意しました。

必要ライブラリをインポート

from keras.models import Sequential
from keras.layers import Activation, Dense, Dropout
from keras.utils.np_utils import to_categorical
from keras.optimizers import Adagrad
from keras.optimizers import Adam
import numpy as np
from PIL import Image
import os

学習用のリストを作成

image_list = []
label_list = []

学習用画像を読み込む①

for dir in os.listdir("C:/Users/user/Desktop/train"):
   dir1 = "C:/Users/user/Desktop/train/" + dir 
   label = 0
   
   if dir == "学習用りんご画像":
       label = 0
   elif dir == "学習用梨画像":
       label = 1

os.listdir("パス") でパス内のディレクトリ名が取得できます。

キャプチャ

学習用画像を読み込む②

for file in os.listdir(dir1):

   #1
   label_list.append(label)
   filepath = dir1 + "/" + file

   #2
   image = np.array(Image.open(filepath).resize((25, 25)))

   #3
   image = image.transpose(2, 0, 1)
   
   #4
   image = image.reshape(1, image.shape[0] * image.shape[1] * image.shape[2]).astype("float32")[0]
  
   #5
   image_list.append(image / 255.)

#1

配列label_listに正解ラベルを追加します。そして、各ファイルのパスをfilepathに設定します。

#2

それぞれのファイルを開き、25*25ピクセルのサイズにリサイズします。そして、np配列にします。1要素が[R,G,B]3要素を含む配列の25x25の2次元配列となります。RGBは0から255で構成されます。

※たとえば、赤色だと、R:255 G:0 B:0

RGBのセットが各ピクセルにセットされるのでこの3セットが25*25のセット生成されます。

キャプチャ

#3

transposeで軸変換を行い、[R],[G],[B]という配列から、[R, G, B]というような配列に変換する。

ex)イメージ

キャプチャ

#4

1次元配列に変換

ex)イメージ

キャプチャ

#5

RGBは0-255の数字で記載されているので0-1の数値に直すため、255で割って、リストに格納

numpy配列に変換


image_list = np.array(image_list)

kerasに渡すためにはnumpy配列に変換する必要があります。

ラベルの配列を1と0からなるラベル配列に変更


Y = to_categorical(label_list)

ex)イメージ

キャプチャ

要素数ごとにカテゴリを分けて、要素に当てはまる箇所を0か1で分別する

モデルを生成してニューラルネットを構築

#1
model = Sequential()

#2
model.add(Dense(200, input_dim=1875))
model.add(Activation("relu"))
model.add(Dropout(0.2))

#3
model.add(Dense(200))
model.add(Activation("relu"))
model.add(Dropout(0.2))

#4
model.add(Dense(2))
model.add(Activation("softmax"))

1875 - 200 - 200 - 2 の3層のニューラルネットワークを作る

#1

Sequentialモデルを使用。Sequentialモデルはレイヤを順に重ねたモデル

キャプチャ


#2,3

Denseはユニット。上記の図でいう黄色の〇。2個目の層のユニットを200個を設定。input_dimは入力数です。今回は1,875を設定。活性化関数はrelu関数を使用します。

※relu関数は、入力した値が0以下のとき0。1より大きいとき入力をそのまま出力するような関数です。

Dropoutは、過学習を防ぐために1 つ前のレイヤーのノードのうち、指定した割合のノードをランダムに選んで出力を 0 にする。

#4

最後の出力層はDenseを2に設定。活性化関数は出力層で使われる関数ソフトマックス関数を使用。簡単に言うと、最終的な結果をパーセンテージで返すようなもの。

オプティマイザの設定


opt = Adam()

効率よく、目的を達成するために最適化を行います。アルゴリズムはAdamを使用。

Adamは、AdaGradやRMSProp、SGDなどと同様にニューラルネットワークの学習において、よく使われる最適化手法の一つです。最適化の手法は世の中にたくさん提案がされており、ニューラルネットワークのパラメータの最適化に関しては入力変数と出力変数の間に起こりうるパターンを見つけ出し、予測精度が最大になるような重みパラメータをどう見つけるかという問題になります。


モデルをコンパイル


model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"])

学習を行うためにモデルをコンパイルします。

損失関数は、categorical_crossentropy を使用。ラベルがone-hot エンコーディングで表現されている場合は、損失関数としてcategorical_crossentropy を使用します。

損失関数は予測と実際の値のズレの大きさを表す関数でモデルの予測精度を評価します。損失関数の値が小さければより正確なモデルと言えます。

https://to-kei.net/neural-network/nn_loss_function/


オプティマイザは、先ほどのAdamを設定。

metrics(評価指標)は、accuracy(正解率)を設定。


学習を実行


model.fit(image_list, Y, nb_epoch=1500, batch_size=100, validation_split=0.1)

引数は、学習リスト、ラベルリスト、繰り返し回数、1度に処理する回数、評価部分の割合

実行すると、下記のように Train on 13 samples , validate on 2 samplesで15枚の内、13枚で学習。2枚で評価というような形となっています。

キャプチャ

結果検証のためのリスト作成

total = 0.
ok_count = 0.

テスト画像で機械に予測してもらう

for dir in os.listdir("C:/Users/user/Desktop/test"):
   dir1 = "C:/Users/user/Desktop/test/" + dir 
   label = 0
   if dir == "テスト用りんご画像":
       label = 0
   elif dir == "テスト用梨画像":
       label = 1
   for file in os.listdir(dir1):
       label_list.append(label)
       filepath = dir1 + "/" + file
       image = np.array(Image.open(filepath).resize((25, 25)))
       print(filepath)
       image = image.transpose(2, 0, 1)
       image = image.reshape(1, image.shape[0] * image.shape[1] * image.shape[2]).astype("float32")[0]
       result = model.predict_classes(np.array([image / 255.]))
       print("label:", label, "result:", result[0])
       total += 1.
       if label == result[0]:
           ok_count += 1.
print("正解率: ", ok_count / total * 100, "%")

キャプチャ

1つだけ間違えました。

C:/Users/user/Desktop/test/テスト用りんご画像/ダウンロード (13).jpg

キャプチャ

機械はこれを梨だと思ったようです…それはそれで正解だな…


過去記事


この記事が気に入ったらサポートをしてみませんか?