Amazon Web Services ブログ

AWS DeepLens の拡張機能: 独自のプロジェクトの構築

AWS DeepLens では、ディープラーニング、Internet of Things (IoT) などの新しいテクノロジーを知ることができるだけでなく、現実的な問題を解決する革新的なシステムを構築することができます。このデバイスおよびサービスには、定義済みのプロジェクトセットが付属しており、プロジェクトをすばやく実行することができます。また、開発者が初心者か経験豊富かに関係なく、同様にエキサイティングなプロジェクトを新しく構築 (および共有) できるようにするオープンプラットフォームとして設計されています。

このブログ投稿では、独自のプロジェクトを構築するプロセスについて説明します。以下に一部のステップを紹介します。

  • ディープラーニングモデルのトレーニング (Amazon SageMaker を使用)
  • AWS DeepLens エッジデバイス上で実行できるように、トレーニング済みのモデルを最適化する
  • モデルをロードし、ビデオストリーム上で推論を実行できるように、AWS Lambda 関数を開発する
  • AWS Greengrass を使用して AWS Lambda 関数を AWS DeepLens にデプロイする
  • コマンドを送信し、推論を出力できるように、エッジ AWS Lambda 関数をクラウドに接続する
  • 完成

ディープラーニングモデルのトレーニング (Amazon SageMaker を使用)

Amazon SageMaker は、データサイエンスで手間のかかる作業を排除する新しいサービスです。このサービスには、推奨のエンジンから Alexa や Amazon Go、Amazon Robotics などの機械学習に基づくシステムまで、Amazon.com のビジネスのさまざまな側面で、Amazon データサイエンティストの長年の経験が反映されています。

優れた機械学習モデルを設計、構築する全体のプロセスは非常に興味深いですが、今回のブログ投稿では割愛します。実際、DeepLens デバイスにディープラーニングモデルをデプロイして再接続し、その出力を活用するフローで生産性を高めれば、現実の新しい問題を解決するために新たなモデルの構築にますます多くの時間を費やすことになります。

機械学習の初心者が、データサイエンティストのエキスパートと同じ開始ポイントに立つには、Amazon SageMaker でノートブックインスタンスを作成する際に利用できる Jupyter ノートブック内のノートブックセットから始めることをお勧めします。たとえば、以下は、転移学習のプロセスと、推論エンドポイントホスティング向けに微調整されたディープラーニングモデルを構築、トレーニング、デプロイするために Amazon SageMaker SDK を使用するフローの両方を示すノートブックです。

このブログ投稿では、プロセスの次のステップに進められるように、Amazon S3 におけるモデルアーティファクトの保存に焦点を当てています。

以下は、SageMaker のトレーニングジョブを使用してトレーニングされたモデルの例です。このトレーニングで使用した出力ディレクトリやハイパーパラメータなどがあります。

ハイパーパラメータは、モデルの使用方法を理解するのに役立ちます。たとえば、カラーイメージ (3=RGB チャネル) を処理するには、image_shape (3,224,224) に基づき、224*224 ピクセルにリサイズする必要があります。また、今後のトレーニングジョブで、トレーニングデータ (epochs>2) を超える実行、learning_rate の変更、num_training_samples 数の増加など、詳細にモデルを設定するのにも役立ちます。

AWS DeepLens エッジデバイス上で実行できるように、トレーニング済みのモデルを最適化する

実際のディープラーニングシステムにおけるこのステップの重要な例として、モデルのハードウェアを DeepLens デバイスに最適化するステップがあります。前のステップでは、モデルのトレーニング用にほぼ無制限のクラウドリソースがありましたが、モデルを推論に使用する場合は、スケーリングなど、新しいビジネス制約に直面します。クラウドでは、GPU ベースのインスタンスの大規模なクラスターを容易に取得できるため、数時間のトレーニングで複数のことを実行できます。しかし、モデルをエッジデバイスにデプロイする場合は、チップセット (CPU/GPU)、メモリ、ネットワーク帯域幅、安定性などの点から、デバイスの仕様を検討する必要があります。DeepLens デバイスは、高フレームレートで高解像度のビデオストリームのモデルを複数実行する上で十分強力ですが、ほとんどの場合、それほど高いスペックは必要ないでしょう。そこで、インテルは、MXNet モデルのアーティファクトを取り、DeepLens デバイスに搭載されているインテルのチップボードに最適化するライブラリを開発しました。このライブラリは、前のステップでモデルをインポートした後、DeepLens コンソールを使用してモデルをデプロイするときに自動的に実行されます。

モデルのトレーニングが終了したら、DeepLens にインポートする際にトレーニングジョブ ID を指定することができます。(モデルをインポートするには、Sagemaker と DeepLens のいずれも、同じ AWS リージョンに存在する必要があります。)

モデルをロードし、ビデオストリーム上で推論を実行できるように、AWS Lambda 関数を開発する

