AWS DeepLensを使用したイメージ分類のプロジェクト作成 (Part2)

NetOne USA
藤田 雄介

Part1では、AWS DeepLensの初期設定を実施し、今回使用するデータの準備を行った後に、Amazon SageMakerによりモデルの作成及びトレーニングの実施を行いました。今回掲載するPart2では、残りのStep4~Step5をご紹介します。作成したモデルとAWS DeepLensの連携を実施するためのAWS Lambdaファンクションを作成し、AWS DeepLensで自身のデータを元にオブジェクト認識が出来るように構成します。

Step 4. AWS Lambdaファンクションの作成

 AWS Lambdaコンソール内で[Create Function]をクリックし、関数を作成します。BluePrintを選択した後に[greengrass]で検索を行い、[greengrass-hello-world]を選択します。関数名とロールを指定して作成を行います。

14

以下のサイトの内容をベースにしてAWS Lambdaファンクションの記載を行います。全体的な動作としては、AWS DeepLensで入力したイメージに対してモデルによりオブジェクト分類を実施し、Probabilityの高い上位5つのオブジェクトをピックアップし、ピックアップしたオブジェクトのラベルとProbabilityをAWS IoTの対象トピックへメッセージとして送出します。また、ストリームに対しては、最も上位のオブジェクトの名称を表示します。

https://aws.amazon.com/jp/blogs/machine-learning/build-your-own-object-classification-model-in-SageMaker-and-import-it-to-DeepLens/

https://aws.amazon.com/jp/blogs/machine-learning/dive-deep-into-aws-DeepLens-lambda-functions-and-the-new-model-optimizer/

数カ所、自身が作成した環境に合わせて変更するべき箇所が存在します。

1. “model_name”変数に対して、作成したモデル名を入力します。モデル名は作成したモデルのプレフィックス部分となり、今回の場合には、”image-classification”となります。尚、”model_type”は”classification”のままになります。

2. 本コード内に、mo.optimizeモジュールを使用している箇所があり、その箇所に対して、自身が使用したEpochs数を入力します。今回は20となります。これはモデルオプティマイザーと呼ばれており、MXNetフレームワークをIntel GPUで処理ができるように変換するものとなります。

3. オブジェクトの名称を示すためのラベルリストを作成して、テキストファイルとして保存しておきます。そのラベルファイル名を入力します。今回は、label.txtとして以下のように作成しました。10番目と11番目には自身で取り込んだイメージ用のラベルを記載しています。

15

[greengrassHelloWorld.py]内のコードを全て削除し、以下の内容を入力します。

#Insert imageclassification_lambda.py
# Copyright Amazon AWS DeepLens, 2017
#

import os
#Insert imageclassification_lambda.py
#
# Copyright Amazon AWS DeepLens, 2017
#

import os
import greengrasssdk
from threading import Timer
import time
import awscam
import cv2
import mo
from threading import Thread

# Creating a greengrass core sdk client
client = greengrasssdk.client('iot-data')

# The information exchanged between IoT and clould has
# a topic and a message body.
# This is the topic that this code uses to send messages to cloud
iotTopic = '$aws/things/{}/infer'.format(os.environ['AWS_IOT_THING_NAME'])
jpeg = None
Write_To_FIFO = True

class FIFO_Thread(Thread):
    def __init__(self):
        ''' Constructor. '''
        Thread.__init__(self)


    def run(self):
        fifo_path = "/tmp/results.mjpeg"
        if not os.path.exists(fifo_path):
            os.mkfifo(fifo_path)
        f = open(fifo_path,'w')
        client.publish(topic=iotTopic, payload="Opened Pipe")
        while Write_To_FIFO:
            try:
                f.write(jpeg.tobytes())
            except IOError as e:
                continue  

