Amazon Web Services ブログ

EI 対応の TensorFlow 1.12 で利用できる柔軟性のある新型 Python API を使用して、Amazon Elastic Inference で TensorFlow モデルをデプロイする

Amazon Elastic Inference (EI) が、TensorFlow 1.12 の最新バージョンのサポートを開始しました。EI は、新しくなってさらに使いやすくなった Python API 関数である EIPredictor を備え、EI アクセラレーターを使用してTensorFlow モデルをデプロイします。EI で TensorFlow モデルを実行するのに、TensorFlow Serving に代わって、この新しい Python API 関数を推論スクリプト内で使用できるようになりました。EIPredictor では簡単な実験が可能で、EI の有無でのパフォーマンスも比較できます。このブログ記事では、EIPredictor を使用して EI にモデルをデプロイする方法を説明します。

まず、この背景から始めましょう。Amazon Elastic Inference は re:Invent 2018 で発表された新しい機能です。EI は、スタンドアロンの GPU インスタンスを使用するよりも、コスト効果が非常に優れた新しい方法を提供し、深層学習推論ワークロードを高速化します。EI を使用すると、任意の Amazon SageMaker または Amazon EC2 インスタンスタイプにアクセラレーターをアタッチでき、GPU の高速化によってもたらされる低いレイテンシー、高スループットといった利点を、極めて低いコスト (最大75%) で実現できます。EI では、TensorFlow、Apache MXNet、および ONNX モデルをデプロイし、推論を実行できます。

TensorFlow Serving を使用して、EI でモデルを実行する

Amazon EI の立ち上げ時に、EI 対応の TensorFlow Serving を導入しました。このため、コードを変更する必要がなくなり、EI アクセラレーターでの TensorFlow モデルの実行が簡単になりました。トレーニング済みの TensorFlow SavedModel を使用して、EI 対応の TensorFlow Serving を使用したモデルサーバーを起動し、TensorFlow Serving を呼び出すだけです。EI 対応の TensorFlow Serving は、通常の TensorFlow Serving と同じ API を使用します。唯一の違いは、エントリポイントが AmazonEI_TensorFlow_Serving_v1.12_v1 と呼ばれる異なるバイナリである点だけです。サーバーの起動に使用できるコマンドの例を次に示します。

$ AmazonEI_TensorFlow_Serving_v1.12_v1 --model_name=ssdresnet --model_base_path=/tmp/ssd_resnet50_v1_coco --port=9000

EI 対応の TensorFlow Serving は、AWS Deep Learning AMI にあります (チュートリアルはこちら)。またはこの Amazon S3 バケットからパッケージをダウンロードし、独自のカスタム Amazon Machine Image (AMI)、または Docker コンテナ内に構築します。EI 対応の TensorFlow Serving では、TensorFlow の高性能モデルに対応するシステムの拡張が可能で、EI とシームレスに連携できます。また、アクセラレーターの検出の自動化、TLS 暗号化を使用してのネットワーク上の推論リクエストの保護、AWS Identity and Access Management (IAM) ポリシーを使ったアクセス制限などが実現できます。

EIPredictor を使用して、EI でモデルを実行する

EIPredictor はトレーニング済みモデルに対して推論を実行する、シンプルな Python 関数です。EI 対応の TensorFlow 内で利用できる、新しい API 関数です。  Deep Learning AMI でも入手可能で、Amazon S3 を使用してダウンロードできます。次のようにして、EIPredictor を使用します。

  • EIPredictor は、保存したモデルまたは frozen graph とともに使用できます。TF Predictor と同様のものです。これらのモデル形式で EIPredictor を使用するには、EI のドキュメントを参照してください。
  • Use_ei フラグ (にデフォルト設定されている) を使用して、EI の使用を無効にすることができます。これは、モデルが EI アクセラレーションの有無にかかわらず、どのように機能するかを確認するのに役立ちます。
  • EIPredictor は TensorFlow Estimator からでも作成できます。トレーニング済み Estimator として、まず SavedModel をエクスポートします。詳細については、SavedModel ドキュメントを参照してください。使用例 :
    saved_model_dir = estimator.export_savedmodel(my_export_dir, serving_input_fn)
    ei_predictor = EIPredictor(export_dir=saved_model_dir)
    //Once the EIPredictor is created, inference is done using the following:
    output_dict = ei_predictor(feed_dict)

次のコードサンプルは、この機能で使用できるパラメータを示しています。

ei_predictor = EIPredictor(model_dir,
           signature_def_key=None,
           signature_def=None,
           input_names=None,
           output_names=None,
           tags=None,
           graph=None,
           config=None,
           use_ei=True)

output_dict = ei_predictor(feed_dict)

EI Predictor を使ってモデルを実行する例

