AWS IoT Greengrass V2とSageMakerを活用したエッジAI推論の紹介

AWS IoT Greengrass V2とSageMakerを活用したエッジAI推論の紹介

岩佐 孝浩
岩佐 孝浩
20 min read
Greengrass IoT SageMaker

はじめに

先日、「AWS IoT Greengrass V2/SageMaker によるエッジAI推論の紹介」という勉強会を開催し、AWS IoT Greengrass V2 と SageMaker を利用したエッジ AI 推論について解説しました。本ブログでは、そのプレゼン内容を共有し、AWS を使ったエッジ推論の可能性を探るための実践的な手順を解説します。

サンプルコードは、GitHub リポジトリからアクセスできます。

前提条件

対象読者

本記事は以下の読者を対象としています。

  • AWS 上でのエッジ AI 推論に興味がある 方。
  • 機械学習と AWS サービスの基本的な理解 を持っている方。

目的

  • AWS を使用したエッジ AI 推論の基本を理解する。
  • IoT Greengrass V2SageMakerSageMaker NeoSageMaker Edge Manager などのツールを活用する方法を学ぶ。

エッジコンピューティングとは

エッジコンピューティングは、データをそのソースに近い場所で処理することにより、遅延を削減し、帯域幅の使用を最小化する分散コンピューティングパラダイムです。

利点

  • 低遅延:自動運転車のようなリアルタイムアプリケーションに最適。
  • セキュリティ向上:データの転送中の露出を制限。
  • 通信コストの削減:中央集権型データセンターへの依存を低減。

課題

  • スケーリング:クラウドと比較してバーティカルスケーリングが柔軟でない。
  • インフラ管理:キャパシティプランニングと保守が必要。

Edge AI Architecture

AWS IoT Greengrass V2

概要

AWS IoT Greengrass は、エッジアプリケーションのデプロイおよび管理のために設計されたオープンソースの IoT エッジランタイムおよびクラウドサービスです。

機能

  • Linux および Windows を含むクロスプラットフォームのサポート。
  • x86 および ARM アーキテクチャ との互換性。
  • 統合された Lambda 関数Deep Learning Runtime (DLR)

コンセプト

IoT Greengrass V2 のアーキテクチャは、以下の主要コンポーネントを中心に構成されています。

  • Greengrass Core Devices :

    • エッジで Greengrass Core ソフトウェアを実行する主要なコンピュートデバイスとして機能。
    • AWS IoT Things として登録。
    • AWS クラウドサービスとの通信をサポート。
  • Greengrass Client Devices :

    • MQTT プロトコル を介して Greengrass Core Devices に接続。
    • AWS IoT Things として登録。
    • Greengrass Core Device をメッセージブローカーとして使用する場合、他のクライアントデバイスと通信可能。
  • Greengrass Components :

    • Greengrass Core Devices 上で実行されるソフトウェアモジュールを表す。
    • ユーザーによってカスタマイズおよび登録され、機能を拡張。
  • デプロイ :

    • Greengrass Core Devices への構成およびコンポーネントの配布を AWS によって管理。

このモジュラーアプローチにより、スケーラブルで柔軟なエッジコンピューティングが可能になり、IoT Greengrass V2 は多様な IoT アプリケーションに最適です。詳細については、Key concepts for AWS IoT Greengrassをご参照ください。

Amazon SageMaker とそのエコシステム

SageMaker の概要

Amazon SageMaker は、機械学習モデルの構築、トレーニング、デプロイを行うための完全マネージドサービスです。TensorFlowPyTorch などの主要な深層学習フレームワークをサポートしています。

次の記事もご参考ください。

SageMaker Neo

Neo は、エッジデバイスのために機械学習モデルを最適化し、互換性と性能を向上させます。

SageMaker Edge Manager

このサービスは、エッジデプロイされた機械学習モデルの管理と監視を行い、モデルの最適化やセキュリティ機能を提供します。

実装:エッジ AI 推論

以下は、エッジデバイスとして EC2 インスタンス を使用してエッジ推論を実行する方法を示す例です。このプロセスでは、エッジ推論パイプラインを設定、トレーニング、デプロイ、およびテストするための一連の手順を含みます。

エッジ推論を実装する手順

  1. セットアップ

    • AWS リソースを準備 :必要な IAM ロール、S3 バケット、およびその他の AWS リソースを設定。
    • トレーニングスクリプトを実装 :モデルをトレーニングするスクリプトを作成。
    • 推論スクリプトを実装 :エッジデバイスでモデル推論を行うスクリプトを開発。
  2. SageMaker 使用

    • SageMaker でトレーニング : SageMaker を活用してモデルをトレーニング。
    • SageMaker Neo でモデルをコンパイル :トレーニング済みモデルをエッジデバイス用に最適化。
    • SageMaker Edge Manager でモデルをパッケージ :モデルを Greengrass Core にデプロイ可能な形に準備。
  3. Greengrass 設定

    • Greengrass Core をセットアップ : EC2 インスタンスに Greengrass Core をインストールして設定。
    • Greengrass コンポーネントを登録 :エッジ推論用の Greengrass コンポーネントを作成して登録。
    • Greengrass コンポーネントをデプロイ :コンポーネントを Greengrass Core デバイスにデプロイ。
  4. テスト

    • テストデータを変換 :エッジモデルに互換性のある形式(例: Numpy arrays )に入力データを準備。
    • テストデータをデプロイ :テストデータを Greengrass Core デバイス上の指定フォルダーに転送。
    • 結果を確認 : Greengrass Core のログで推論結果を確認。

