AWS IoT Greengrass V2 / SageMaker によるエッジAI推論の紹介

AWS IoT Greengrass V2 / SageMaker によるエッジAI推論の紹介

Takahiro Iwasa
(岩佐 孝浩)
Takahiro Iwasa (岩佐 孝浩)
21 min read
Greengrass IoT SageMaker

AWS IoT Greengrass V2 / SageMaker の紹介を目的とした勉強会、「AWS IoT Greengrass V2/SageMaker によるエッジAI推論の紹介」を開催しました。

プレゼンテーションの内容を共有し、 AWS を使用したエッジ推論についての理解の機会を提供できればと思います。この投稿のサンプルは、 GitHub リポジトリから取得できます。

前提条件

参加者は以下が期待されます:

  • AWS でのエッジ AI 推論に興味がある
  • 機械学習と AWS の基本知識

この投稿の目標:

  • AWS 上でのエッジ AI 推論の概要把握
  • IoT Greengrass V2, SageMaker, SageMaker Neo, SageMaker Edge Manager を使用したデモ

エッジコンピューティング概要

Edge computing is a distributed computing paradigm that brings computation and data storage closer to the sources of data. This is expected to improve response times and save bandwidth.

エッジコンピューティングには次のような多くの利点があります。

  • 低レイテンシー(特に自動運転などのリアルタイムアプリケーションにとって重要)
  • セキュリティリスク低減
  • 通信コスト低減

ただし、エッジコンピューティングにはいくつかの欠点もあります。

  • 垂直スケーリングが難しい(クラウド環境では簡単)
  • キャパシティプランニングが必要
  • インフラ管理

エッジコンピューティングは AI だけでなく、 CDN にも利用されています。

エッジ AI の現在の課題の1つは、コンピューティング能力です。現代の機械学習と深層学習のアルゴリズムは多くのハイパーパラメーターを持ち、相当なコンピューティングリソースを必要とします。エッジ AI 向けに ML/DL モデルを最適化するためのさまざまな取り組みが行われています。1

IoT Greengrass V2

概要

AWS IoT Greengrass is an open source Internet of Things (IoT) edge runtime and cloud service that helps you build, deploy and manage IoT applications on your devices.

IoT Greengrass V2 の特徴:

  • Windows 2, Linux (Ubuntu, Raspberry Pi OS など) での実行が可能
  • x86, ARM の両方のアーキテクチャに対応
  • Lambda 関数サポート
  • エッジ AI 推論のための Deep Learning Runtime (DLR) サポート

概念

IoT Greengrass V2 の概念には以下が含まれます。

  • Greengrass Core デバイス
    • エッジで Greengrass Core を実行します。
    • AWS IoT Things として登録されます。
    • AWS と通信します。
  • Greengrass クライアントデバイス
    • MQTT を使用して Greengrass Core デバイスと通信します。
    • AWS IoT Things として登録されます。
    • Greengrass Core デバイスがメッセージブローカーとして使用される場合、他のクライアントデバイスと通信します。
  • Greengrass コンポーネント
    • Greengrass Core デバイス上で実行されるソフトウェアです。
    • ユーザーによって実装および登録されます。
  • デプロイメント
    • AWS から Greengrass Core デバイスへの指令です。

SageMaker

SageMaker 概要

SageMaker は AWS での機械学習用マネージドサービスです。ユーザーは17の組み込みアルゴリズムを使用して、少ないコードで機械学習を実行できます 3TensorFlow や PyTorch などの主要なディープラーニングフレームワークをサポートしています 4

SageMaker は以下の種類の推論エンドポイントを提供しています。

SageMaker Neo 概要

Neo is a capability of Amazon SageMaker that enables machine learning models to train once and run anywhere in the cloud and at the edge.

With a single click, SageMaker Neo optimizes the trained model and compiles it into an executable. The compiler uses a machine learning model to apply the performance optimizations that extract the best available performance for your model on the cloud instance or edge device.