これは、EI Predictor を使った Single Shot Detector (SSD) モデルで、ResNet の実行を試すことができる例です。この例では、EI アクセラレーターを使用して、EC2 インスタンスを起動したと想定しています。この例では、最新の Deep Learning AMI をここで使用します。

  1. 最初の手順は、TensorFlow Elastic Inference Note を有効にすることです。これは Deep Learning AMI に固有のものです。EI 対応の TensorFlow ライブラリを独自のカスタム AMI で構築した場合には、この手順は必要ありません。Python 2 か、Python 3 のTensorFlow EI 環境のどちらかを選択できます。この例では Python 2 を使います。
    $ source activate amazonei_tensorflow_p27
  2. Amazon S3 から ResNet SSD モデルの例をダウンロードします。
    $ curl -O https://s3-us-west-2.amazonaws.com/aws-tf-serving-ei-example/ssd_resnet.zip
  3. モデルを解凍します。繰り返しますが、既にモデルがある場合は、この手順を省略できます。
    $ unzip ssd_resnet.zip -d /tmp
  4. 3 匹の犬の写真を、現在のディレクトリにダウンロードします。
    $ curl -O https://raw.githubusercontent.com/awslabs/mxnet-model-server/master/docs/images/3dogs.jpg
  5. Vim などのテキストエディタを開き、次の推論スクリプトを貼り付けます.ファイルを ssd_resnet_predictor.py として保存します。
    from __future__ import absolute_import
    from __future__ import division
    from __future__ import print_function
    
    import os
    import sys
    import numpy as np
    import tensorflow as tf
    import matplotlib.image as mpimg
    import time
    from tensorflow.contrib.ei.python.predictor.ei_predictor import EIPredictor
    
    tf.app.flags.DEFINE_string('image', '', 'path to image in JPEG format')
    FLAGS = tf.app.flags.FLAGS
    if(FLAGS.image == ''):
      print("Supply an Image using '--image [path/to/image]'")
      exit(1)
    coco_classes_txt = "https://raw.githubusercontent.com/amikelive/coco-labels/master/coco-labels-paper.txt"
    local_coco_classes_txt = "/tmp/coco-labels-paper.txt"
    #Coco ラベルのダウンロード
    os.system("curl -o %s -O %s" % (local_coco_classes_txt, coco_classes_txt))
    #デフォルトの予測数を設定する
    NUM_PREDICTIONS = 20
    #リストへ coco ラベルを読み取る
    with open(local_coco_classes_txt) as f:
      classes = ["No Class"] + [line.strip() for line in f.readlines()]
    
    
    def main(_):
      #ユーザーから与えられたテスト画像を読み込む
      img = mpimg.imread(FLAGS.image)
      #バッチサイズを 1 に設定する
      img = np.expand_dims(img, axis=0)
      #EIPredictor Input を設定する
      ssd_resnet_input = {'inputs': img}
    
      print('Running SSD Resnet on EIPredictor using specified input and outputs')
      #これは、指定された入力と出力を使用する EIPredictor インターフェースです
      eia_predictor = EIPredictor(
          #保存したモデルのあるモデルディレクトリ
          model_dir='/tmp/ssd_resnet50_v1_coco/1/',
          #Predictor への入力を指定する
          input_names={"inputs": "image_tensor:0"},
          #Predictor のテンソルに出力名を指定する
          output_names={"detection_classes": "detection_classes:0", "num_detections": "num_detections:0",
                        "detection_boxes": "detection_boxes:0"},
      )
    
      pred = None
      #予測を繰り返します。最初の推論リクエストが完了するまでに、数秒かかる場合があります
      for curpred in range(NUM_PREDICTIONS):
        if(curpred == 0):
          print("The first inference request loads the model into the accelerator and can take several seconds to complete.Please standby!")
        #タイマーをスタートさせる
        start = time.time()
        #ここが実際に推論が起こるところです
        pred = eia_predictor(ssd_resnet_input)
        print("Inference %d took %f seconds" % (curpred, time.time()-start))
    
      #プレディクターの出力から、入力画像で検出されたオブジェクトの数を取得する
      num_detections = int(pred["num_detections"])
      print("%d detection[s]" % (num_detections))
      #出力からクラス ID を取得する
      detection_classes = pred["detection_classes"][0][:num_detections]
      #クラス ID を coco ラベルのクラス名にマッピングする
      print([classes[int(i)] for i in detection_classes])
    
      print('Running SSD Resnet on EIPredictor using default Signature Def')
      #これは、デフォルトの Signature Def を使用する EIPredictor インターフェースです
      eia_predictor = EIPredictor(
          #保存したモデルのあるモデルディレクトリ
          model_dir='/tmp/ssd_resnet50_v1_coco/1/',
      )
    
      #予測を繰り返します。最初の推論リクエストが完了するまでに、数秒かかる場合があります
      for curpred in range(NUM_PREDICTIONS):
        if(curpred == 0):
          print("The first inference request loads the model into the accelerator and can take several seconds to complete.Please standby!")
        #タイマーをスタートさせる
        start = time.time()
        #ここが実際に推論が起こるところです
        pred = eia_predictor(ssd_resnet_input)
        print("Inference %d took %f seconds" % (curpred, time.time()-start))
    
      #プレディクターの出力から、入力画像で検出されたオブジェクトの数を取得する
      num_detections = int(pred["num_detections"])
      print("%d detection[s]" % (num_detections))
      #出力からクラス ID を取得する
      detection_classes = pred["detection_classes"][0][:num_detections]
      #クラス ID を coco ラベルのクラス名にマッピングする
      print([classes[int(i)] for i in detection_classes])
    
    
    if __name__ == "__main__":
      tf.app.run()
    
  6. 推論スクリプトを実行します。
    $ python ssd_resnet_predictor.py --image 3dogs.jpg

結論

TensorFlow モデルをコスト効率の高いアクセラレーターで実行するには、好みに応じて 2 つの便利な方法があります。ぜひ試してみて、amazon-ei-feedback@amazon.comまで感想をお聞かせください。

こちらで Elastic Inference をさらに学ぶことができます。Linux インスタンス用ユーザーガイドも参照してください。EI に Deep Learning AMI を使用する手順については、AWS Deep Learning AMI のドキュメントを参照してください。

著者について


Dominic Divakaruni は、Amazon Elastic Inference のプロダクトマネージャーです。生産に関する機械学習アプリケーションを拡張するサービスを構築しています。余暇には、息子と一緒にドラムをたたいたり、車の修理を楽しんでいます。