【Custom Vision】アナログメータ(湿度計)の読み取り

Cognitive ServicesのCustom VisionでAdvanced Trainingを使ってアナログメータの読み取りをやってみたら思いのほかうまくいったのでまとめておこうと思います。

# Cognitive Serviceとは
[Cognitive Service](https://azure.microsoft.com/ja-jp/services/cognitive-services/)とは、機械学習等で必要となる専門的な知識があまりなくとも簡単に目的に沿ったモデルを作ったり、利用できたりするお手軽AI体験サービスです。今回はこのサービスの中の1つであるCustomVisionを使って画像分類をします。

# 作ったやつ
![0022.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/577b8b55-28bc-0c60-e593-f84bc6046d65.png)
結果としてはこんな感じです。

# 使ったもの
![DSC_0906.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/8e31826e-8040-a81d-3863-a1bd09959118.jpeg)
こんな感じの湿度計を使いました。ダイソーに行って買ってきました。

* 湿度計
* webカメラ
* Azureのアカウント
* Customvisionのリソース

とりあえず、これだけあればOKです。

# ざっくりとした手順

1. 写真を撮る(30分くらい)
2. アノテーション(6時間くらい)
3. Customvisionにアップロード(20分くらい)
4. 学習(1時間半くらい)

それぞれの作業では、かっこの中に書いたくらいの時間使いました。厳密に計測したわけではないのでおおよそです。
アノテーションはめんどくさくて中々手が動かなかったので3日くらいに分けて作業してます。

# 1.写真を撮る
最終的な画像のサイズは640 * 480 pxで、解像度は96pdiです。形式はjpgです。
この湿度計は2%刻みの目盛りなので、0～100%まで目盛りの数だけ画像を撮っていきます。これで51タグ分のデータができます。1タグ当たりトレーニング用に20枚、テスト用に10枚の計30枚取得していきます。ざっと1530枚の画像が必要です。

![DSC_0907.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/d85abbfb-0fb9-8ea5-a6b2-86122dd45845.jpeg)
分解するとこんな感じで、真ん中ところを回すと手動で目盛りを動かせます。黒いのはただのテープです。文字盤が接着されてなくて取れそうだったので手元にあった電子工作用の絶縁テープ貼っただけです。
1530枚もポチポチ写真撮っていくのはさすがに骨が折れるので、今回は動画を撮ってAfterEffectsを使ってJPGシーケンスとして出力しました。約3分くらいの動画で3000枚くらいの画像ができました。この辺りは工夫すればもっと簡単にやる方法があるんですかね？詳しい人教えてください。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">教師データ作成用。動画撮って1フレームごとに連番の画像として出力。<a href="https://t.co/zrYCAVagLj">https://t.co/zrYCAVagLj</a></p>&mdash; shota (@Shota7Y) <a href="https://twitter.com/Shota7Y/status/1141365072574332928?ref_src=twsrc%5Etfw">2019年6月19日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

こんな感じで作成できます。AfterEffectsの中で余分なところをトリミングしたり、グレースケールにしたりすると一石二鳥かもしれません。

# 2.アノテーション
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/963bd50b-bc9e-8fdb-c3d1-32f76817fc3d.png)

作成した3000枚の画像を1つ1つ目視で確認して、1%ごとにフォルダを分けていきます。実際には2%刻みのデータしか使いませんが、せっかく取得できたデータなので地道に頑張ってフォルダ分けしました。Deep Learningで一番めんどくさい作業ですね。
さすがに3000枚を確認していくのは面白くなくて結局3日に分けて、夜な夜なちょっとずつやってました。

# 3.Customvisionにアップロードする
## Azureでリソースを作る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/d82c40cd-bb47-0e1a-6c25-a5def8b7ee8a.png)
AzureでCustomvisionのリソースを作ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/a1e4522e-310c-1536-e5e1-301d66490664.png)

* 名前：適当に
* サブスクリプション：私の場合は従量課金
* 場所：東日本
* 予測価格レベル：F0(画像はS0になってますが無料枠がある人はF0で良いです)
* トレーニング価格レベル：予測価格レベルと同じ
* リソースグループ：なければ作る。

必要な項目を入力したら作成ボタンでリソースを作成してデプロイ完了まで待ちます。

