機械学習でアガベを判定してみた。ノーコードで。

# はじめに
皆さん植物は好きですか？僕は大好きです。

特に**アガベ**という多肉植物が好きで、好きが講じて海外からアガベを小口輸入してオリジナル鉢と合わせて販売しています。D2Cによりinstagramさえあれば誰だってブランドを立ち上げられるいい時代になりました。

## 足元に転がった大量のアガベの写真を整理したい

さて本業の傍らで運営している中で困っていることの一つがストックしているアガベの管理です。中でも売れ筋なのがコンパクトで型が良い台湾アガベ。ただ台湾のチタノタ系は独自の名称がついた株が多数存在していてしかも形がよく似ているんです。例えば下の写真
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/871869/42caa7b5-0163-f820-b907-42492e8586f7.jpeg" width=70% align=center>

左はみんな大好き『agave titanota "白鯨（はくげい）"』。右がみんなの憧れ『agave titanota "Caesar（シーザー）"』。見分けられますか？ うちの家族に見せたところ全然違いが分からないとのこと:sweat_smile:

**見た目が似ていてややこしいアガベの写真を機械学習で種別を判定**させて、ゆくゆくは個体も判定できたら各チャネル用の多量な写真の管理が捗りそう、、、でも**機械学習についての専門的な知識は持ち合わせていない**、、、

そんな自分にぴったりなサービスが各クラウドプラットフォームから出ているので、今回は2つピックアップして検証してみました。


# 試してみたサービス
今回使ってみたサービスは以下の2つ。

### AWS Recognition Image Custom Label
AWSが提供する画像認識、画像分析サービスであるAWS Recognition。基本的にはすでに用意された学習済みモデルしか利用できませんが、Custom Labelを使うことで用途に合わせた独自のモデルの作成とオブジェクトの検出が可能。

### Microsoft Lobe

Microsoftが10月26日にプレビューを公開した、ローカルで簡単に機械学習モデルを用意できるツール。ラベルあたり5枚あれば推論ができて、用意したモデルデータは各種フォーマットにエクスポート可能。

いずれも無料（Recognitionは条件あり）でノーコードでラベリング〜学習〜検証までできます。素敵。


## 検証の内容

上記2つの画像識別サービスを使って以下の内容を検証してみます。

### 検証方法
* 学習で用意するラベルは二種類。それぞれ10枚ずつ計20枚の学習用の画像を使って学習モデルを用意。
* 学習用とは別の画像４0枚を用意してそれぞれのモデルで検証。

### 検証項目
* 推論結果の精度
* 学習プロセス

【おことわり】
今回の検証は、少ない学習データでかつアガベという特定の植物の種類の判定という条件のもとでの検証なので、この内容が各サービスの品質評価に繋がるものではないということを先にお断りしておきます:bow_tone1:

# AWS Recognitionによる機械学習モデルの作成
まずはAWS Recognitionのカスタムラベルから触っていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/871869/027d88fb-7dbb-6e4e-b795-10b2af10fc0a.png)

プロジェクトを作成しカスタムラベルを作成していきます。カスタムラベルは現在us-north-1のリージョンでのみ利用可能なのでその点は忘れずに。
※AWS Recognitionカスタムラベルのプロジェクトやデータセットの詳細な作成方法はここでは割愛します。

画像データをアップロードし（一度にできるのは30枚まで）、それぞれにバウンディングボックスとラベルを設定したら、モデルのトレーニングを開始します。

## 学習

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/871869/117ad85a-a7de-8afc-5e03-5d639799cdec.png)

モデルのトレーニングは22枚の画像だと約1時間ほどかかりました。
終わるとモデルの詳細画面にてトレーニングの結果を確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/871869/ca016d23-b9df-dbdf-24c9-17d4a07caba9.png)

F1 Score(精度と検出率をバランス良く持ち合わせているか示す指標)がめっちゃ低い。。
どうやら内訳を見ると白鯨は0.79とまあ好成績な一方でシーザーが0.39と低く足を引っ張る形に。
今回は数が少ない上に角度もばらばらの画像を使った事で精度が出なかったのかもしれない。

## 推論

とはいえ一応モデルは出来上がったのでモデルを起動してみます。
AWSの管理コンソール画面上で起動、推論、停止用のAWS CLIコマンドが記載してあるので動作確認がとても楽。

![スクリーンショット 2020-11-18 19.30.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/871869/56b932a8-d546-8fb0-1f11-bd16818fa03f.png)

StartAPIを実行。ただなかなかモデルが立ち上がらない。。結局ステータスが"RUNNING"になったのは約30分後。

ようやくRUNNINGになったので早速推論してみます。
推論用のサンプルコードはs3のオブジェクトを参照するようになっているので、適当にS3のバケットを作って画像を上げて実行。

```
    "CustomLabels": [
        {
            "Name": "hakugei",
            "Confidence": 100.0,
            "Geometry": {
                "BoundingBox": {
                    "Width": 0.7819100022315979,
                    "Height": 0.9035300016403198,
                    "Left": 0.15939000248908997,
                    "Top": 0.05576999858021736
                }
            }
        }
    ]
```
こんな感じのresponceが帰ってきます。テストした画像は白鯨（hakugei）。Confidece（確信度）が100て。めっちゃ心強いやん。ただこのあといくつかテストしてみましたがやはりCaesar(シーザー)はほとんど判定できませんでした。

## AWS Recognition Custom Labelによるアガベ画像の自動振り分け

