はじめに
こんにちは。技術開発チームの矢澤です。
このブログの読者の中には、昨今の情勢を受けて自宅などで業務を行っている社会人の方も多いと思います。 今後ますます在宅勤務が普及していくと、Zoomを使ったリモート会議のように、仕事の形や自宅での過ごし方が大きく変わってくるのではないでしょうか。
業務のリモート化については、色々と課題や賛否があるかもしれませんが、在宅勤務のメリットの一つとして、これまでオフィスにいる時にはできなかったような家でのことを行えるということがあると思います。 例えば、お子さんがいる方は子供の面倒を見たり、あるいは宅配便の受け取りや細かな家事などを業務の合間に行う方もいるかもしれません。
そこで今回は、在宅勤務中に役立つツールとして、Laundry Monitor(洗濯物監視カメラ)を開発してみました。 M5StickVというカメラデバイスでベランダなどに干してある洗濯物を監視し、洗濯物が落下したら音で知らせてくれるというものです。 これによって、仕事中に風で洗濯物が落ちても、すぐに気付いて掛け直すことができるようになります。
それでは、さっそく開発方法を説明していきたいと思います。
M5StickVについて
はじめに、今回使用するカメラデバイス「M5StickV」について簡単に紹介します。
M5StickVは、スイッチサイエンス社が開発しているIoTデバイスの一つで、M5Stickというデバイスのカメラ付き版です。 デュアルコアのCPUに加えて、ニューラルネットワーク用のプロセッサ(KPU)が内蔵されているため、高速・高性能な画像処理を行うことができます。 M5シリーズには他にも、基本的な開発モジュールの「M5Stack」やカメラの無い「M5Stick」、あるいは機能拡張用の専用モジュールなどがあり、目的に応じて使い分けることができるようになっています。
M5StickVには初めから顔検出用のプログラムが内蔵されているため、そのままでも遊ぶことができますが、 SDカードにプログラムを入れて使用することで、自分の好きなモデルを動かすこともできます。 また、液晶ディスプレイやスピーカー、3つのボタンも付いているので、簡単な機能であれば外部のモジュールなどに接続しなくても実現できます。
開発方法
ここからは、実際にLaundry Monitorの開発の流れを説明します。 具体的には、洗濯物判定のモデルをあらかじめ学習し、学習済みのモデルと判定用のソースコードをSDカードに入れることで、M5StickVで動かせるようにします。
洗濯物の落下判定については、画像分類(CNNなど)を使った方法と物体検出(SSDなど)を使った方法の2通りが考えられます。 画像分類では、洗濯物が落ちている(わざと落とした)画像と落ちていない画像をそれぞれ集めて、両者を2値分類するモデルを学習します。 一方、物体検出はファッションデータセットなどを使って画像中の服の有無(と位置)を判定できるようにし、画面中に服が見つかった場合は落下とみなすという方法です。 今回は、学習のしやすさ(後述するV-Trainingを使用可能)や、判定の難易度(綺麗に映ったファッションデータで学習したモデルを使って、地面に落ちている洗濯物を服とみなすのは難しい)を踏まえ、前者の画像分類を使った方法を採用しています。
スマートフォンなどで画像を撮影し、開発用のマシンで画像分類モデルを学習してデプロイしても良いのですが、 M5StickVには画像の収集からモデルの学習・検証、判定プログラムの実装までを、一貫して行うことができる「V-Training」というツールが公式で用意されているため、今回はそちらを使用しました。
学習データの収集
上記の画像分類モデルを学習するために、洗濯物の写真を集める必要があります。 画像収集用のプログラムは、上記のV-Trainingのチュートリアルの「boot code」にあります。
zipファイルをダウンロードし、解凍してSDカードにコピーします。 このとき注意点として、M5StickVではSDカードの選択がかなりシビアなようで、相性の悪いSDカードを使用するとうまく認識してくれないようです (自分の場合は、たまたま自宅にあったSDカードで動きました)。
SDカードをM5StickVに挿入し、USBケーブルでPCから電源供給して起動(すでに起動済みの場合は電源ボタンを長押しして再起動)すると、画像を撮影するためのプログラムが開始されます。 撮影画面では、左上に撮影済みの画像枚数が表示され、右上では現在撮影中のクラス番号が分かります。 電源ボタン以外の2つのボタンを使って、画像の撮影とクラスの切り替えをそれぞれ行うことができます。
画像枚数は「**/35」となっていますが、これは学習に必要な画像の最低枚数が1クラス35枚ということであって、35枚以上撮影することもできます。
※ 後で判明してやり直したのですが、学習画像は全部で90枚以上必要であり、今回は2クラス分類であるため、1クラス当たり45枚は用意しなければなりません。 さらに、撮影した画像は自動的に学習用と検証用に分けられるため、検証用データの分も合わせると、1つのクラスにつき最低50枚は撮影する必要があります。
撮影が完了したら、SDカードを抜いてPCなどに挿し、今集めた画像を確認します。 trainとvaild(validのスペルミスだと思います)というディレクトリが作られており、さらにその中にクラスごとに分かれて画像が格納されています。 所属クラスを間違えて撮影してしまった場合なども、画像を手動で移動して修正することが可能です。
モデルの学習
画像を用意できたら、モデルの学習を行います。 手順は簡単で、先ほどの学習・検証用のディレクトリをまとめて圧縮し(学習データだけではダメなので注意)、以下のV-Trainingのページから入力するだけです。
学習後のモデルを送信したいメールアドレスを入力し、上記の画像データをドラッグ&ドロップします。 Statusの欄が黄色字で「Uploading (xx%)」となり、その後緑色の「Finished」となれば投入成功です。 数時間後ほど待つと(時間帯などによってまちまちのようです)、先ほどのアドレスにメールが届きます。
データの形式などに問題がなければ、学習結果とモデルが送付されますが、何かしら問題があるとエラーメッセージが送られてきます。 以下は、自分が失敗した際のエラー内容と詳細です。
- Train or Valid folder not found. If you are using the M5StickV software, make sure you reach enough image counts of 35 per class.
画像データは1クラスあたり35枚以上必要なため、規定枚数に達していないとエラーになります。
- Lake of Enough Train Dataset, Only ** pictures found, but you need 90 in total.
各クラスの画像が35枚以上であっても、全クラス合わせて90枚以上無いと学習することができません。
- Unexpcted error happened during training. Err: Unable to create file (unable to open file: name = 'trained_h5_file/e8f612f508db061e_mbnet10.h5', errno = 2, error message = 'No such file or directory', flags = 13, o_flags = 242)
正確な原因は分かっていないのですが、同じユーザーが連続してモデルを作成しようとすると、内部で不整合が起こりエラーとなる場合があるようです(違うPCからデータを投入したら、上記のエラーが出なくなりました)。
無事に学習できた場合は、学習結果としてモデルの精度と損失の推移を確認できます。 グラフを見ると、Validation Lossが24エポック目辺りで急激に増えているので、過学習してしまっている感じがありますが、今回は学習データ数がそもそも少ないのでやむを得ないと思います。 また、洗濯物なしの画像には影が映ってしまっているため、それが学習に悪影響を与えているのかもしれません。
学習後のモデルは、メールに記載されたURLからzipファイルとしてダウンロードできます。 また、メール本文に「Model: Classification MobileNetV1 Alpha: 0.7 Depth: 1」とあるので、CNNのネットワークとしてMobileNet V1を使用しているようです。
モデルのデプロイ
モデルが学習できたので、いよいよM5StickVにデプロイします。 上記のzipファイルを解凍し、そのままSDカードにコピーしてM5StickVに挿入します。
M5StickVを再起動すると、先ほどのモデルを使った画像分類プログラムが実行されます。 つまり、これだけで洗濯物の有無を判定するツールが開発できたことになります!
実際にベランダで撮影してみると、洗濯物が画面に写っている場合はクラス1(洗濯物あり)、ない場合はクラス2(洗濯物なし)と、ほぼ正しく予測されることが確認できました。
通知機能の実装
上記のプログラムでは、単に予測クラスを画面に表示するだけなので、洗濯物を検出したら音が鳴るようにソースコードを変更します。 具体的には、判定部分を以下のように書き換えて再度デプロイしました。
DETECTION_THRESHOLD = 10 INTERVAL_TIME = 1 detection_count = 0 while(True): img = sensor.snapshot() fmap = kpu.forward(task, img) plist=fmap[:] pmax=max(plist) max_index=plist.index(pmax) a = lcd.display(img) if pmax > 0.95: max_label = labels[max_index] lcd.draw_string(40, 60, "Accu:%.2f Type:%s"%(pmax, max_label)) if max_label == '1': detection_count += 1 elif max_label == '2': detection_count = 0 # 洗濯物が一定回数以上連続して検出されたら通知する if detection_count == DETECTION_THRESHOLD: lcd.draw_string(40, 60, "Laundry dropped!") # SDカード内のファイルを読み込んで通知音を鳴らす play_sound('/sd/detection_sound.wav') detection_count = 0 # 1回の判定ごとに一定時間待機する time.sleep(INTERVAL_TIME)
誤判定の可能性があるため、「洗濯物あり」と一定回数以上(上記では10回)連続して判定されたら、音が鳴るようにしました。 また元のプログラムでは、Whileループで常に画像分類を行うようになっていましたが、電池の節約のため1回判定するごとに一定時間(1秒)スリープするようにしています。
音声再生用の関数(play_sound)は、画像撮影用のプログラムからコピーしました。 通知音のwavファイル(detection_sound.wav)は、独自に用意してSDカードの中に入れておきます。
以上で、Laundry Monitorの開発は完了です。 あとは、ベランダに設置して雨除けなどを作れば、洗濯物の監視を実現できます。
おわりに
今回はM5StickVというカメラ付きデバイスを使用して、落下した洗濯物を検出するツールを開発しました。
途中で説明したように、洗濯物の有無の判定は画像分類モデルではなく、SSDのような物体検出モデルを使用して実現することもできます。 また、今回は学習を簡単に行うためにV-Trainingを活用しましたが、TensorFlowなどで独自に作成したモデルのデプロイも可能です。 その場合、複雑なネットワークをM5StickV上で動かすためには、TensorFlow Liteのような軽量なモデルに変換する必要が出てきます。 今後は、そのような方法を使った検出精度の向上にも挑戦してみたいです。