GCP AutoML Vision で鍵かけ忘れを防ぐ仕組みを作る

f:id:r_kurain:20191016200356g:plain
slack にカギの開閉が通知される様子
玄関ドアのカギが開いた時、閉じたときに slack に通知が来る仕組みを作りました。今のところうまく運用できていて、外出後にカギが不安になって玄関まで戻ってくることがなくなりQoLがあがった感があります。

この仕組はドアの画像から閉じたサムターンを検出することで実現しています。Raspbeery Pi 3 で毎秒1画像くらいの処理ができるので、カギの通知としては問題ないレイテンシーです。

f:id:r_kurain:20191016200658g:plain
物体識別を可視化してみる

肝となる画像認識部分は GCP の AutoML Vision で学習させています。画像10枚で実用的な精度が出るDNNモデルが取得できる手軽さはなかなかすごいものがあります。 もちろんこんな簡単な画像認識なら、OpenCV を使ってテンプレートマッチングでも良いのでは? と思う向きもあるでしょう。実際その手法も試していて、頑張ってチューニングすればできそうな感触はありました。しかし AutoML Vision なら画像 10 枚を渡して、アノテーションするだけでチューニング不要で十分精度が出てしまうし、モデル作成から推論まで全部 WebUI でポチポチするだけでおわってしまうのです。学習には2時間くらいかかっているようですが、無料で計算できる範囲には収まっています。

コンピュータ資源を富豪的に使って、機械学習アプリケーションの PoC が簡単にできる。そのまま実運用まで持っていけるというのは、なかなか衝撃的な体験でした。 というわけで、以下は解説です。UIの遷移を説明するのがだるかったので AutoML Vision の使い方の説明はほとんどしていません。こちらの QuickStart どおりに動かすだけでモデルの取得ができます。

必要なもの

  • Raspberry Pi 3 (2とか zero でできるかは未検証です)
  • Raspberry Pi に接続できる赤外線カメラ
    • 僕がつかったのはこちら

しくみ

  • Raspberry Pi 3 に接続している赤外線カメラでサムターン(玄関鍵の手で回す部分)を含む写真を撮影
  • GCP AutoML Vision で'閉じてるサムターン' か '開いてるサムターン'を検出するモデルを作成
  • 作成したモデルを使って画像から'閉じてるサムターン'検出
  • '閉じてるサムターン'のスコアが閾値以上なら鍵が閉まっていると認識する
  • 前回の画像認識から状態が変化していれば slack に通知する

しくみの解説と構築手順

赤外線カメラによる撮影

なぜ普通のカメラではなく、赤外線カメラを使うのかというと玄関の照明を落としているときに帰宅したり、でかけたりという ことはよくあるので、玄関が暗い時でも画像認識が正しく動作してほしいからです。赤外線カメラとざっくり表現していますが、 赤外線LEDの照射機能がついていて、センサーに赤外線域を落とすフィルターが入っていないカメラを指しています。 今回は Raspberry Pi にフラットケーブルで接続するタイプのカメラを使っています。このカメラ、外光の明るさに応じて 照射する赤外線の光量を調整する機能がついています。外光に対して反応する量を可変抵抗で調整できるのですが、マニュアルが なく調整の仕方がよくわからないので現場合わせで適当に調整しました。外光が暗い時でも明るい時でも似たような明るさの写真が 撮影できればOKです。初期設定では外光が明るい日中にだいぶ白飛びしていたので、赤外線投射量が減る方向に調整しました。

カメラについてはUSB接続のものでも、あるいは wifi接続の監視カメラでも赤外線域で撮影できれば動作する可能性は高いと考えています。

GCP AutoML Vision で作るモデル

ここが今回のキモです。赤外線域で撮影した写真からサムターンを検出する機械学習モデルを作ります。 モデルを全部自前で設計する手もありますが、ここは手抜きしたいので、AutoML Vision に頼ります。 AutoML VisionGoogle が提供する機械学習のためのサービスで、画像識別と物体検出のモデルを簡単に作ることができます。今回は物体検出のモデルを利用します。

AutoML Vision の入力に必要な画像は、検出したい物体が写っている写真が最低10枚です。 今回は'閉まっているサムターン'と'開いているサムターン'を検出したいので、それぞれ10枚の計20枚を用意しました。

f:id:r_kurain:20191017202906p:plain
明るさが微妙に違うし、画角も微妙にずらしてある

明るさが異なる写真や、多少カメラの向きが変わった写真を用意しておくことで、汎化性能が高まることを多少期待しています。 '開いているサムターン'の検出はあとのフェーズでも実は使わないのですが、開いているサムターンを間違って閉じているサムターンと認識しないように、 違うものだと認識されることを期待して検出対象にいれています。不要なような気もしますが試していないのでわかりません。

