AWS IoT GreengrassとBlueoilを使ってFPGAデバイス上で量子化されたDeep Learningモデルを実行する

この記事は、[インテル® FPGA Advent Calendar 2020](https://qiita.com/advent-calendar/2020/intelfpga) 10日目の記事です。

## TL;DR
Cyclon® V SoC FPGAが搭載されたTerasic社製のDE10-Nanoボード上で、Deep Learningを使った推論アプリを動かすよ。
動かすモデルやアプリケーションをAWS上で管理してNetwork経由で更新したりするよ。


## この記事の目的
私が所属しているLeapMindでは、Blueoilという低消費電力なデバイス上でディープラーニングを実現するためのOSSを提供しています。さらに今年は、BluegrassというBlueoilとAWSのコンポーネント(Amazon SageMakerやAWS IoT Greengrassなど)を組み合わせたMLOps環境のサンプルをOSSとして公開しました。

https://github.com/LeapMind/bluegrass

本記事ではこのBluegrassを使用して、実際にFPGAデバイス上での推論アプリケーションを構築する手順について紹介します。
Amazon SageMakerを利用して量子化されたモデルを学習する方法については、下記のAWS Blogに紹介されていますので、そちらも合わせて見ていただけるといいかなと思います。

AWS Startup ブログ: [効率的にインテル® FPGA エッジデバイス上の深層学習推論を実行する](https://aws.amazon.com/jp/blogs/startup/using-fewer-resources-to-run-deep-learning-inference-on-intel-fpga-edge-devices/)


## AWS IoT Greengrassって？
> AWS IoT Greengrass では、AWS をエッジデバイスにシームレスに拡張します。これによりエッジデバイスでは、管理、分析、耐久性のあるストレージのためにクラウドを使用しながら、生成されたデータに基づいてローカルで動作することが可能になります。AWS IoT Greengrass を使用すると、接続されたデバイスで AWS Lambda 関数を実行し、機械学習モデルに基づいて予測を実行し、デバイスデータを常に同期させ、他のデバイスと安全に通信できます。これはインターネットに接続していないときでも可能です。

Ref: https://aws.amazon.com/jp/greengrass/

上記にあるように、Greengrassはエッジデバイスをクラウド側で管理するために必要な多種の機能を提供しているサービスです。
Greengrassを利用することで、デバイス上で動作させるソフトウェアをクラウド側で作成/テストして、デバイスにデプロイしたり、デバイスからデータを収集してクラウド側に連携することなどが可能になります。
今回はこのGreengrassを利用して、学習済みDeep Learningモデルと推論アプリケーションのデプロイ、実行、結果の収集を行います。

## Blueoilって？
> Blueoil is a software stack dedicated to neural networks. It includes special training method for quantization and original networks designed to be highly compatible with FPGA devices. This is done in order to operate a neural network at high speed on a low-powered FPGA. New models can be trained easily by only preparing data. The finished model can be converted into a binary file that runs on FPGA or CPU devices with a single command.

Ref: https://blueoil.org/

Blueoilは[LeapMind Inc.](https://leapmind.io/)が提供している、低消費電力なデバイス上でディープラーニングを実現するためのオープンソースソフトウェアスタックです。
Blueoilを利用することで、量子化されたDeep Learningモデルの学習および、学習したモデルをCPUやFPGAデバイスで実行するためのBinary Fileの生成が可能になります。
今回は[機械学習を使った今までにないデバイスをあまねく世に広める](https://leapmind.io/about/)ために、学習した量子化済みモデルをエッジデバイスにデプロイし、それらを管理するための環境構築が、いかに簡単に実現できるかということを誰でも体験できるように、OSSであるBlueoilを利用しています。

ちなみに弊社からはこのOSSとは別に、FPGA/ASIC上で動作する、より大きく飛躍、進化した、[超低消費電力AIアクセラレータIP Efficiera](https://leapmind.io/business/ip/)が今年から提供されているので、もしご興味がある方は資料などをみてもらえると幸いです。

## 今回使用するデバイス
インテル社のCyclone® V SoC FPGAを搭載したTerasic社製DE10-Nanoボードを利用します。
このデバイスはAWS IoT Greengrass で AWS Device Qualification Program (DQP) 認定を受けているデバイスになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/c205125d-e673-4256-cdbd-95268cb87bdd.png)


## 実行手順
前置きが長くなりました。。。以下に具体的な実行手順を記載します。
下記の構成の構築およびデバイス上での推論アプリケーションの実行をゴールとします。
![bluegrass.png](https://user-images.githubusercontent.com/12394960/87919648-12b48a80-cab3-11ea-819d-e799b12d9411.png)

### Step0: 事前準備
まず[bluegrass](https://github.com/LeapMind/bluegrass)を手元にcloneしてください。

#### AWS CLIのセットアップ
Bluegrassでは、全ての構成をCloudFormationテンプレートとして公開しています。
今回の手順では、このテンプレートをAWS CLIを使ってデプロイするため、こちらの[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-install.html)に従ってAWS CLIをセットアップしてください。

#### Ansibleのインストール
DeviceのセットアップにAnsibleを利用します。
Cloneしたbluegrassのリポジトリ配下で下記のコマンドを実行することでインストールできます。

```
$ pip3 install -r requirements.txt
```

#### 物理的な準備
下記の準備をお願いします。

* Terasic社製DE10-Nanoボード及びUSBカメラ
* イーサネットケーブルとインターネット接続
* ノート PC またはローカル開発環境

### Step1: Amazon S3 bucketとIAM Roleの作成
それではまず、Step1として、Greengrassから収集したデータなどを配置するためのS3 bucketとそれらを利用するために必要なRoleを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/4a946f96-2e3a-12bd-7069-c0a2c17ee957.png)

下記のコマンドでS3 bucket及びGreengrass用のI AM Roleを作成します。
作成するbucketの名前を`BLUEGRASS_S3_BUCKET_NAME`として設定して、実行してください。

```
$ export BLUEGRASS_S3_BUCKET_NAME=[your S3 bucket name]
$ aws cloudformation create-stack --stack-name BluegrassS3 --capabilities CAPABILITY_NAMED_IAM --template-body file://$(pwd)/deploy/s3.yaml --parameters ParameterKey="S3BucketName",ParameterValue="${BLUEGRASS_S3_BUCKET_NAME}"
```

下記のようにコンソールから作成されたリソースが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/65a78f40-856a-098e-c290-17b0c2c80415.png)

### Step2: Amazon SageMaker上での学習の実行
次に学習環境、SageMakerの部分を構築していきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/24d1eb26-43d9-4f89-2b8f-4582a1252b96.png)

#### Amazon SageMaker Notebookの作成
下記のコマンドでAmazon SageMaker Notebookを作成します。

```
$ aws cloudformation create-stack --stack-name BlueoilSagemaker --template-body file://$(pwd)/deploy/sagemaker.yaml
```

下記のようにコンソールから作成されたリソースが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/9a8f28f0-58bc-69e6-365f-a1ec0a5a17a9.png)

#### SageMaker Notebook上での学習およびモデルの変換
学習を実行するための[exampleとしてnotebookを提供している](https://github.com/LeapMind/bluegrass/tree/master/blueoil_sagemaker)ので、下記のようにAWSコンソールから先ほど作成したSageMaker Notebookにアクセスし、`blueoil_*_example.ipynb`を開くことで簡単に学習の実行およびFPGA用に最適化されたモデルへの変換を実行することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/6a38f1d4-b293-37dc-7439-5ebea275e071.png)

モデルの学習はSageMaker SDKを利用してTraining Jobとして実行します。`esrimator.fit()`を実行することで、GPU instanceが立ち上がり、そのinstance上で指定したDocker imageでの学習が開始されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/f61c386e-2459-f402-4df9-daf6570ed50d.png)

Binary fileへの変換はSageMaker Processingを利用します。convert用のpython scriptを`processor.run`で実行しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/87d657b6-f950-b2bb-74e1-cb5e652df9d5.png)

これらの実行はJupyter Notebook上で`Shift + Enter`していくだけです。詳細についてはAWS Startup ブログの[効率的にインテル® FPGA エッジデバイス上の深層学習推論を実行する](https://aws.amazon.com/jp/blogs/startup/using-fewer-resources-to-run-deep-learning-inference-on-intel-fpga-edge-devices/)に記載されていますので、そちらをご確認ください。

#### 学習結果の確認
データセット・実験環境・実験コンフィグ・実験結果等の必要な情報が、実験を行う毎にTraining Jobsという単位で管理され、コンソールから下記のように確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/ef8474c4-b70e-7f53-2841-b06ef428f048.png)

以上で、DE10-Nanoで実行するために最適化された学習済みモデルが作成できました。次にGreengrass部分の構築に進みます。

### Step3: AWS IoT Greengrass Groupの作成
下記のコンポーネントを構築します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/4661300f-ffe1-e35f-4982-31e2e05bfac5.png)