## Customvisionでプロジェクトを作成
[Custom Vision Home](https://www.customvision.ai/)
ここにアクセスしてサインインします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/08d5febf-d787-740c-eee3-4afed82768a0.png)
NEW PROJECTから新しいプロジェクトを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/4a5dc1d2-1da2-ffda-35db-98672b4baf00.png)

* Name：適当に
* Description：プロジェクトの説明を記載(書かなくてもよい)
* Azureでリソース作成した際のリソースグループが表示されているのでそれを選択
* Project Types：Classification(画像分類なのでこれ。もう1つは物体検出用です)
* Classification Types：General(ほかに該当しない場合はこれを選ぶ。Compactはエクスポートしてスマホやラズパイのようなエッジで使いたい場合(オフライン利用も含めて)に選択)

こんな感じに入力して「Create Project」をクリック

## 画像をアップロードしていく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/b5ce964b-db3e-fff4-699b-a48e36484420.png)
画面左上の「Add images」から画像をアップロードしていく。
無料枠の場合、作成できるタグが50個までなので、今回は0～98%のデータを使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/8ce7ed01-0978-9377-3ea7-f3a0ca8e5dec.png)
%ごとにフォルダ分けしてるので、20枚まとめて選択して「開く」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/e4a15ff0-301d-86fb-dffa-3ae3c28fc7fd.png)
ここでタグを入力する。この画像はすべて0%なので「00」と入力してEnterキーで確定。2桁にそろえるために00と入力しているが0でもよいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/52e2b839-8031-dfa3-352a-f881c4c1c466.png)
タグが入力できていることを確認して「Upload files」をクリック。アップロードが完了したら「Done」で完了。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/99e741de-55fd-9992-1a2a-1024f6e0d605.png)
同じ手順でどんどん画像をアップロードしていきます。

![eeror.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/bde79f18-069e-0b6f-3379-52cec713956d.png)
途中でこのエラーが出た場合は、画面左側のチェックボックスを外してください。ここが20を超えるとエラーが出ます。アップロードに失敗しているわけではないのでそこは安心して大丈夫です。

# 4.学習させる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/3ea62055-7b60-702a-f22d-c3224568ac5b.png)
画像がアップロード出来たら画面右上の緑の「Train」ボタンをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/7d18a605-d8b1-f28a-b707-5b1da17dec01.png)
「Fast Training」を選択して「Train」ボタンをクリック。これで1～2分くらいで学習が完了しますので終わるのを待ちます。
「Advanced Training」は後から触れますので今は飛ばします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/901c53d0-9b1a-5ae1-1e96-d00da7821d05.png)
画像分類機ができました。今回の学習結果がこれです。正直よくないです。

* Precision(精度)：正しかったと識別された分類の割合を示します。 たとえばあるモデルで、100 個の画像が犬として識別され、それらのうち 99 個が実際に犬であった場合、精度は 99% になります。
* Recall(再現率)：正しく識別された実際の分類の割合を示します。 たとえば、実際にりんごである画像が 100 個あり、そのモデルで、80 個がりんごとして識別された場合、再現率は 80% になります。
* AP(Average Precision)：閾値によって計算されたPrecisionの平均値。

※APは最近追加されたもので私も精度の平均くらいの認識しかないので、詳しい人がいれば教えてください。
　一応[Using the Custom Vision Service to Perform Image Classification](https://github.com/microsoft/computerscience/blob/master/Labs/AI%20and%20Machine%20Learning/Custom%20Vision%20Service/Custom%20Vision%20Service.md)を見てなんとなくわかったようなわかってないようなという感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/570df9b9-466e-b831-978b-d8fa9e461d6e.png)
右上にあるこのスライダーは閾値で、左にスライドさせると値が小さくなり、右にスライドさせると値が大きくなります。これでPrecisionとRecallを調整できます。

|  区分  | 閾値との関係 | 閾値を上げたらどうなるか |
|:-:|:-:|:-:|
| Precision &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; | 閾値を上げると上がる &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;| 間違って分類されるものが減る。取りこぼしは増える |
| Recall &nbsp;| 閾値を下げると上がる &nbsp; | 取りこぼしは減る。間違って分類されるものも増える |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/bd56f4bf-98a5-cbb6-1659-0c1eb3ad40f7.png)
タグごとのパフォーマンスを見ると、湿度6～12%のタグについては0%でまったく検出できない状態のようです。
![0023.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/60482983-56a9-742e-2bdb-5434e2d80c3c.png)
実際に湿度10%の画像をテストで読ませてみると、59%の確率で「湿度14%」だと判断しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/9e5b5ff6-e9b0-eee7-e09f-3bbb26e6a143.png)
湿度10%の画像を試しに10枚ちょっと追加して再度学習してみましたがこの程度では意味がなかったです。