AWS リソースの準備

事前に以下の AWS リソース を準備してください。詳細については、GitHub リポジトリ内の CloudFormation テンプレートをご参照ください。

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

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

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

トレーニングスクリプトの実装

依存関係のインストール

この例では、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:
    # トレーニングコードをここに追加
    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')
    # `model.state_dict()` を使用すると、SageMaker コンパイルが失敗します。
    torch.save(model, path)


def parse_args() -> argparse.Namespace:
    # クライアントから送信されたハイパーパラメータはスクリプトのコマンドライン引数として渡されます。
    parser = argparse.ArgumentParser()
    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 公式ドキュメントをご参照ください。

推論スクリプトの実装

依存関係のインストール

モデル推論のために Deep Learning Runtime (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__))
    # 参照: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:
        return json.load(f)


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)

推論コンポーネントの登録

推論スクリプトと関連ファイルを 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

トレーニングジョブをキューに入れるには、以下のようにスクリプト(training_job.py)を作成してジョブを定義します。

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()

モデルは 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.

特定の設定が必要ない場合は、デフォルト設定のまま進めてください。

SageMaker Edge Manager を使用したモデルのパッケージ化

モデルをデプロイ可能な形式にパッケージ化するには、SageMaker Edge Packaging Job を作成します。

SageMaker Neo コンパイルジョブの名前を入力して続行します。

Greengrass V2 component をデプロイプリセットとして選択すると、コンパイルされたモデルは次のように処理されます。

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

Greengrass Core セットアップ

エッジデバイスに Greengrass Core をセットアップします。この例では、Ubuntu 20.04.03 を実行している EC2 インスタンスを使用しています。詳細なインストール手順については、AWS 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 認証情報の設定

# CloudFormation によって作成された greengrass-core-setup-user の認証情報を設定します
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

自動リソースプロビジョニング

この投稿では 自動リソースプロビジョニングを使用しています。必要に応じて、手動プロビジョニングガイドを使用してリソースを手動でプロビジョニングすることも可能です。

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

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

コンポーネントレシピの作成

エッジ推論を有効にするには、recipe.yaml ファイルを作成して Greengrass コンポーネントを登録します。コンポーネントレシピの詳細については、公式ドキュメントをご参照ください。

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/v2/work/variant.DLR/greengrass_ml/greengrass_ml_dlr_venv に配置される Python 仮想環境が含まれます。詳細については、公式ドキュメントをご参照ください。
  • vgg16-component: SageMaker Neo によってコンパイルされ、SageMaker Edge Manager によって登録されたモデルです。

コンポーネントの作成

recipe.yaml の作成が完了したら、Greengrass コンポーネントを作成します。

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

デプロイの設定

Create ボタンを押します。

Name フィールドに vgg16-inference-deployment を入力し、Next ボタンを押します。

デプロイするコンポーネントを選択

  • My Components:

    • vgg16-component: SageMaker Edge Manager によってパッケージ化された VGG16 モデル。
    • vgg16-inference-component: 推論用コンポーネント。
  • Public Components:

    • variant.DLR: モデルのロードに必要。
    • aws.greengrass.Nucleus: Greengrass の基本機能。

コンポーネントの設定

設定変更を行わずに Next を押します。

レビューとデプロイ

デプロイ設定を確認後、Deploy を押してコンポーネントのデプロイを開始します。

テスト

Greengrass Core 上で推論をテストするには、以下の手順を実行します。

  1. 入力データの準備:
    事前学習済みの PyTorch モデルは、入力として 4 次元テンソル (N, C, H, W) を必要とします。画像を Numpy 配列に変換します。詳細については、公式ドキュメントをご参照ください。

  2. データを Greengrass Core に転送:
    変換したデータを Greengrass Core デバイスの /greengrass/v2/work/vgg16-inference-component/images/ ディレクトリに転送します。

  3. 推論ログを確認:
    Greengrass Core デバイスの /greengrass/v2/logs/vgg16-inference-component.log ファイルの推論結果を確認します。

画像を Numpy 配列に変換する Python スクリプト

以下の Python スクリプトを使用して、推論用の画像を準備できます。

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')

スクリプトの実行

スクリプトを使用して画像を Numpy 配列形式に変換します。

python convert_img_to_npy.py <YOUR_IMAGE>

データの転送

変換した Numpy 配列を Greengrass Core デバイスに転送します。

scp xxx.jpg.npy <GREENGRASS_HOST>://greengrass/v2/work/vgg16-inference-component/images/

推論ログの確認

Greengrass Core デバイスに SSH 接続し、推論ログを確認します。

ssh <GREENGRASS_HOST>
tail -f /greengrass/v2/logs/vgg16-inference-component.log

推論結果の例

以下は /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}

以下の画像の推論結果は次のとおりです。

  1. 画像:computer_keyboard

  1. 画像:fountain_pen

まとめ

AWS IoT Greengrass V2SageMaker の統合により、開発者はエッジデバイスにインテリジェントな機械学習機能を効率的に展開できます。本投稿では、エッジ AI 推論のライフサイクル(モデルのトレーニング、最適化、Greengrass Core デバイスへのデプロイ、テスト)を解説しました。

Happy Coding! 🚀

岩佐 孝浩

岩佐 孝浩

Software Developer at KAKEHASHI Inc.
AWS を活用したクラウドネイティブ・アプリケーションの要件定義・設計・開発に従事。 株式会社カケハシで、処方箋データ収集の新たな基盤の構築に携わっています。 Japan AWS Top Engineers 2020-2023