IoT デバイス (ここでは AWS DeepLens カメラ) 上で動作している AWS Greengrass コアでは、デプロイされている AWS Lambda Python 関数を実行することができます。次回以降の投稿では、Greengrass Group、Core、および登録デバイスを作成するステップについて説明します。「入門ガイド」については、Greengrass ドキュメントをご覧ください。AWS DeepLens は、これらのステップのほとんどで自動化されています。ここでは、Lambda 関数を開発して、登録、構成されたデバイスにデプロイする方法について説明します。

それぞれの Lambda 関数において、以下のステップを行います。

  • モデルのロード
  • フレームのキャプチャ
  • フレームでのモデル推論の実行
  • 推論結果の解析
  • MQTT トピックに結果を発行する

これらのステップの例をいくつか見ていきましょう。

モデルのロード

AWS DeepLens デバイスは、ヘルパーライブラリ awscam に事前にインストールされています。このライブラリを使用すると、Lambda 関数のロジックに統一しやすくなります。このロジックでは、モデルのロードなど、最も一般的なステップで行われます。次の例で示すように、モデル XML ファイルへのパスとモデルのコンテキスト (GPU/CPU) を指定する必要があります。モデルの読み込みとバインディングはライブラリで自動的に行われます。

import awscam
modelPath = "/opt/awscam/artifacts/mxnet_deploy_CaltechTransfer_224_FP16_FUSED.xml"
# Load model to GPU (use {"GPU": 0} for CPU)
mcfg = {"GPU": 1}
model = awscam.Model(modelPath, mcfg)

このステップは、内部の推論関数 (例: 以下の greengrass_infer_image_run) 外で定義する必要があります。このステップは、モデルがディスクからメモリおよび GPU にロードされるまでに数秒かかる場合があるため、1 回だけ実行する必要があります。

フレームのキャプチャ

OpenCV (cv2) は、ディープラーニングモデルの (リサイズ) 前と (ボックスとラベルの描画) 後の画像を操作するために使用されます。トレーニングの入力仕様はモデルごとに異なるため、最初のステップとして、キャプチャされたフレームを適切なサイズにリサイズします。

import cv2
input_width = 224
input_height = 224
ret, frame = awscam.getLastFrame()
# Resize frame to fit model input requirement
frameResize = cv2.resize(frame, (input_width, input_height))

フレームでのモデル推論の実行

ヘルパーライブラリ awscam は、predict コマンドがシンプルな doInference 関数に含まれているため、この Lambda 関数の部分を簡潔にすることができます。

# リサイズされたフレームでモデルの推論を実行する
inferOutput = model.doInference(frameResize)

推論結果の解析

ヘルパーライブラリは、従来のいくつかのコンピュータビジョン問題に対応しています。たとえば、ラベルでオブジェクトを分類する「分類」、オブジェクトのラベルと境界ボックスを提供する、オブジェクト検出およびローカリゼーションの「ssd」 (「single-shot-multibox-detector」)、イメージをリージョンに分割し、ピクセルレベルの出力を提供する「セグメンテーション」 (例: スタイル転送) などがあります。次の例は、一般的な「ssd」タイプのモデルを対象としています。

modelType = "ssd"
parsed_results = model.parseResult(modelType, inferOutput)['ssd']

MQTT トピックに結果を発行する

最後に、モデルの出力を送信します。このロジックは、モデルのタイプと、解決を試みる問題のタイプによって異なります。シンプルな出力としては、以下の例で示す Dog/Cat または Hotdog/Not Hotdog などの画像のラベルがあります。他の出力タイプには、顔検出モデルから顔認識に送信される画像内の顔の切り抜きや、ビデオストリーム内のオブジェクトの境界ボックス、画像/ビデオのニューラルスタイル転送などがあります。最もかんたんにデバイスからの出力を送信するには、次のコードに示すように、Greengrass クライアントを使用して MQTT を経由します。このチャネルは、テキストメッセージだけでなく、テキストエンコード後の画像 (境界ボックスやラベルなどを含む) にも対応しています。

# Greengrass コアの sdk クライアントを作成する
client = greengrasssdk.client('iot-data')
iotTopic = 'iot-data'
for obj in parsed_results:
    if obj['prob'] > max_threshold:
        label = '{{"label":"{}", "prob":{:.2f}%'.format(outMap[obj['label']], obj['prob']*100 )
        client.publish(topic=iotTopic, payload = label)

AWS Greengrass を使用して AWS Lambda 関数を DeepLens にデプロイする