def greengrass_infinite_infer_run():
    try:
        input_width = 224
        input_height = 224
        model_name = "image-classification"
        error, model_path = mo.optimize(model_name,input_width,input_height, aux_inputs={'--epoch': 20})
        # The aux_inputs is equal to the number of epochs and in this case, it is 20
        # Load model to GPU (use {"GPU": 0} for CPU)
        mcfg = {"GPU": 1}
        model = awscam.Model(model_path, mcfg)

        client.publish(topic=iotTopic, payload="Model loaded")
        model_type = "classification"

        with open('label.txt', 'r') as f:
             labels = [l.rstrip() for l in f]

        topk = 5
        results_thread = FIFO_Thread()
        results_thread.start()

        # Send a starting message to IoT console
        client.publish(topic=iotTopic, payload="Inference is starting")

        doInfer = True
        while doInfer:
            # Get a frame from the video stream
            ret, frame = awscam.getLastFrame()
            # Raise an exception if failing to get a frame
            if ret == False:
                raise Exception("Failed to get frame from the stream")

            # Resize frame to fit model input requirement
            frameResize = cv2.resize(frame, (input_width, input_height))

            # Run model inference on the resized frame
            inferOutput = model.doInference(frameResize)

            # Output inference result to the fifo file so it can be viewed with mplayer
            parsed_results = model.parseResult(model_type, inferOutput)
            top_k = parsed_results[model_type][0:topk]

            msg = '{'
            prob_num = 0
            for obj in top_k:
                if prob_num == topk-1:
                    msg += '"{}":{:.2f}'.format(labels[obj["label"]], obj["prob"]*100)
                else:
                    msg += '"{}":{:.2f},'.format(labels[obj["label"]], obj["prob"]*100)
                prob_num += 1
            msg += "}"  

            client.publish(topic=iotTopic, payload = msg)

            cv2.putText(frame, labels[top_k[0]["label"]], (10,500), cv2.FONT_HERSHEY_SIMPLEX, 4, (255, 165, 20), 4)
            global jpeg
            ret,jpeg = cv2.imencode('.jpg', frame)

    except Exception as e:
        msg = "myModel Lambda failed: " + str(e)
        client.publish(topic=iotTopic, payload=msg)

    # Asynchronously schedule this function to be run again in 15 seconds
    Timer(15, greengrass_infinite_infer_run).start()

# Execute the function above
greengrass_infinite_infer_run()

完了したら、[Publish New Version]を選択し、公開を行います。

Step 5. AWS DeepLensに対するデプロイ

 AWS DeepLensコンソールに移動し[Model]をクリックし、[Import Model]を実行します。”External trained model”を選択し、必要な項目を入力します。[Model artifact path]はモデル(.paramファイル等)を保存したパスになるため、今回は”s3://deeplens-sagemaker-image/deeplens”となります。[Model Framework] は今回はMXNetを使用しているため、MXNetを選択します。[Import Model]をクリックします。

16

[Projects]の項目から[Create New Project]をクリックし、[Create New Blank Project]を選択します。Project Nameを付与した後に、Modelとして上記で作成したモデル(own-image-classification)を追加し、Functionとして作成したファンクション(Own-Image-classification)の追加を実施します。

17

その後、AWS DeepLensにデプロイを実施します。[Devices]画面上で確認できる”MQTT Topic”の値を確認しておきます。AWS IoTサービスコンソールを起動します。[Subscription topic]の項目に、AWS DeepLensの “MQTT Topic”の値を入力し、[Subscribe to topic]をクリックします。
うまく動作すると、AWS IoT内で想定されたメッセージがJSON形式で受信できます。

18

プロジェクトストリームに関しては以下のようになり、左側に認識したオブジェクトに対してラベルが表示されていることが分かります。 ※ ストリーミングに関しては若干不安定な場合も見受けられ、デプロイ前に一旦再起動が必要な場合もあります。

19

AWS IoTに発行されたメッセージを活用して、他のAWSサービスとの連携を実施することも可能となります。

まとめ

 今回はオブジェクト認識モデルを使用して人物の認識を実施したため、精度は高くありません。また、AWS DeepLensを使用してカスタマイズを行うためには、ある程度の時間を要します。冒頭にも記載しましたが、本手順を参照することで、Deep Learningに経験の無い人が初回実施する際にも、環境構成の時間を短縮し、より多くの時間を次のフェーズの様々な応用に充てることが出来るようになることを期待しています。これにより、より多くの人がDeep Learningを活用することが出来ればと考えています。

関連記事

AWS DeepLensを使用したイメージ分類のプロジェクト作成 (Part1)
AWS DeepLensを使用したイメージ分類のプロジェクト作成 (Part2)

執筆者プロフィール

藤田 雄介
ネットワンシステムズ株式会社所属。CCIE #8777、VMware vExpert 2013-2017獲得。2016年からシリコンバレーに活動拠点を移し、インフラ系の知識をベースに機械学習等の技術を活用した取り組みを米国スタートアップ企業と共に実施する、技術系ビジネスデベロップメントとして活動中。

イベント/レポート

pagetop