メインコンテンツまでスキップ

100均のキッチンばかりで異常検知(成功編)

· 約6分
moritalous
お知らせ

過去にQiitaに投稿した内容のアーカイブです。

前回 は失敗してしまいましたが、試行錯誤の上、上手く識別できるようになりました。 試行錯誤の軌跡を残します。

今回もこれ! 68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f34313537342f37326136333766332d653430372d356363342d643166302d3633393963396131316138632e706e67.png

画像の水増し

前回使用した画像は全部で400枚(正常200枚、異常200枚)でした。画像が少なすぎるのかと思い、画像を増やすことにしました。Kerasに便利な機能がありました。

自前のDeep Learning用のデータセットを拡張して水増しする https://qiita.com/halspring/items/7692504afcba97ece249

画像の前処理 - Keras Documentation https://keras.io/ja/preprocessing/image/

参考にしたサイトほぼそのままですが、今回のキッチンばかりの場合、画像の角度が重要だと考え、画像の回転はしないようにしました。

パラメーター設定値
rotation_rangeコメントアウト
horizontal_flipFalse
vertical_flipFalse
    # 拡張する際の設定
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枚)にすることができました。

スクリーンショット (298).png

モデルのパラメーターの変更

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のメモリで動作するって、すごいことなのでしょうね。

予測

画像結果
1.jpg[[9.9999988e-01 1.2415921e-07]]
200g以下!

正解!
2.jpg[[1.0000000e+00 5.4107854e-08]]
200g以下!

正解!
3.jpg[[8.696176e-06 9.999913e-01]]
200g以上

正解!
4.jpg[[7.8308704e-10 1.0000000e+00]]
200g以上!

正解!
5.jpg[[4.8343203e-08 1.0000000e+00]]
200g以上!

正解!
6.jpg[[1.0000000e+00 1.5057713e-08]]
200g以下!

不正解!
(キッチンばかりの裏側)
想定外の画像のときってどうすればいいんだろう

予測のソース

## 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で通知したら、なんか、やったった感。

スクリーンショット (300).png

PythonからLINE NotifyでLINEにメッセージを送る https://qiita.com/tadaken3/items/0998c18df11d4a1c7427