Amazon SageMakerでお手軽に物体検出サーバを作成する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/e7e7a42f-166b-6deb-e789-bfd3112e4886.png)


この記事は[UMITRON Advent Calendar 2023](https://adventar.org/calendars/8726) 5日目の記事です

[English page](https://qiita.com/hosonot/items/ddd8e621564051ae6bea)

## 目次
[まえがき](#まえがき)
[大まかな流れ](#大まかな流れ)
[Amazon SageMaker Ground Truthを利用した学習データ作成](#amazon-sagemaker-ground-truthを利用した学習データ作成)
[Amazon SageMaker組み込みアルゴリズムを利用した物体検出モデルの学習](#amazon-sagemaker組み込みアルゴリズムを利用した物体検出モデルの学習)
[Amazon SageMaker エンドポイントを利用した物体検出モデルのデプロイ](#amazon-sagemaker-エンドポイントを利用した物体検出モデルのデプロイ)
[物体検出の実行](#物体検出の実行)
[エンドポイントの停止](#エンドポイントの停止)
[最後に](#最後に)

## まえがき
こんにちは、[UMITRON](https://umitron.com/ja/index.html)の細野です。
[昨年](https://qiita.com/hosonot/items/343e373b5ee35a63c81b)に引き続き物体検出に関する記事です。

ウミトロンでは要件に応じていくつかの物体検出アルゴリズムが使われていますが、手軽に検証をしたいというときは、Amazon SageMaker組み込みの物体検出アルゴリズムがよく使われます。
物体検出アルゴリズムはSSD[^1]なので、最新のアルゴリズムと比較すると精度が出にくい場面があるかもしれませんが、学習データの生成からモデルのデプロイまですべてウェブインタフェースででき、簡単に物体検出サービスを構築できます。

モデルの更新等の運用を楽にするという観点では、ウェブインタフェースを使うよりもSDKを使ってコードで管理した方が良い場合が多いですが、ウェブインタフェースを使えば物体検出やAWSを使った開発に慣れていない方でも手軽に検証ができるというのは大きなメリットだと思うので、本記事では物体検出の推論実行部分以外はすべてコードの記述が不要なやり方を紹介します。

なので、本記事が参考になるかもしれない方は以下のような方です。

- 物体検出の知識はあまりないが、物体検出を使ったサービスを開発してみたい
- 物体検出の利用経験があるが、Amazon SageMakerを使ったことがない

## 大まかな流れ
本記事ではAmazon SageMakerを使った、物体検出モデル学習用のデータセット作成方法、そのデータを使って学習されたモデルのAPIサーバーとしてのデプロイ方法及びその呼び出し方法を紹介します。
大まかな流れは以下の通りです。

1. Amazon SageMaker Ground Truthを利用した学習データ作成
1. Amazon SageMaker組み込みアルゴリズムを利用した物体検出モデルの学習
1. Amazon SageMaker エンドポイントを利用した物体検出モデルのデプロイ
1. 物体検出の実行

物体検出モデルのデプロイについて、本記事ではリアルタイム推論[^2]を用いた方法を紹介します。リアルタイム推論では低レイテンシーで利用可能なAPIサーバをホスティングできます。

余談ですがAmazon SageMakerでは、不定期にリクエストが発生するアプリケーションに適しているサーバレス推論[^3]や、大きなデータの処理に適している非同期推論[^4]等といったその他のデプロイ方法も選択できます。

以降、各手順について解説していきます。

## Amazon SageMaker Ground Truthを利用した学習データ作成

本記事では、学習データのラベリングを自分たちでやる方法を紹介します。
Amazon Mechanical Turkを利用してクラウドソーシングすることも可能ですが、費用がかかったり機密情報は扱えなかったりする点に注意が必要です。

### ラベリングワークフォースの作成

ラベリングを自分でやるために、ラベリングワークフォースを事前に作成しておく必要があります。
手順は以下の通りです。

1. SageMaker→Ground Truth→laveling workforces→Private→Create private teamを選択します <br> <img width="900" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/4e12beaa-8ef3-8e42-6e80-7ea0fdb13cda.png">
1. チーム名を決めてチームを作成します（チーム名以外はデフォルトのまま） <br> <img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/b6151aea-4807-9bf3-9403-4369b6611380.png">
1. Labeling workforcesの画面に戻り invite new workersを選択します <br> <img width="900" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/56fd35fa-3b99-945c-aa89-e201433b14a9.png">
1. ラベリングを実施する人のメールアドレスを入力し invite new workersを選択します <br> <img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/478b2eec-aecf-3d23-4e24-33bedbd058d8.png">

1. 登録したワーカに以下のような内容のメールが届くので、メール内のリンクからworker portalにログインしパスワードの設定をしておきます。このときworker portalログイン用のURLを保存しておくと便利です。 <br> <img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/a264a338-1adc-e548-feb0-0db31a14d06b.png">

 ### 学習データの画像をS3にアップロード
 Amaon S3の好きな場所に画像データアップロードします
 1. Amazon　S3→画像をアップロードするフォルダに移動→Upload <br> <img width="700" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/496f6970-03a7-1de0-71d1-375bed114684.png">
1. ドラッグ&ドロップ等で画像を選択してアップロード <br> <img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/6bba6789-1702-2729-af31-93277e3fe5e1.png">


### ラベリングジョブの作成

1. SageMaker→labeling jobs→create labeling jobを選択します <br> <img width="700" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/6de3fa9d-d4da-8094-4ff9-96fc79c0c7da.png">
1. Job overviewの各項目を設定します。Input data setupはautomated data setupを選択し、S3 location for input datasetsには先程画像をアップロードしたフォルダのパスを入力してください。また、Data typeはImageを選択してください。IAM RoleはAmazonSageMakerfullAcessを持つものを指定してください。その後、complete data setupをクリックします <br> <img width="700" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/4d7352ef-7843-ef55-6d83-c08e95b6336c.png">
1. Data setupが成功すると下の画像のような表示になります <br> <img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/30b83fad-92ca-45b0-13a3-261f02d807ce.png">
1. Task typeをbounding boxに変更し、nextをクリックします <br> <img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/4e1c7944-84e4-1a41-2f1b-94e97f78b7fb.png">
1. Worker typesがprivateになっていることを確認し、先程作成したチームをprivate teamsに設定してください。Task timeout（一枚の画像のアノテーションに掛けられる時間）とtask expiration time（全データのアノテーションを完了させる期限）は適宜調整してください <br>  <img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/ac2ac715-74ce-ee59-8b0f-74c5342be3bc.png">
1. Bounding box labeling toolの設定を行います。ここではlabelsのみ設定しています。ラベリングを実施するメンバーにタスク内容を詳細に説明したい場合は、ここに正解の例やルールの記述をすることができます。設定後createをクリックして完了です <br> <img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/a8b0d677-3f26-602c-5aea-0328717246e0.png">

### ラベリング

1. Worker potalにログインするとタスクが追加されているので、start workingでラベリングを開始します <br> <img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/388ec48b-fd68-3c6e-7d88-356b1c67028e.png">
1. ラベリングしていきます（本記事で使用している魚の画像はすべてDeepFishデータセット[^5]のものです） <br> <img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/2a4a233d-eef5-046e-f866-01770208d959.png">
1. 完了してしばらくするとラベリングジョブのステータスがcompleteになります <br> <img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/c836f2e9-2dc8-7028-eb1e-ffd616869724.png">

## Amazon SageMaker組み込みアルゴリズムを利用した物体検出モデルの学習

### トレーニングジョブの作成

1. SageMaker→trainging jobs→create training jobを選択します <br> <img width="900" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/9c5d7dab-7a1e-56a0-0dfc-2443abc8d258.png">
1. Job settingsを設定していきます。IAM roleは先程と同様にAmazonSageMakerFullAccessを持つものを設定してください。Algorithm sourceはAmazon SageMaker built-in algorithmを選択し、algorithmはVision - Object Detection (MxNet)を選択します。Input modeはFileです。 <br> <img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/12c8fd66-e442-f6c0-4c2b-88180b81d757.png">
1. Resource configurationのinstance typeはGPU搭載のもの（p2やg4dn）を選択してください。 <br> <img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/cfe336b5-1ce9-3731-b1b1-c264d3ca7be2.png">
1. ハイパーパラメータの設定です。物体検出に慣れていない方は謎の項目だらけかもしれませんが、ほとんどデフォルトで大丈夫です。<br>必ず設定しなければならない項目は下の画像の赤枠で示したnum_classesとnum_traning_samplesです。それぞれ学習データに含まれるクラス（ラベルの種類）数と画像の総数を設定してください。<br>また、下の画像の緑枠で示したbase_networkとepochsとmini_batch_sizeは調整した方がいいかもしれない項目です。base_networkはresnet-50の方が少し精度がよくなるかもしれないので私はいつもこちらをまず試します。epochsは少ないと学習が十分にされない可能性がありますが、多いと学習時間がかかります。後ほど調整方法を解説します。mini_batch_sizeは初期値でいい場合が多いですが、今回のように学習データの数が少ないときは大きくても学習データの10分の1程度にしておいて方が良いです（num_training_sampleより大きな値にするとエラーが出ます）。また、num_training_sampleの数が数万枚等多い場合は512等デフォルトよりも大きな値にしてもいいかもしれません。 <br> <img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/5e58e7b6-a17b-14e1-49c0-ef8209002b13.png">
1. Input data configurationを設定します。デフォルトから変更する箇所が多いですが、下の画像のように設定してください。赤枠で示したAugmentedManifestFile attribute namesの２つ目にはラベリングジョブのジョブ名を設定してください。緑枠で示したS3 locationにはラベリングジョブのoutput dataset locationのフォルダ以下に生成されているmanifest/output/outpu.manifestのS3 URIを記載してください。その後、add channelをクリックします。<br> <img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/c7d3914b-7502-184e-4e95-dd9c8395bcc2.png">
1. 追加したchannelのchannel nameはvalidationにして、その他はすべてtrainと同じものを記載してください（理想的には学習データとは別のvalidation用データを用意したほうがいいのですが、今回はお手軽版ということで省略させてください）。<br> <img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/659cf7ed-da04-6072-e0c0-59c65c84b097.png">
1. Output data configurationには、生成されたモデルファイルを置きたいフォルダを指定してください。Enable managed spot trainingを有効にすると、学習が長くなることがありますが、お安く学習をすることができます。最後にcreate training jobをクリックして学習スタートです。<br> <img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/9ff092a1-9075-69e6-fe3a-eee9326b3a1b.png">





### トレーニング結果の確認


1. SageMaker→trainging jobsから先程作成したトレーニングジョブのstatusがcompletedになっていることを確認し、クリックしてジョブの詳細ページにいきます <br> <img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/0a6fd8e1-3bf5-5c09-2422-ab3fd54e1652.png">
1. ジョブの詳細ページのmonitorで様々な値のログを確認します。ここではトレーニングジョブの作成時に設定したepoch数を調整するために見る項目であるvalidation:mAPとtrain:cross_entropyについて少し説明します。<br>validation:mAPの縦軸はvalidationデータでどのくらい精度良く物体検出を表しており、高いほどよいです。今回は42枚という少ないデータ数だったので値があまり高くないですが、もっと多くの学習データを使い、かつうまく学習できていれば0.8程度になります（そもそも物体検出が難しいデータセットの場合も低い値になります）。横軸は学習時間でこれがepoch数に比例します。グラフを見ると学習が進むに連れて0.4付近に収束していることがわかります。この収束が不十分な場合はepoch数を増やして再度学習したほうが良いです。また、収束してからも長時間学習されている場合、次回同じようなデータで学習するときはepoch数を減らすことで、精度を保ちつつ学習時間を削減できます。<br> train:cross_entropyの縦軸は学習がどれくらいうまく行っているかを表す指標であり低いほどよいです。横軸は学習時間です。この値も学習が進むに連れて収束していくので、epoch数の過不足を確認できます。<br> <img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/dbec830a-cb5e-6154-1432-c215b86e8d4b.png">


## Amazon SageMaker エンドポイントを利用した物体検出モデルのデプロイ

### モデルの作成
1. SageMaker→trainging jobs→先程作成したトレーニングジョブ→create modelを選択します <br> <img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/36f36629-8cf4-f618-6945-15e8b914204f.png">
1. Model nameのみ記載し、そのままcreate modelをクリックします <br> <img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/759f87f2-641f-7259-a022-c729d594aba2.png">

### エンドポイントの作成

1. SageMaker→models→先程作成したモデル→create endpointを選択 <br> <img width="900" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/71e89428-1f0c-f35a-6da5-97dd55c08a54.png">
1. Endpoint nameとendpoint configuration nameを入力し、create endpoint configurationをクリックします <br> <img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/4ccb2e2e-2be0-6c8b-6533-d1ceb2e65d4d.png">
1. Endpoint configurationの作成が完了したらcreate endpointをクリックします <br> <img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/e92a96ca-ab17-0139-0b4a-8e5db4e39fb5.png">
1. 数分後にエンドポイントが作成されます <br> <img width="700" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/36d4063a-25cd-be45-dd41-26e25d24f550.png">




## 物体検出の実行

1\. Pythonが実行できる環境にAWS SDK[^6]とOpenCV[^7]をインストールします。どちらもpipでインストールできます
 ```shell
 $ pip install boto3
 $ pip install opencv-python
 ```
2\. コードを書きます。エンドポイントを呼び出す部分のサンプル関数を以下に記します
```python
import boto3
import cv2

def detect(img, endpoint_name, aws_profile_name):
    """Detect pellets using SageMaker endpoint
    Args:
        img (np.array): Image data loaded with OpenCV
        endpoint_name (str): SageMaker endpoint name 
        aws_profile_name (str): AWS profile name to access endpoint
    Return:
        dict: detection result json
            {"prediction":[[class id, score, xmin, ymin, xmax, ymax],...]}
    """
    _, buffer = cv2.imencode(".jpg", img)
    session = boto3.session.Session(profile_name=aws_profile_name)
    client = session.client("sagemaker-runtime")

    response = client.invoke_endpoint(
        EndpointName=endpoint_name,
        Body=buffer.tobytes(),
        ContentType="image/jpeg",
    )
    return json.loads(response["Body"].read())
```

実行結果です。42枚でしか学習していないですが結構検出できました。
![7434_F1_f000073.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/8ed3a041-172a-dc3b-6a8a-84b2e0ebf862.jpeg)


## エンドポイントの停止
エンドポイントは起動している時間に対して料金が掛かるので、使っていないときはdeleteしましょう。エンドポイント設定を残残しておけばSageMaker→endpoints→create endpointから簡単に再作成できます。

1. SageMaker→endpoints→先程作成したエンドポイント→deleteを選択します <br> <img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2371662/728195ac-4185-c2bf-393c-dd482195e04b.png">



## 最後に
本記事ではAmazon SageMakerを使った物体検出サーバの作成方法を紹介しました。
画像さえ収集できれば簡単に物体検出の検証ができますし、十分な精度が出るならそのままプロダクト用の物体検出サーバとして運用することもできるので、スピーディーに物体検出を使ったサービス開発ができる点も魅力的です。
本記事が、物体検出を使ったサービスを開発してみたい方の一助となれば幸いです。

---
ウミトロンでは一緒に働く仲間を募集しております。持続可能な水産養殖を地球に実装するというミッションの元で、私たちと一緒に水産養殖xテクノロジーに取り組みませんか？

https://umitron.com/ja/career.html

https://open.talentio.com/1/c/umitron/requisitions/746

[^1]:[Amazon SageMaker デベロッパーガイド オブジェクト検出-MXNet](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/object-detection.html)
[^2]:[Amazon SageMaker デベロッパーガイド リアルタイム推論](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/realtime-endpoints.html)
[^3]:[Amazon SageMaker デベロッパーガイド サーバーレス推論](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/serverless-endpoints.html)
[^4]:[Amazon SageMaker デベロッパーガイド 非同期推論](https://docs.aws.amazon.com/ja_jp/sagemaker/latest/dg/async-inference.html)
[^5]:[DeepFish](https://alzayats.github.io/DeepFish/)
[^6]:[Amazon SageMaker デベロッパーガイド AWS SDK のセットアップ](https://docs.aws.amazon.com/ja_jp/kendra/latest/dg/aws-kendra-set-up-sdks.html)
[^7]:[opencv-python](https://pypi.org/project/opencv-python/)