AWS IoT Greengrass V2とSageMakerを活用したエッジAI推論の紹介
はじめに
先日、「AWS IoT Greengrass V2/SageMaker によるエッジAI推論の紹介」という勉強会を開催し、AWS IoT Greengrass V2 と SageMaker を利用したエッジ AI 推論について解説しました。本ブログでは、そのプレゼン内容を共有し、AWS を使ったエッジ推論の可能性を探るための実践的な手順を解説します。
サンプルコードは、GitHub リポジトリからアクセスできます。
前提条件
対象読者
本記事は以下の読者を対象としています。
- AWS 上でのエッジ AI 推論に興味がある 方。
- 機械学習と AWS サービスの基本的な理解 を持っている方。
目的
- AWS を使用したエッジ AI 推論の基本を理解する。
- IoT Greengrass V2、SageMaker、SageMaker Neo、SageMaker Edge Manager などのツールを活用する方法を学ぶ。
エッジコンピューティングとは
エッジコンピューティングは、データをそのソースに近い場所で処理することにより、遅延を削減し、帯域幅の使用を最小化する分散コンピューティングパラダイムです。
利点
- 低遅延:自動運転車のようなリアルタイムアプリケーションに最適。
- セキュリティ向上:データの転送中の露出を制限。
- 通信コストの削減:中央集権型データセンターへの依存を低減。
課題
- スケーリング:クラウドと比較してバーティカルスケーリングが柔軟でない。
- インフラ管理:キャパシティプランニングと保守が必要。
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 は、機械学習モデルの構築、トレーニング、デプロイを行うための完全マネージドサービスです。TensorFlow や PyTorch などの主要な深層学習フレームワークをサポートしています。
次の記事もご参考ください。
SageMaker Neo
Neo は、エッジデバイスのために機械学習モデルを最適化し、互換性と性能を向上させます。
SageMaker Edge Manager
このサービスは、エッジデプロイされた機械学習モデルの管理と監視を行い、モデルの最適化やセキュリティ機能を提供します。
実装:エッジ AI 推論
以下は、エッジデバイスとして EC2 インスタンス を使用してエッジ推論を実行する方法を示す例です。このプロセスでは、エッジ推論パイプラインを設定、トレーニング、デプロイ、およびテストするための一連の手順を含みます。
エッジ推論を実装する手順
-
セットアップ
- AWS リソースを準備 :必要な IAM ロール、S3 バケット、およびその他の AWS リソースを設定。
- トレーニングスクリプトを実装 :モデルをトレーニングするスクリプトを作成。
- 推論スクリプトを実装 :エッジデバイスでモデル推論を行うスクリプトを開発。
-
SageMaker 使用
- SageMaker でトレーニング : SageMaker を活用してモデルをトレーニング。
- SageMaker Neo でモデルをコンパイル :トレーニング済みモデルをエッジデバイス用に最適化。
- SageMaker Edge Manager でモデルをパッケージ :モデルを Greengrass Core にデプロイ可能な形に準備。
-
Greengrass 設定
- Greengrass Core をセットアップ : EC2 インスタンスに Greengrass Core をインストールして設定。
- Greengrass コンポーネントを登録 :エッジ推論用の Greengrass コンポーネントを作成して登録。
- Greengrass コンポーネントをデプロイ :コンポーネントを Greengrass Core デバイスにデプロイ。
-
テスト
- テストデータを変換 :エッジモデルに互換性のある形式(例: Numpy arrays )に入力データを準備。
- テストデータをデプロイ :テストデータを Greengrass Core デバイス上の指定フォルダーに転送。
- 結果を確認 : Greengrass Core のログで推論結果を確認。
AWS リソースの準備
事前に以下の AWS リソース を準備してください。詳細については、GitHub リポジトリ内の CloudFormation テンプレートをご参照ください。
リソース | 名前 | 説明 |
---|---|---|
IAM ユーザー | greengrass-core-setup-user | Greengrass Core のセットアップ用 |
IAM ロール | sagemaker-execution-role | SageMaker 実行ロール |
IAM ロール | GreengrassV2TokenExchangeRole | Greengrass 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)
torch.Tensor
フォーマットとして想定していますが、SageMaker Neo でコンパイルされたモデルは numpy.ndarray
フォーマットを必要とします。入力形状の詳細については、PyTorch pre-trained models documentationをご参照ください。
推論コンポーネントの登録
推論スクリプトと関連ファイルを 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.
出力設定は、要件に基づいて指定してください。
rasp4b
を Target device
として選択した場合、モデルは 64 ビットアーキテクチャ用にコンパイルされます。そのため、これらのモデルは Raspberry Pi の 32 ビット OS など、32 ビットのオペレーティングシステムでは読み込むことができません。この場合、64 ビット OS を使用する必要があります。
この点については、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
自動リソースプロビジョニング
この投稿では 自動リソースプロビジョニングを使用しています。必要に応じて、手動プロビジョニングガイドを使用してリソースを手動でプロビジョニングすることも可能です。
リソース | 名前 |
---|---|
Thing | MyGreengrassCore |
Thing Group | MyGreengrassCoreGroup |
Thing Policy | GreengrassV2IoTThingPolicy |
Token Exchange Role | GreengrassV2TokenExchangeRole |
Role Alias | GreengrassCoreTokenExchangeRoleAlias |
エッジ推論用の 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 上で推論をテストするには、以下の手順を実行します。
-
入力データの準備:
事前学習済みの PyTorch モデルは、入力として 4 次元テンソル(N, C, H, W)
を必要とします。画像を Numpy 配列に変換します。詳細については、公式ドキュメントをご参照ください。 -
データを Greengrass Core に転送:
変換したデータを Greengrass Core デバイスの/greengrass/v2/work/vgg16-inference-component/images/
ディレクトリに転送します。 -
推論ログを確認:
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}
以下の画像の推論結果は次のとおりです。
- 画像:
computer_keyboard
- 画像:
fountain_pen
まとめ
AWS IoT Greengrass V2 と SageMaker の統合により、開発者はエッジデバイスにインテリジェントな機械学習機能を効率的に展開できます。本投稿では、エッジ AI 推論のライフサイクル(モデルのトレーニング、最適化、Greengrass Core デバイスへのデプロイ、テスト)を解説しました。
Happy Coding! 🚀