#### Greengrass用の証明書の作成
下記のコマンドでそれぞれのDeviceに配置する証明書を作成しAWS上に登録します。

```
$ deploy/create_cert.sh
...
Certificate files are created in certs/xxxxxx...xxxxxx
certificateArn is "arn:aws:iot:xxxxxx:xxxxxx:cert/xxxxxx...xxxxxx"
```

今回の構成ではDE10-Nanoを2台紐付ける構成となっているため、それぞれのデバイス用に上記コマンドを2回実施し、得られたArnを環境変数として下記のように設定します。

```
$ export CERT_ARN1=[your certificateArn1]
$ export CERT_ARN2=[your certificateArn2]
```

#### AWS IoT Greengrass Groupの作成
下記のコマンドでAWS IoT Greengrass Groupを作成します。

```
$ export MODEL_S3_URI=[your S3 uri]
$ aws cloudformation create-stack --stack-name Bluegrass --capabilities CAPABILITY_NAMED_IAM --template-body "$(aws cloudformation package --template-file deploy/greengrass.yaml --s3-bucket ${BLUEGRASS_S3_BUCKET_NAME})" \
--parameters \
ParameterKey="ModelS3Uri",ParameterValue="${MODEL_S3_URI}" \
ParameterKey="S3BucketName",ParameterValue="${BLUEGRASS_S3_BUCKET_NAME}" \
ParameterKey="Core01CertificateArn",ParameterValue="${CERT_ARN1}" \
ParameterKey="Core02CertificateArn",ParameterValue="${CERT_ARN2}"
```