Greengrass では、主な 2 つのモード (固定およびオンデマンド) で Lambda 関数を実行することができます。AWS DeepLens モデルでは、Lambda 関数の起動時に固定オプションを使用することが推奨されています。ディープラーニングモデルが大きい場合 (数百 MB から数 GB) は時間がかかります。推論がトリガーされる頻度や時間は以下のモードで制御することができます。

  • 高フレームレート – フレーム間に「スリープ」がない無限ループで関数を実行します。フレームレートは、モデル推論の速度、前処理および後処理に応じて、10~30 FPS に設定することができます。
  • 特定フレームレート – フレーム間に定義済みの「スリープ」を含む無限ループで関数を実行します。顔検出などのタスクでは、1 秒あたり 1~5 フレームレートで実行することができ、リージョン内のすべての顔を検出するのに必要な機能が搭載されています。関数の推論のレートを制御するには、Timer を使用します。
    インポートタイマーのスレッディング
    def greengrass_infer_image_run():
        # 画像の読み取り
        # 前処理
        # 画像のモデル推論を実行する
        # 結果を解析する
        # 結果を出力する
        
        # この関数が 0.5 秒で再実行されるように非同期でスケジュールする
        Timer(0.5, greengrass_infer_image_run).start()
  • オンデマンド – この関数は、手動または別のイベントからトリガーする場合に実行します。固定の関数を実行している場合でも、イベントハンドラーを使用して実行できます。この例では、各イベントの推論をトリガーする方法を表していますが、イベントのパラメータを解析して、イベントハンドラーから関数を制御する (モデルまたはモデルモードの切替えなど) こともできます。
    インポートタイマーのスレッディング
    def greengrass_infer_image_run():
        # 画像の読み取り
        # 前処理
        # 画像のモデル推論を実行する
        # 結果を解析する
        # 結果を出力する
        
    def lambda_handler(event, context):
        client.publish(topic=iotTopic, payload="About to call image inference function")
        greengrass_infer_image_run()
    return

Lambda 関数の Greengrass スケルトンをかんたんに取得するには、AWS Lambda コンソールで Greengrass のいずれかの設計図を使用します。パッケージにすでに Greengrass クライアントライブラリが含まれているため、できれば greengrassHelloWorld を使用します。この設計図を使用して Lambda 関数を作成し、この関数の Python コードをお客様のコードに置き換え、新しく作成した Lambda 関数を発行します。これで、プロジェクトに追加し、AWS DeepLens コンソールからデバイスにデプロイできるようになりました。

コマンドを送信し、推論出力を受信できるように、ローカル Lambda 関数をクラウドに接続する

以前に説明したように、Lambda 関数では、MQTT プロトコルを介して IoT トピックスに書き出すことができます。組み込みプロジェクトで使用されているデフォルトの出力トピックは以下のとおりです。

iotTopic = '$aws/things/{}/infer'.format(os.environ['AWS_IOT_THING_NAME'])

これは AWS DeepLens コンソールまたは AWS IoT コンソールをご覧ください。同じ形式を使用するか、前の例の iotTopic = ‘iot-data’ など、Lambda 関数のトピック名を使用することもできます。

lambda_handler を使用して、オンデマンドモードで Lambda 関数をトリガーできることも説明しました。これを行うには、IoT コンソールを使用して、IoT クラウドと Lambda 関数の間にサブスクリプションをセットアップする必要があります。たとえば、Lambda 関数のインバウンドサブスクリプションとアウトバウンドサブスクリプション (ImageInferenceTest バージョン 19) は以下のとおりです。

この例では、トピック「trigger-image-inference」をリッスンすると、エッジ Lambda 関数は、イベントがこのトピックに発行される度にトリガーされます。もう一方のサブスクリプションでは、エッジ Lambda から出力メッセージを表示し、クラウド側で確認することができます。たとえば、AWS IoT ルールエンジンを使用して、特定のメッセージ (例: 「顔が検出されました」) をフィルタリングし、他のクラウドサイド の Lambda 関数や、Amazon Elasticsearch Service、Amazon Kinesis などに送信することができます。また、DeepLens デバイスでもサブスクリプションが有効になるように必ずサブスクリプションをデプロイ (「Actions」の下) してください。

また、Lambda 関数のログや、Greengrass の主要情報 (またはデバッグ) のログを表示できるように、デバイスの Greengrass グループの Amazon CloudWatch ログを有効にすることをお勧めします。詳細については、「Greengrass グループコンソールページ」の「設定」セクションで確認できます。

まとめ

今回は、AWS DeepLens で使用できるオープンプロジェクト環境を拡張する方法について説明しました。次回以降は、同様の構造を使用してブロックを構築しながら、このフロー上で構築されている例を紹介していきます。以下の図は、既存のプロジェクトを拡張するか (モデルの改善または Lambda 関数の変更)、一から新しいプロジェクトを作成するステップを示します。


その他の参考資料

AWS DeepLens を拡張して AWS Lambda で SMS 通知を送信する方法について説明します。


今回のブログの投稿者について

Guy Ernest 氏は Amazon AI のプリンシパルソリューションアーキテクトです。マインドシェア構築の戦略に携わり、Amazon の AI、Machine Learning、ディープラーニングのユースケースのクラウドコンピューティングプラットフォームを幅広く使用しています。時間がある時は家族との時間を楽しみ、面白くちょっと恥ずかしい話しを集めたり、Amazon や AI の今後について話し合ったりしています。