前回 は失敗してしまいましたが、試行錯誤の上、上手く識別できるようになりました。
試行錯誤の軌跡を残します。
画像の水増し
前回使用した画像は全部で400枚(正常200枚、異常200枚)でした。画像が少なすぎるのかと思い、画像を増やすことにしました。Kerasに便利な機能がありました。
自前のDeep Learning用のデータセットを拡張して水増しする
https://qiita.com/halspring/items/7692504afcba97ece249
画像の前処理 - Keras Documentation
https://keras.io/ja/preprocessing/image/
参考にしたサイトほぼそのままですが、今回のキッチンばかりの場合、画像の角度が重要だと考え、画像の回転はしないようにしました。
パラメーター | 設定値 |
---|---|
rotation_range | コメントアウト |
horizontal_flip | False |
vertical_flip | False |
# 拡張する際の設定
generator = ImageDataGenerator(
# rotation_range=90, # 90°まで回転
width_shift_range=0.1, # 水平方向にランダムでシフト
height_shift_range=0.1, # 垂直方向にランダムでシフト
channel_shift_range=50.0, # 色調をランダム変更
shear_range=0.39, # 斜め方向(pi/8まで)に引っ張る
horizontal_flip=False, # 垂直方向にランダムで反転
vertical_flip=False # 水平方向にランダムで反転
)
この方法で画像を10倍の4000枚(正常2000枚、異常2000枚)にすることができました。
モデルのパラメーターの変更
Kerasのドキュメントを眺めて、今回の問題は「イヌ」「ネコ」「ゾウ」のように複数に分けるのではなく、「正常値」「異常値」の2つに分類するだけの問題だと気づきました。
Sequentialモデルのガイド - Keras Documentation
https://keras.io/ja/getting-started/sequential-model-guide/
# マルチクラス分類問題の場合
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
# 2値分類問題の場合
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['accuracy'])
# 前回のコード(参考元のコピペです)
model.compile(loss='categorical_crossentropy',
optimizer='SGD',
metrics=['accuracy'])
真ん中の「2値分類問題」のコードに変更しました。
optimizerの意味は勉強します。
Optimizer : 深層学習における勾配法について
https://qiita.com/tokkuman/items/1944c00415d129ca0ee9
画像のグレースケール化
水増しした画像を見たときに、今回の問題は色情報は関係ないと思いました。
これもKerasで簡単にできました。(すごいね、Keras!!)
img = img_to_array(load_img(picture, target_size=(224,224), grayscale=True))
グレースケールにすることで、色情報がRGBの3から1になるので、input_shape
を追加で指定する必要があります。(指定なしだと3扱いなのかな?)
model = MobileNet(include_top=True, weights=None, classes=2,input_shape=(224, 224, 1))
モデルの変更(今回は不採用)
モデルを変えると結果も変わるのかなと思って試したのですが、Raspberry Pi Zeroで予測させようとすると、メモリ不足で動作させることができませんでした。感覚がわかりませんが、Raspberry Pi Zeroの512MBのメモリで動作するって、すごいことなのでしょうね。
予測
予測のソース
# coding:utf-8
from time import sleep
from keras.applications import mobilenet
from keras.models import load_model
from keras.preprocessing import image
from keras.preprocessing.image import img_to_array, load_img
import numpy as np
from keras.utils import np_utils
model = load_model('0212_my_model_0216.h5', custom_objects={
'relu6': mobilenet.relu6,
'DepthwiseConv2D': mobilenet.DepthwiseConv2D})
while True:
X = []
picture = '/home/pi/motion/capture/lastsnap.jpg'
img = img_to_array(load_img(picture, target_size=(224, 224), grayscale=True))
X.append(img)
X = np.asarray(X)
X = X.astype('float32')
X = X / 255.0
features = model.predict(X)
print(features)
if features[0][0] > features[0][1]:
print('200g以下!')
else:
print('200g以上!')
sleep(5)
終わりに
なんとか上手く分類させることができました。
ただ、閾値を200gから300gに変えたくなったらもう一回学習させないといけないのかな?
「マルチクラス分類」にすればいいのかな?
おまけ
予測に使った画像と予測結果をLINE Notifyで通知したら、なんか、やったった感。
PythonからLINE NotifyでLINEにメッセージを送る
https://qiita.com/tadaken3/items/0998c18df11d4a1c7427