ここで`MODEL_S3_URI`はSageMakerで学習したモデルの場合、下記のようになります。
`s3://sagemaker-xxxxxx/blueoil-sagemaker-2020-XX-XX-XX-XX-XX-XXZ/output/converted/output.tar.gz`

#### AWS IoT Greengrass Groupの確認
下記のようにAWS IoTコンソールにて作成されたGreengrass Groupが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/3d9ee28c-08ef-8b96-82f1-d74f0dec8dde.png)

以上でCloud側の構築は完了しました。次にDeviceのセットアップを行なっていきましょう。

### Step4: Deviceのセットアップ
#### DE10-Nanoのセットアップ
公式に提供されているmicroSDカードイメージ([DE10-Nano-Cloud-Nativeイメージ](http://download.terasic.com/downloads/cd-rom/de10-nano/DE10-Nano-Cloud-Native.zip))を書き込んだSDカードを挿入し、下記のようにEthernet Cable及び電源を接続してデバイスを起動します。起動後にNW設定等を実施し、固定アドレスでssh loginができるように設定します。設定方法の詳細は[AWS Blog](https://aws.amazon.com/jp/blogs/startup/using-fewer-resources-to-run-deep-learning-inference-on-intel-fpga-edge-devices/)を参照してください。
![de10nano.jpeg](https://d2908q01vomqb2.cloudfront.net/0286dd552c9bea9a69ecb3759e7b94777635514b/2020/09/29/Image-from-iOS-7-1024x576.jpeg)


下記のコマンドでGreengrassのインストール及びBlueoil用の推論環境のセットアップを実施します。

```
$ ansible-playbook -i [IP address of Core1],[IP address of Core2] ansible/playbook.yml
```


次に各デバイス毎に証明書の配置を行います。これにてセットアップは完了です。

```
$ export CERT_ID1=$(echo ${CERT_ARN1} | sed -e 's/.*\///g')
$ export THING_ARN1=[thing arn of your Core1]
$ export IOT_HOST=$(aws iot describe-endpoint --endpoint-type iot:Data-ATS --query 'endpointAddress' --output=text)
$ export GG_HOST=$(echo ${IOT_HOST} | sed -e 's/.*-ats/greengrass-ats/g')

$ ansible-playbook -i [IP address of Core1], ansible/playbook_certs_deploy.yml --extra-vars "cert_id=${CERT_ID1} thing_arn=${THING_ARN1} iot_host=${IOT_HOST} gg_host=${GG_HOST}"
```

#### AWS IoT コンソールから接続確認
セットアップが完了すると、下記のようにAWS IoTのコンソール上から接続が確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/c43cbaf8-97f8-d862-1039-f23ac8c5b410.png)

### Step5: Application Deployと推論実施
#### AWS IoT コンソールからDeploy
いよいよApplicationをデプロイしていきます！
AWS IoTのコンソール上から対象のGroupを選択し、ActionsからDeployの実行を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/b8ba002e-ff02-15d9-fa86-12f6950af88a.png)

`In progress` -> `Successfully completed`となればDeploy完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/a9ebb41d-62ec-b7fd-c9db-1d69e6c87e7b.png)