教師データとなる写真のとり方ですが、cron で 10 分おきに写真を撮影するようにして 24 時間分写真をためます。 途中サムターンを開けておく時間を作ったりカメラの向きを少し動かしたりして、必要な写真が貯まるように仕込みます。 写真が溜まったところで、20枚の写真を選ぶと良いでしょう。

画像を用意したら、サムターンの場所を矩形で指定して、開いているのか閉まっているのかのラベルも付けます。 WebのUIでできますが、動作が緩慢で、あまり賢くもないので違うツールでラベル付けをして csv を upload するほうが楽かもしれません。

f:id:r_kurain:20191017203158p:plain
WebUI でアノテーションする様子

ここでのハマリポイントは、20枚画像をupすると、そのうち16枚を学習データ、2枚をハイパパラメータ検証データ, 2枚をテストデータに 分けてくれるのですが、アノテーションする前にその振り分けが行われるという点です。つまり、振り分けの運がわるいと、2枚のテストデータが 両方"閉じたサムターン"の方に入っていて、"開いたサムターン"データにテストデータが存在しないと怒られることがあります。 このようなときは、アノテーションが終わったあとに、一旦データセットアノテーションデータをCSVでダウンロードします。 ダウンロードしたCSVには矩形のラベルと、データの使いみちがTRAINING, VALIDATION, TESTの3つで示されているので、 それぞれのラベルにTRAININGが8つ, VALIDATIONが1つ, TESTが1つ有るように編集してあげます。 編集したファイルを upload してトレーニングデータとして AutoML Vision に認識させれば準備完了です。

レーニングを開始すれば2時間程度で学習が終わるはずです。

作成したモデルを使って raspberry pi 上で物体検出

AutoML Vision で作ったモデルはそのまま GCPクラウド上で運用することもできます。 しかし運用コストが安くはないので raspberry pi 上で物体検出まで行います。 作成したモデルは、Tensorflow の saved_model 形式か, tflite 形式でダウンロードできます。 tflite 形式のほうが軽量なモデルになっており、 raspberry pi での運用には向いているはずなのですが、 サンプル通りに動かしても正しく動作しないので、saved_model 形式を利用します。 概ね 1fps で検出できるので今回の用途には十分です。

動かしているコードと同等のサンプルを gist に置いておきます。

detecting thumbturn status · GitHub

Tensorflow(TF) の Raspberry Pi へのインストールについてはこちらを参考にしてください。 まだ TF v2.0 ではなく v1.4 です。サンプルコードもv1系を前提にしているので deprecation の warning が出ます。 (消したかったのですがとりあえず、問題なく動くので放置しています。)

識別ルール

カメラとサムターンの間に人が入って、検出がそもそもできない状況もあります。なので、閉まっているサムターンが 認識できるときは、カギが閉まっている、それ以外のときはカギが開いていると認識することにします。 このルールで状態が変化したときに、識別している状態(カギが掛かっている/開いている)を通知します。 通知するときに写真も添付しているので、誤検知があっても安心です。

また、家庭用 slack bot から signal (SIGHUP) を送ると、状態の変化に関係なくその時のドアの写真と状態を 通知してくれるので、出先でカギが不安になってもすぐに確認できます。

運用など

玄関に Raspberry Pi 3 とカメラを接続した状態で置いています。見た目がロボットぽいと子どもたちに好評なので ボディもつけてあげたいところです。

f:id:r_kurain:20191017210035j:plain

認識に使っている python スクリプトは gist にあげたものから多少変更していますがほぼ同じものです。supervisor でデーモン化しています。

検討したけど却下したもの

完成までには、M5 Stack と接近センサーや距離センサーを使った仕組みも試していて、正常に動作するところまでは確認できました。 そちらを採用しなかったのは、ドアの周りにセンサー類の配線がついてしまうのが微妙だったためです。 M5 Stack と 各種センサーの組み合わせのほうが省エネだし、よりレイテンシーも下がるのだけれど、Raspberry PiWebカメラの組み合わせのほうがお手軽感は格段に上です。

実際のところ最もお手軽なのは各種スマートロックをドアに付けてしまうことなのですが、インキーが怖いし、オートロック機能を使わないとしても家のカギを 第三者に預けるサービスは個人的な信条からちょっと利用したくないので今回は避けました。

おわりに

こういったものを作ろうと決めてからだとだいぶ時間がかかりましたが、機械学習モデルの作成部分だけなら特に悩むところがなくさすが Google のサービスだなーという感じでした。 一方でモデルを Raspberry Pi で動かすにあたっては tflite 形式だとうまく動かないとかハマリポイントもいくつかあり、こういったアプリケーションを簡単に動かせるようになるにはまだ少しハードルがあります。もうちょっと簡単にこういった仕組みが作れるアプリケーションがあっても良い気がするので気が向いたらつくろうかなあ。