SageMaker Edge Manager 概要

Amazon SageMaker Edge Manager provides model management for edge devices so you can optimize, secure, monitor, and maintain machine learning models on fleets of edge devices such as smart cameras, robots, personal computers, and mobile devices.

この投稿の例では、モニタリング機能は使用しません。

エッジ AI 推論の例

概要

この例では、 EC2 インスタンスをエッジデバイスとみなします。

以下でエッジ推論を確認できます。

  1. セットアップ
    1. AWS リソース準備
    2. 訓練スクリプト実装
    3. 推論スクリプト実装
  2. SageMaker
    1. SageMaker 訓練
    2. SageMaker Neo でモデルのコンパイル
    3. SageMaker Edge Manager でモデルのパッケージング
  3. Greengrass
    1. Greengrass Core セットアップ
    2. エッジ推論用 Greengrass コンポーネント登録
    3. Greengrass コンポーネントのデプロイ
  4. テスト

AWS リソース準備

以下の AWS リソースを事前に準備してください。各リソースの詳細については、サンプルの GitHub リポジトリで提供している CloudFormation テンプレートを確認してください。

リソース名前説明
IAM ユーザーgreengrass-core-setup-userGreengrass Core セットアップに使用
IAM ロールsagemaker-execution-roleSageMaker 実行ロール
IAM ロールGreengrassV2TokenExchangeRoleGreengrass Core ロール
S3sagemaker-ml-model-artifacts-{account_id}-{region}ML モデル用のバケット

以下のコマンドを実行して、これらのリソースを作成できます。

% aws cloudformation deploy --template-file ./cfn.yaml --stack-name greengrass-sample --capabilities CAPABILITY_NAMED_IAM

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - greengrass-sample

訓練スクリプト実装

この例では、 PyTorch の事前学習済み VGG16 モデルを使用しているため、次のコマンドでインストールしてください。

% pip install torch torchvision

以下の内容で training.py を作成してください。このファイルは SageMaker で実行されます。

import argparse
import os
from datetime import datetime

import torch
from torchvision import models


def fit(model: torch.nn.modules.Module) -> None:
    # Write some training codes...
    pass


def save(model: torch.nn.modules.Module, path: str) -> None:
    suffix = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
    path = os.path.join(path, f'model-{suffix}.pt')
    # If you use `model.state_dict()`, SageMaker compilation will fail.
    torch.save(model, path)


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser()

    # hyperparameters sent by the client are passed as command-line arguments to the script.

    # input data and model directories
    parser.add_argument('--model_dir', type=str)
    parser.add_argument('--sm_model_dir', type=str, default=os.environ.get('SM_MODEL_DIR'))
    parser.add_argument('--train', type=str, default=os.environ.get('SM_CHANNEL_TRAIN'))
    parser.add_argument('--test', type=str, default=os.environ.get('SM_CHANNEL_TEST'))

    args, _ = parser.parse_known_args()
    return args


if __name__ == '__main__':
    args = parse_args()
    vgg16 = models.vgg16(pretrained=True)
    fit(vgg16)
    save(vgg16, args.sm_model_dir)

SageMaker 用の訓練スクリプトを実装する際は、ローカル環境でのアプローチと同じように進めることができます。ただし、以下の点に留意する必要があります。詳細については、公式ドキュメントをご参照ください。

  • 実行時引数
  • 環境変数
  • 訓練データセット
    • FILE モードを使用している場合、訓練データセットは S3 から SageMaker インスタンスに自動的にコピーされます。
    • PIPE モードを使用している場合、ストリーミングされた訓練データの読み取りのためのコードを実装する必要があります。詳細については、公式ドキュメントをご参照ください。
  • モデル保存ディレクトリ
    • SM_MODEL_DIR 環境変数は、訓練済みモデルを保存するために使用できます。このディレクトリに保存されたモデルは、自動的に S3 にアップロードされます。

