Jetson Nano Developer KitでAWS IoT GreengrassのML Inferenceを試す

前回の記事では、Jetson Nano上でAWS IoT Greengrassを動かしました。
[Jetson Nano Developer KitでAWS IoT Greengrassを動かしてみる](https://qiita.com/sparkgene/items/2757f35bbae0186cced7)

今回は、Jetson Nano上でMLの推論を試してみます。

Greengrassは事前に生成したMLのモデルを使って推論を実行する事が可能です。
[AWS IoT Greengrass ML Inference](https://aws.amazon.com/jp/greengrass/ml/)

推論で使うモデルが必要になるので、今回はこちらの「[AWS マネジメントコンソール を使用して Machine Learning Inference を設定する方法](https://docs.aws.amazon.com/ja_jp/greengrass/latest/developerguide/ml-console.html)」を参考にしながら作業を進めます。

## MXNetのインストール

AWSのドキュメントではJetson TX2向けの手順やライブラリが有るのですが、Jetson NanoはCUDA10の為、そのまま使えません。
で、ソースからインストールやら色々ハマった結果、公式のフォーラムで解決策が提供されていたので、それを参考にインストールしました。

[I was unable to compile and install MXNET on the jetson nano，Is there an official installation tutorial?](https://devtalk.nvidia.com/default/topic/1049293/jetson-nano/i-was-unable-to-compile-and-install-mxnet-on-the-jetson-nano-is-there-an-official-installation-tutorial-/post/5326170/#5326170)

```
sudo apt-get install -y git build-essential libatlas-base-dev libopencv-dev graphviz python-pip
sudo pip install mxnet-1.4.0-cp27-cp27mu-linux_aarch64.whl
```

ついでにGreengrassSDKもインストールします

```
sudo pip install greengrasssdk
```

## MXNet モデルパッケージを作成する

- squeezenet_v1.1-0000.params
- squeezenet_v1.1-symbol.json
- synset.txt

この3つのファイルをzipに固めるらしいのだが、このドキュメントのURLからダウンロードしようとしても、タイムアウトしてちっともDL出来ない。。。
探してみたら、githubにあげている人がいたので、そこからDLしました。
https://github.com/dzimine/aws-greengrass-ml-inference/tree/master/lambdas/GreengrassImageClassification/squeezenet

## Lambda 関数を作成して公開する

ドキュメントだとMXNetのビルド中にサンプルソースが生成されるとのことだが、今回はビルドしていないのでソースが見つからない。
以前に、試した際に取っておいたソースが有るので、今回はこれを使う。そのソースだと、Jetson TX2のオンボードカメラやRaspberry PiのPiCameraを使う内容なので、Jetson Nano向けにUSBカメラが使えるように変更したソースをgithubに上げました。
https://github.com/sparkgene/greengrassObjectClassification
(ソース取得元は、AWS IoTのマネージメントコンソールで Software > Machine learning inference > Runtimes and precompiled framework libraries configure downloadでソフトウエアの画面を開き、MXNet Nvidia Jetson TX2のdownloadでダウンロードしたファイルの中にmxnet_examples.tar.gzがあるのでそれを展開するとexamples/greengrassObjectClassificationに見つかります)

この3つのファイルをzip化して、新しく作成したLambdaに登録する。
Lambdaの登録とAliasの作成は[こちら](https://qiita.com/sparkgene/items/2757f35bbae0186cced7#4lambda%E3%82%92%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E3%81%97%E3%81%A6%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%82%92%E9%80%81%E4%BF%A1%E3%81%99%E3%82%8B)を参考にしてください。

LambdaをGreengrassに登録する際、以下のように設定を変更する

- Memory limit
  - 128M
- Lambda lifecycle
  - Make this function long-lived and keep it running indefinitely

## Greengrass グループにリソースを追加する

### ビデオカメラ

次に、Lambdaからビデオカメラにアクセスさせる必要があるので、Greengrassの画面でローカルリソースの追加を行います。
<img width="1039" alt="スクリーンショット 2019-04-12 23.18.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/b2470e0a-4de2-5245-1ab4-89dddd1e6072.png">

わかり易い名前をつけます
<img width="687" alt="スクリーンショット 2019-04-12 23.23.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/c38d6f79-5419-28bb-0632-1d391dd09f4b.png">

`Device` を選んで、ビデオのパスに`/dev/video0`を指定します。（環境によって変わります）
パーミッションでは`Automatically add OS group permissions of the Linux group that owns the resource` にチェックを付けます。
<img width="719" alt="スクリーンショット 2019-04-12 23.24.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/33feb187-3729-2dd4-59ef-53910d03a4b0.png">

読み書き権限が必要なので、`Read and write access`を選ぶ。最後に保存をします。
<img width="1043" alt="スクリーンショット 2019-04-12 23.24.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/e1b3188e-5f7f-f6fe-8f7a-cb66745d54da.png">

### モデル

次に、推論で使うモデルもリソースに追加します。
`Machine Learning`を選び、`Add machine learning resource`で新規に追加します
<img width="1067" alt="スクリーンショット 2019-04-12 23.29.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/6f8ddfa5-2bdc-b446-b22c-8dd9ff23aa37.png">

わかり易い名前をつけます
<img width="732" alt="スクリーンショット 2019-04-12 23.35.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/82ab7222-2ac7-d8f4-0e61-d49a2195b323.png">

先の手順でzipに固めたモデルをS3に上げておきます。ここでは、S3にあげてあるモデルを指定します。
<img width="1045" alt="スクリーンショット 2019-04-12 23.36.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/84a2b013-2513-eeba-89d6-09b31b7e6e01.png">

local pathには、Lambda内から参照する際のパスを指定します。Lambdaに紐付けるので、登録したLambdaを探して選択します。Lambdaからは`Read-only access`で大丈夫です。
<img width="1090" alt="スクリーンショット 2019-04-12 23.39.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/2bcbe057-19bf-0575-b542-cf149878987d.png">

最後に`Save`をクリックして登録します。
<img width="1074" alt="スクリーンショット 2019-04-12 23.44.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/33a73610-ca7a-b0d9-94dd-d2eef977048e.png">

### AWS IoTへのPublish

今回のサンプルだと、物体を検出したらMQTTでデータをAWS IoTに上げる仕組みにしているので、Greengrass側のSubscriptionにデータの流れを登録します。
Subscriptionのメニューから`Add Subscription`を選択します。
<img width="1064" alt="スクリーンショット 2019-04-12 23.47.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/8c0368d4-f43f-be19-6561-b1cd65b80095.png">

SourceにLambda、targetにIoT Cloudを指定すると、LambdaからPublishされた、メッセージがAWS IoT Coreにルーティングされます。Nextをクリックします。
<img width="1046" alt="スクリーンショット 2019-04-12 23.53.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/f2ebbe09-51fb-5a43-8b55-45a793ad452b.png">

このサブスクリプションをどのトピックに紐付けるかを指定します。サンプルソースでは、`data/jetsonnano`というtopicに対してpublishするので、合わせます。`Next`を押すと確認画面が表示されるので、確認して登録をします。
<img width="1054" alt="スクリーンショット 2019-04-13 0.00.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/b89aec77-eec5-e71b-b4f4-8c7f74587329.png">

## 動作確認

クラウド側の設定が終わったので、Jetson Nanoにデプロイします。先に、USBカメラの接続をしておきます。
デプロイに時間がかかるので、この間に、AWS IoTのテストメニューを開いて、`data/jetsonnano`を監視します。
<img width="988" alt="スクリーンショット 2019-04-13 0.06.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/8eb5b04c-51ec-80ba-4592-3d650fb016f7.png">

デプロイがされ、しばらくすると以下のように、推論した結果が表示されます。
<img width="690" alt="スクリーンショット 2019-04-13 0.09.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36184/3037bf07-5460-cf58-6e49-55fff6c21cb2.png">

## まとめ

MXNetのインストールはどうなるかと思ったが、なんとかなりました。
ハマらなければ、結構簡単に推論アプリを実行するところまで進められました。
Raspberry Piより性能が高く、Jetson TX2より安いので、色々なシーンで利用できるかなと思います。

## GPUを使う場合(9/5追記)

こちらの記事を参照してください。
[Jetson Nano Developer KitでAWS IoT GreengrassのML Inferenceを試す(GPU編)](https://qiita.com/sparkgene/items/2562045dee93e6f3826b)

## 免責

発言内容は個人的な意見であり、所属する企業を代表するものではありません。
掲載しているソースコードは、サンプルレベルの物ですので動作を保証するものではありません。