## うまくいかない原因
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/ff05302e-2bbd-8057-4b2b-0f7bff055c9a.png)
画像処理やってる人はわかると思いますが、今回教師データに使用した画像は、このように影やプラスチックカバーの光の反射などノイズとなるものが含まれていて、学習にかけるにはあまりよろしくない状態です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/04d7e1be-63f1-a061-8553-0790f072c0c3.png)
この手の画像処理では、白黒の2値化とか手法としてポピュラーなので、例えばこのようにモノクロビットマップにしてしまうと、カラーで見たときに針の影があった湿度14%あたりが黒くなっています。また、湿度0%～10%あたりまでは黒く塗りつぶされていてこれでは判断できません。

# 再学習
うまくいかない原因と思われる要素がこれだけとは限りませんが、少なくとも1つがわかったわけです。じゃあどうするのか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/b6ea6e9d-d114-483e-036c-f73f648d15a2.png)
画像分類は白黒にしてしまうとうまくいきやすいと言われているので、こうしてグレースケールを調整してこれくらいの画像にして再度教師データを用意するという手もありますが、今回は教師データを改めて用意することはしません。
## Advanced Training
![0014.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/20b5aebb-ab00-2528-b9a7-278f177272e9.png)
最初に学習する際は「Fast Training」を使いましたが、今度は「Advanced Training」を使用します。
これは1時間から最大で24時間まで1時間単位で学習時間を調整して学習にかけることができます。
今回は1時間を指定して学習します。ちなみにプランF0の場合、1か月最大で1時間の学習時間が無料枠として提供されています。今回はすでに何分か使用しているので、残りの時間をすべて学習時間につぎ込みます。トータル1時間になった時点で学習は強制的に完了になります。
プランS0の場合は1時間当たり2240円かかります。5時間やれば1万円ちょっとの料金です。1日回したら5万3千円ですね。ちなみに途中で止めることはできないようなので注意が必要です。(計算の途中でリソースを削除したら課金が止まるのかはわかりません)

![0020.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/6cec6e24-db9c-d5e2-9916-2b91264c0c99.png)
というわけで、1時間学習した結果がこちら。かなり良くなってますね。教師データは最初にアップロードした分でやってるので、2値化とかしたデータを与えたわけではないですよ。
ただ、内部的には回転を加えたり、位相をずらしたり、2値化したりと様々な分析関数にかけて、さらには都度パラメータの調整などもやっていると思われます。(ブラックボックス化されてるので正確なところはわかりません。推測です。)
逆に言えば、1分程度のFast Trainingではそれほど詳しくはやっていないということだと思います。
![0021.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/e015b796-fe7a-63e0-6d0c-86ec0e1f9402.png)
最初に「湿度14%」だと判断された画像は99.9%の確率で「湿度10%」だと判断していますね。正直劇的な改善だと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261327/b6068e2d-c68c-cec6-3c1e-f1b62b8f4b42.png)
アノテーションに時間がかかったとは言え、集中してやれば1日くらいやればアナログメータの読み取りは行けそうですね。類似のメータとしてはタコメータとかも行けそうですが、こういった電流計のように針の細いものでも大丈夫なのか試してみたいですね。
tensorflowとかを使って独自に開発というのも面白そうですが、こういたサービスを使うと大幅に時間が短縮できそうです。
特に、私のようにモデルを作ることよりも、そのモデルを使って何かをやることに重きを置いてる人間にはCognitive Servicesは最適だと思います。

教師データを作成する手順はどのみち必要なので、Customvisionがわずか1日くらいで検証できるのであれば、

1. とりあえずCustomvisionを使ってやる
2. どうやっても精度がいまいちなら自分でプログラミングする

という感じでやってみるのがよさそうですね。気軽にとりあえずやってみるというのは大事だと思いました。
あと独自で作るのはちょっと汎用性とかを持たせられそうなので、同じ推論モデルで類似のメータを読むこともできるかもしれません。汎用性を持たせようと思ったらハードルが一気に上がりそうなので、やっぱり専用で割り切ってさっと作ってしまうのが今はいいのかな。

ということで、湿度計の読み取りチャレンジでした。