上記の例では訓練コードは含まれていません。

推論スクリプト実装

SageMaker Neo でコンパイルされたモデルは、 Deep Learning Runtime (DLR) を使用してロードできます。 次のコマンドで DLR をインストールしてください。

% pip install dlr

以下の内容で inference.py を作成してください。このファイルは Greengrass Core で実行されます。

import argparse
import glob
import json
import os
import time

import numpy as np
from dlr import DLRModel


def load_model() -> DLRModel:
    return DLRModel('/greengrass/v2/work/vgg16-component')


def load_labels() -> dict:
    path = os.path.dirname(os.path.abspath(__file__))
    # See https://storage.googleapis.com/download.tensorflow.org/data/imagenet_class_index.json
    path = os.path.join(path, 'imagenet_class_index.json')
    with open(path, 'r') as f:
        labels = json.load(f)
    return labels


def iter_files(path: str) -> str:
    path = path[:-1] if path.endswith('/') else path
    files = glob.glob(f'{path}/*.npy')
    for file in files:
        yield file


def predict(model: DLRModel, image: np.ndarray) -> np.ndarray:
    return model.run(image)[0]


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser()
    parser.add_argument('--test_dir', type=str)
    parser.add_argument('--interval', type=int, default=300)
    args, _ = parser.parse_known_args()
    return args


def start(model: DLRModel, path: str, labels: dict) -> None:
    for file in iter_files(path):
        image = np.load(file)
        y = predict(model, image)
        index = int(np.argmax(y))
        label = labels.get(str(index), '')
        print(f'Prediction result of {file}: {label}')


if __name__ == '__main__':
    args = parse_args()
    print(f'args: {args}')
    model = load_model()
    labels = load_labels()

    if args.interval == 0:
        start(model, args.test_dir, labels)
    else:
        while True:
            start(model, args.test_dir, labels)
            print(f'Sleep in {args.interval} seconds...')
            time.sleep(args.interval)

PyTorch は入力データとして torch.Tensor を想定していますが、 SageMaker Neo でコンパイルされたモデルは numpy.ndarray を想定していることに注意が必要です。 PyTorch の事前学習済みモデルの入力フォーマットに関する情報については、公式ドキュメントをご参照ください。