#### Device上の推論アプリケーションの確認
では、先ほどデプロイした推論アプリケーションを確認してみましょう。
`http://<deviceのIP address>:8080`にブラウザ経由でアクセスすることで、カメラから取得した画像のリアルタイムな推論結果を下記のように確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/11e15891-5fa7-68f0-649a-961c5f652896.png)

#### 推論結果の確認
次に、推論した結果がCloudに連携されていることを確認してみましょう。
AWS IoT コンソールの`Test`というところをClickして、MQTT clientを立ち上げ、`inference/result`というtopicをsubscribeします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/89139b58-97bb-52c7-1d21-1ae6b71f53f1.png)

すると、下記の様に、推論結果のJSONを確認することができます。
今回のサンプルアプリケーションでは、Cloud側には推論結果のメタデータのみを送信するようにしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/5f2d7623-4206-28dc-264a-f82fcafafe42.png)
以上で推論の実施及びデータの収集が確認できました。
これにて全ての構築作業が完了しました。

### Step6: 別のモデルをデプロイする
では、最後に別のモデルをデプロイしてみましょう。Greengrassを利用する大きな利点の一つが、デバイスを直接操作することなく、動作するアプリケーションやモデルの更新ができることです。コンソールから下記のように新たなモデルをデプロイすることができます。

デプロイしたいデバイスのGroupにアクセスし、`リソース`の`Machine Lerning`タブから`リソースの編集`をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/ecc8112a-2972-4130-705d-fce25811fec1.png)

`S3のモデルをアップロード`を選択し、`変更`をクリックして新たなモデルのS3のパスを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/1165969a-c0b4-48fa-a013-6a63f27541c5.png)

変更後下記の更新をクリックし、Group定義を更新します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79348/825493dc-5fbd-4d8c-d005-2b72397fa3ae.png)

更新後、[Step5: Application Deployと推論実施](#step5-application-deployと推論実施)と同様に再度Deployを実行することで、デバイスに新たなモデルがデプロイされ、Applicationが再起動して新たな推論が実行されます。

このように全ての作業をCloud側で完結することができます！
実際にProductionレベルでデバイスを利用する際は、たくさんのデバイスを利用する場合や、直接的にログインできない場合など様々なユースケースがあります。Cloud側で全てが管理可能であるということは運用において非常に大きなメリットになりそうですね！

## まとめ
Greengrassを使ってFPGAデバイス上で量子化されたDeep Learningモデルを利用した推論アプリケーションを動かしました！
さらには、デバイスの管理や動作するモデル/アプリケーションの更新、推論データのクラウド側への蓄積などの運用基盤についても構築しました！
今回のように公開済みのCloudFormationテンプレートを利用することで、複雑なシステムも簡単にデプロイすることができますし、AWSなどが提供しているIoT系のサービスを利用すれば、自前でデバイス管理システムを用意しなくても、エッジデバイスの管理やデータ収集などの基盤を簡単に構築することができます。
皆さんもぜひ、ご自身の手で、今回のGreengrass x Blueoilを試してみてください！