推論の検証をする上でいちいちAPI叩くのが面倒なので、s3に上げた画像をLambdaでAWS Recognition Custom Labelの推論APIを使って判定し、その結果で保存先を自動で振り分けるようにしてみます。
フォルダの振り分けは推論の信頼度が70よりも低い場合は直下に。判別できたものはラベル名のフォルダに振り分けます。

今回はPyton製のサーバーレスフレームワーク[Chalice](https://github.com/aws/chalice)を使ってLambdaを構築しました。Chaliceめっちゃ便利。用意したコードはこんな感じです。

```python:app.py
import uuid
import boto3
from chalice import Chalice
from chalice.app import S3Event

app = Chalice(app_name='detect-agave')

# S3へのPutをトリガーに設定
@app.on_s3_event(bucket='detect-agave',
                 events=['s3:ObjectCreated:Put'],
                 prefix='',
                 suffix='jpg',
                 name='detect-image')

def lambda_handler(event: S3Event):

    s3 = boto3.client('s3')
    rekognition = boto3.client('rekognition')

    bucket = event.bucket
    key = event.key
    tmp_key = key.replace('/', '')
    image_path = '/tmp/{}{}'.format(uuid.uuid4(), tmp_key)

    # データダウンロード
    s3.download_file(bucket, key, image_path)

    # カスタムラベル推論API呼び出し
    response = rekognition.detect_custom_labels(
        ProjectVersionArn = 'YOUR_PROJECT_VERSION_ARN', #用意したモデルのリソースネームを設定
        Image={'S3Object': {'Bucket': bucket, 'Name': key}},
        MinConfidence=70)

    # 推論結果による振り分け
    update_bucket = '{}-detected'.format(bucket)
    for labelDetail in response['CustomLabels']:
        s3.upload_file(image_path, update_bucket, '{}/{}'.format(labelDetail['Name'],key)
    else:
        s3.upload_file(image_path, update_bucket, key)  
```

このようにAPIを呼び出すだけで簡単に機械学習モデルによる判定を実装することができました。


# Lobeによる機械学習モデルの作成

続いてLobeを試します。
Lobeはローカルで動作します。Windows、Macそれぞれのプログラムが用意されているのでダウンロードします。

https://lobe.ai/

ダウンロードしたZipファイルを展開して起動すると、以下のような画面が表示されました。

![スクリーンショット 2020-11-18 14.23.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/871869/567a2365-22f2-07a9-d054-59899ac1059f.png)

シンプルなメニュー。そして"**5** images per label needed to start training."とのこと。今回は10枚ですがそれで一定の精度を出せるのであればすごい。

## 学習用データのアップロード＆ラベル付け
Importは(Image, Camera, Dataset)の3種類の方法から選べます。今回は『Dataset』を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/871869/e53d1703-6c50-3fd8-8d33-4aa90f084989.png)

構造化したフォルダを用意することで自動でラベル付けをしてくれる。これはめちゃ便利でした。
ただ一方でバウンディングボックスによるアノテーションには対応していないということかな。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/871869/b338de85-a6f2-aa7b-4d1a-e3dddc565288.png)

## 学習
あっという間にアップロード完了。そしてアップロードすると自動で学習してくれます。これがとにかく速い！気がついたら終わっています。『Train』メニューで結果を確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/871869/bc3e6534-28b7-a200-68dd-57ea1308c21d.png)

なんと精度100%！ ほんと？ 早速『Play』で推論してみます。

## 推論

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/871869/0cc9c46c-fc4d-5c6a-e5db-3987e0e09570.png)

学習データ以外の画像ファイルをドラッグ&ドロップすることで正しく推論してくれました:clap:
さらに『Camera』を使うことでカメラに写ったオブジェクトに対してリアルタイムに推論と修正を進めてくれます。これは捗る。

![ezgif.com-gif-maker (3).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/871869/4eb57995-c1b4-40f9-5519-225cb368060a.gif)


とにかくデータの用意とトレーニングがサクサク進んで終始ストレスなく進められました。
作成したモデルは汎用的なフォーマットでエキスポートも可能。
本当に簡単なのでこういったツールを使ってたくさんの実用的なモデルが生み出されていくと素敵ですね。

# 検証結果

| サービス | AWS Recognition - Custom Label | Microsoft Lobe |
|:-:|:-:|:-:|
| 推論の精度  | 45% | 74.5%  |
| 学習プロセス | 学習データのアップロード、ラベル付の際にUI上の数制限あり。少ないデータでもモデル作成までに時間を要する。バウディングボックスによる単一画像からの複数ラベル抽出が可能。  | アップロードしたら即学習開始。モデルの作成時間が非常に短くテンポよく学習が進められる。バウンディングボックスによるラベル付けはできない  |

上記結果はあくまで**各ラベル10枚程度というごく少数でかつアガベという植物の写真を使った検証結果**です。
もちろん対象やデータセットの数と画像の処理によってはまた結果は異なるかと思いますが、今回の条件では**Lobeの学習プロセスの容易さと少ないデータセットでの精度の高さ**が目立つ結果となりました。

# まとめ

簡単に機械学習を使えるいい時代になりました。
個人的に普段はAWSを利用しているので扱いやすいのはAWS Recognitionですが、Lobeの手軽さと精度の高さに感動しました。Lobeは作成したモデルをTensorFlow等様々なフォーマットでエクスポートできるので、分業化して効率を上げながら精度の高いモデルを使ったサービスを手軽に作ることができそうです。

皆さんも機械学習で快適なアガベライフを！