この例では、 Greengrass Core に配置された /greengrass/v2/work/vgg16-inference-component/images/*.npy に対して --interval 引数で指定された間隔で推論が実行されます。 AWS 提供のコンポーネント aws.greengrass.DLRImageClassificationaws.greengrass.DLRObjectDetection もご参照ください。

推論用 Greengrass コンポーネントを登録するには、推論スクリプトと関連するファイルを含む ZIP ファイルを S3 バケットにアップロードしてください。

% cd vgg16-inference-component
% zip vgg16-inference-component-1.0.0.zip inference.py imagenet_class_index.json
% aws s3 cp vgg16-inference-component-1.0.0.zip s3://{YOUR_BUCKET}/artifacts/

SageMaker 訓練

SageMaker Python SDK を以下のコマンドでインストールしてください。

% pip install sagemaker

ローカル環境で SageMaker の訓練ジョブをキューに入れるには、以下の内容で training_job.py を作成してください。もちろん、 SageMaker のマネジメントコンソールを使用することもできます。

from sagemaker.pytorch import PyTorch

AWS_ACCOUNT_ID = '123456789012'
S3_BUCKET = f's3://sagemaker-ml-model-artifacts-{AWS_ACCOUNT_ID}-ap-northeast-1’


if __name__ == '__main__':
    pytorch_estimator = PyTorch(
        entry_point='training.py',
        source_dir='./',
        role='sagemaker-execution-role',
        instance_count=1,
        instance_type='ml.m5.large',
        framework_version='1.10.0',
        py_version='py38',
        output_path=f'{S3_BUCKET}/models/trained',
        hyperparameters={}
    )
    pytorch_estimator.fit()

スクリプトを実行後、実行ログに請求情報が表示されます。例えば、以下のログでは255秒が請求されます。

% python training_job.py

…

2022-02-16 15:41:56 Uploading - Uploading generated training model
2022-02-16 15:42:56 Completed - Training job completed
ProfilerReport-1645025749: NoIssuesFound
Training seconds: 255
Billable seconds: 255

モデルは S3 バケットに保存されます (output/model.tar.gz)。この後、 SageMaker Neo を使用してコンパイルおよび最適化します。

SageMaker Neo でモデルのコンパイル

SageMaker のコンパイルジョブを作成してください。この例では、ジョブが完了するのに約4分かかりました。

以下に従って入力設定を指定してください。

フィールド
アーティファクトmodel.tar.gzのS3 URI
入力設定モデルの入力形状
フレームワークPyTorch
フレームワークのバージョン1.8

入力形状については、公式ドキュメントに次のように記載されています。

All pre-trained models expect input images normalized in the same way, i.e. mini-batches of 3-channel RGB images of shape (3 x H x W), where H and W are expected to be at least 224.

出力設定は任意の値を指定してください。

AWS 公式ドキュメントには情報が見当たりませんでしたが、 AWS フォーラムでコメントがありました。

ページの下部に以下のように記載されています。

The library libdlr.so compiled by Sagemaker Neo with target rasp4b returns “ELF-64 bit LSB pie executable, ARM aarch64, version 1 (GNU/Linux), dynamically linked,

以下の項目はデフォルトのままで OK です。

SageMaker Edge Manager でモデルのパッケージング

SageMaker Edge パッケージングジョブを作成してください。

SageMaker Neo コンパイルジョブ名を入力してください。

デプロイのプリセットとして Greengrass V2 コンポーネントを選択した場合、コンパイルされたモデルは以下のようになります。

  • SageMaker Edge によって Greengrass V2 コンポーネントとして登録されます。
  • Greengrass Core 上の /greengrass/v2/work/vgg16-component/ に保存されます。

Greengrass Core セットアップ

エッジデバイス上に Greengrass Core をセットアップしてください。この投稿では、 Ubuntu 20.04.03 を実行している EC2 インスタンスを使用しています。 Greengrass Core のインストール手順についての詳細は、公式ドキュメントをご参照ください。

MQTT over TLS は、8883 ポートを使用します。ポートが開いていない場合は、手動セットアップが必要です。

以下のコマンドで JDK をインストールしてください。

% sudo apt install default-jdk
% java -version

Greengrass Core 用のユーザーとグループを追加してください。

% sudo useradd --system --create-home ggc_user
% sudo groupadd --system ggc_group

AWS クレデンシャルを設定してください。

% # Set the credential of greengrass-core-setup-user already provisioned by CloudFormation
% export AWS_ACCESS_KEY_ID=
% export AWS_SECRET_ACCESS_KEY=

以下のコマンドで Greengrass Core をインストールしてください。

% curl -s https://d2s8p88vqu9w66.cloudfront.net/releases/greengrass-nucleus-latest.zip > greengrass-nucleus-latest.zip
% unzip greengrass-nucleus-latest.zip -d GreengrassInstaller && rm greengrass-nucleus-latest.zip
% sudo -E java -Droot="/greengrass/v2" -Dlog.store=FILE \
  -jar ./GreengrassInstaller/lib/Greengrass.jar \
  --aws-region ap-northeast-1 \
  --thing-name MyGreengrassCore \
  --thing-group-name MyGreengrassCoreGroup \
  --thing-policy-name GreengrassV2IoTThingPolicy \
  --tes-role-name GreengrassV2TokenExchangeRole \
  --tes-role-alias-name GreengrassCoreTokenExchangeRoleAlias \
  --component-default-user ggc_user:ggc_group \
  --provision true \
  --setup-system-service true

Greengrass Core サービスを確認してください。メモリの使用状況を考慮すると、2GB 以上のメモリを搭載していると良さそうです。

% sudo systemctl status greengrass
● greengrass.service - Greengrass Core
     Loaded: loaded (/etc/systemd/system/greengrass.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2022-02-16 05:09:16 UTC; 1 day 2h ago
   Main PID: 1454 (sh)
      Tasks: 51 (limit: 2197)
     Memory: 734.2M
     CGroup: /system.slice/greengrass.service

この投稿では自動リソースプロビジョニングを使用しているため、以下の AWS リソースが自動的にプロビジョニングされています。代わりに、手動リソースプロビジョニングでセットアップすることも可能です。

リソース名前
ThingMyGreengrassCore
Thing GroupMyGreengrassCoreGroup
Thing PolicyGreengrassV2IoTThingPolicy
Token Exchange RoleGreengrassV2TokenExchangeRole
Token Exchange Role AliasGreengrassCoreTokenExchangeRoleAlias

エッジ推論用 Greengrass コンポーネント登録

推論用 Greengrass コンポーネントを登録するために recipe.yaml を作成してください。コンポーネントのレシピに関する詳細は、公式ドキュメントをご参照ください。

RecipeFormatVersion: '2020-01-25'

ComponentName: vgg16-inference-component
ComponentVersion: 1.0.0
ComponentDescription: Inference component for VGG16
ComponentPublisher: Iret

# Arguments to be passed.
ComponentConfiguration:
  DefaultConfiguration:
    Interval: 60

# Dependencies which will be installed with this component.
ComponentDependencies:
  variant.DLR:
    VersionRequirement: ">=1.6.5 <1.7.0"
    DependencyType: HARD
  vgg16-component:
    VersionRequirement: ">=1.0.0"
    DependencyType: HARD

Manifests:
- Name: Linux
  Platform:
    os: linux
  Lifecycle:
    Run:
      RequiresPrivilege: true
      Script: |
        . {variant.DLR:configuration:/MLRootPath}/greengrass_ml_dlr_venv/bin/activate
        python3 -u {artifacts:decompressedPath}/vgg16-inference-component-1.0.0/inference.py --interval {configuration:/Interval} --test_dir {work:path}/images/
  Artifacts:
  - Uri: s3://sagemaker-ml-model-artifacts-123456789012-ap-northeast-1/artifacts/vgg16-inference-component-1.0.0.zip
    Unarchive: ZIP

上記の例の Interval は推論間隔を意味します。

ComponentDependencies でコンポーネントの依存関係を指定できます。この例では、以下が指定されている必要があります。

  • variant.DLR
    • SageMaker Neo でコンパイルされたモデルのロードに必要です。詳細については、公式ドキュメントをご参照ください。
    • Greengrass Core デバイス上の /greengrass/v2/work/variant.DLR/greengrass_ml/greengrass_ml_dlr_venv に Python の仮想環境があります。
  • vgg16-component
    • SageMaker Neo によってコンパイルされたモデル
    • SageMaker Edge Manager によって登録されています。

recipe.yaml を作成したら、 Greengrass コンポーネントを作成してください。

コンポーネントをデプロイする際、 Greengrass Core は S3 からアーティファクトをダウンロードして解凍します。 Greengrass Core はアーティファクトのチェックサムを検証するため、アーティファクトが直接上書きされると、コンポーネントのステータスが破損します。 詳細については、公式ドキュメントをご参照ください。

Greengrass コンポーネントのデプロイ

このステップでは、デプロイするコンポーネントを選択できます。

My components では、以下を指定してください。 vgg16-inference-component のレシピには vgg16-component に対する HARD 依存関係があるため、指定しなくても vgg16-component がインストールされます。

名前説明
vgg16-componentSageMaker Edge Manager によってパッケージングされた VGG16 コンポーネント
vgg16-inference-component推論コンポーネント

Public components では、以下を指定してください。 vgg16-inference-component のレシピには variant.DLR に対する HARD 依存関係があるため、指定しなくても variant.DLR がインストールされます。

名前説明
variant.DLRモデルのロードに必要なコンポーネント
aws.greengrass.NucleusGreengrass Core に必要なコンポーネント

設定変更はせず Next を押してください。

設定変更はせず Next を押してください。

レビュー後、 Deploy を押してコンポーネントのデプロイを開始してください。

テスト

Greengrass Core で推論をテストするには、以下の手順を実行してください。

  1. 事前に訓練された PyTorch モデルは、入力形状として4次元テンソル (N, C, H, W) を想定しているため、推論用の画像を Numpy Array に変換します。詳細については、公式ドキュメントをご参照ください。
  2. 変換したデータを Greengrass Core デバイスの /greengrass/v2/work/vgg16-inference-component/images/ に転送します。
  3. Greengrass Core デバイス上の /greengrass/v2/logs/vgg16-inference-component.log ファイルを確認します。

以下の Python スクリプトを使用して、画像を Numpy Array に変換できます。

import argparse
import os
from PIL import Image

import numpy as np
import torch
from torchvision import transforms


def load_image_to_tensor(path: str) -> torch.Tensor:
    preprocess = transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
    ])

    img = Image.open(path)
    tensor_3d = preprocess(img)
    return torch.unsqueeze(tensor_3d, 0)


def save(tensor: torch.Tensor, path: str) -> None:
    np.save(path, tensor.numpy())


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser()
    parser.add_argument('image', type=str)
    args, _ = parser.parse_known_args()
    return args


if __name__ == '__main__':
    args = parse_args()
    image = args.image

    tensor = load_image_to_tensor(image)
    save(tensor, os.path.basename(image) + '.npy')

以下のコマンドでスクリプトを実行してください。

% python convert_img_to_npy.py <YOUR_IMAGE>

変換された Numpy Array データを Greengrass Core デバイスに転送してください。その後、 /greengrass/v2/logs/vgg16-inference-component.log で推論結果を確認できます。

% scp xxx.jpg.npy <GREENGRASS_HOST>://greengrass/v2/work/vgg16-inference-component/images/
% ssh <GREENGRASS_HOST>
% tail -f /greengrass/v2/logs/vgg16-inference-component.log

…

2022-02-19T21:32:21.993Z [INFO] (Copier) vgg16-inference-component: stdout. Prediction result of /greengrass/v2/work/vgg16-inference-component/images/keyboard.jpg.npy: ['n03085013', 'computer_keyboard']. {scriptName=services.vgg16-inference-component.lifecycle.Run.Script, serviceName=vgg16-inference-component, currentState=RUNNING}
2022-02-19T21:32:22.257Z [INFO] (Copier) vgg16-inference-component: stdout. Prediction result of /greengrass/v2/work/vgg16-inference-component/images/pen.jpg.npy: ['n03388183', 'fountain_pen']. {scriptName=services.vgg16-inference-component.lifecycle.Run.Script, serviceName=vgg16-inference-component, currentState=RUNNING}

この投稿では、以下の2つの画像を使用しました。

下の推論結果は computer_keyboard でした。

下の推論結果は fountain_pen でした。


Footnotes

  1. https://cacm.acm.org/magazines/2022/1/257437-shrinking-artificial-intelligence/fulltext CACM. Shrinking Artificial Intelligence.

  2. https://aws.amazon.com/about-aws/whats-new/2021/11/aws-iot-greengrass-support-windows-devices/

  3. https://docs.aws.amazon.com/sagemaker/latest/dg/common-info-all-im-models.html

  4. https://docs.aws.amazon.com/sagemaker/latest/dg/frameworks.html

Takahiro Iwasa
(岩佐 孝浩)

Takahiro Iwasa (岩佐 孝浩)

Software Developer at KAKEHASHI Inc.
処方箋データ収集基盤の設計・開発・運用に携わっています。