TensorRT5 と NVIDIA T4 GPU を使用した TensorFlow 推論ワークロードの実行

このチュートリアルでは、Google Compute Engine 上で動作する NVIDIA TensorRT5 GPU を使用して、大規模なワークロードに対し、ディープ ラーニングでの推論を行う方法について説明します。

始める前に、次の内容をふまえておいてください。

  • ディープ ラーニングでの推論とは、機械学習プロセスの一段階であり、トレーニング済みモデルを使用して、認識、処理、結果の分類を行うものです。
  • NVIDIA TensorRT は、ディープ ラーニングのワークロードを実行するために最適化されたプラットフォームです。
  • GPU を使用して、機械学習やデータ処理などのデータ集約型ワークロードを高速化します。さまざまな NVIDIA GPU を Compute Engine で利用できます。このチュートリアルでは T4 GPU を使用します。T4 GPU は、ディープ ラーニングで推論を行う際のワークロードに特化して設計されたものです。

目標

このチュートリアルでは、次の手順について説明します。

  • 事前トレーニング済みのグラフを使用したモデルの準備。
  • モデルの推論速度を、異なる最適化モードでテスト。
  • カスタムモデルを TensorRT に変換。
  • マルチゾーン クラスタの設定。次のような構成になります。
    • Google のディープ ラーニング VM イメージ上に構築。イメージには、TensorFlow、TensorFlow Serving、TensorRT5 がプリインストールされます。
    • 自動スケーリングが有効。このチュートリアルでは、GPU の使用率に基づいて自動スケーリングされます。
    • 負荷分散が有効。
    • ファイアウォールが有効。
  • マルチゾーン クラスタでの推論ワークロードの実行。

チュートリアル用の設定のアーキテクチャの概要

料金

このチュートリアルの実施にかかる費用は、セクションによって異なります。

モデルを準備し、推論の速度を複数の最適化速度でテストする場合、見積もり価格は、1 日あたり約 $22.34 になります。この費用の見積もりは、次の仕様に基づいています。

  • VM インスタンス 1 台: n1-standard-8(vCPU: 8、RAM 30 GB)
  • NVIDIA Tesla T4 GPU 1 基

マルチゾーン クラスタを設定する場合の見積もり価格は、1 日あたり約 $154.38 です。この費用の見積もりは、次の仕様に基づいています。

  • VM インスタンス 2 台: n1-standard-16(vCPU: 16、RAM 60 GB)
  • VM インスタンスごとに NVIDIA Tesla T4 GPU 4 基
  • VM インスタンスごとに 100 GB SSD
  • 転送ルール 1 つ

これらの費用は、料金計算ツールを使用して見積もられたものです。

始める前に

プロジェクト設定

  1. Google アカウントにログインします。

    Google アカウントをまだお持ちでない場合は、新しいアカウントを登録します。

  2. GCP プロジェクトを選択または作成します。

    プロジェクト セレクタのページに移動

  3. Google Cloud Platform プロジェクトに対して課金が有効になっていることを確認します。 詳しくは、課金を有効にする方法をご覧ください。

  4. Compute Engine と Cloud Machine Learning API を有効にします。

    APIを有効にする

ツール設定

このチュートリアルで gcloud コマンドラインを使用するには:

  1. gcloud コマンドライン ツールの最新バージョンをインストールするか、最新バージョンに更新します。
  2. デフォルトのリージョンとゾーンを設定します(省略可)。

モデルの準備

このセクションでは、モデルの実行に使用される VM インスタンスの作成について説明します。Tensorflow の公式モデルの一覧からモデルをダウンロードする方法についても説明します。

  1. VM インスタンスを作成します。

    export IMAGE_FAMILY="tf-1-12-cu100"
    export ZONE="us-central1-b"
    export INSTANCE_NAME="model-prep"
    gcloud compute instances create $INSTANCE_NAME \
        --zone=$ZONE \
        --image-family=$IMAGE_FAMILY \
        --machine-type=n1-standard-8 \
        --image-project=deeplearning-platform-release \
        --maintenance-policy=TERMINATE \
        --accelerator="type=nvidia-tesla-t4,count=1" \
        --metadata="install-nvidia-driver=True"
    
  2. モデルを選択します。このチュートリアルでは、ResNet モデルを使用します。ResNet モデルは、TensorFlow にある ImageNet データセットでトレーニングされています。

    ResNet モデルを VM インスタンスにダウンロードするには、次のコマンドを実行します。

    wget -q http://download.tensorflow.org/models/official/resnetv2_imagenet_frozen_graph.pb
    

    ResNet モデルのロケーションを $WORKDIR 変数に保存します。

    export WORKDIR=[MODEL_LOCATION]
    

推論速度テストの実行

このセクションでは、次の手順について説明します。

  • ResNet モデルの設定。
  • 異なる最適化モードでの推論テストの実行。
  • 推論テストの結果の確認。

テストプロセスの概要

TensorRT では、推論の際のワークロードの処理速度を向上させることができますが、その最も大きな要因となっているのが量子化プロセスです。

モデルの量子化とは、モデルにおける重みの精度を下げる処理のことです。たとえば、モデルの重みが FP32 であったとするならば、それを FP16、INT8、さらには INT4 というように精度を下げることができます。この場合、速度(重みの精度)とモデルの正確さを勘案し、妥当な水準を検討することが重要です。TensorFlow にはまさにそのための機能が含まれており、速度と精度の対比に加え、スループット、レイテンシ、ノード変換率、総トレーニング時間などの指標も測定することができます。

手順

  1. ResNet モデルを設定します。モデルを設定するには、次のコマンドを実行します。

    git clone https://github.com/tensorflow/models.git
    cd models
    git checkout f0e10716160cd048618ccdd4b6e18336223a172f
    touch research/__init__.py
    touch research/tensorrt/__init__.py
    cp research/tensorrt/labellist.json .
    cp research/tensorrt/image.jpg ..
    
  2. テストを実行します。このコマンドは、完了するまでにしばらく時間がかかります。

    python -m research.tensorrt.tensorrt \
        --frozen_graph=$WORKDIR/resnetv2_imagenet_frozen_graph.pb \
        --image_file=$WORKDIR/image.jpg \
        --native --fp32 --fp16 --int8 \
        --output_dir=$WORKDIR
    

    ここで

    • $WORKDIR は、ResNet モデルをダウンロードしたディレクトリです。
    • --native 引数は、テストに使用する量子化モードです。
  3. 結果を確認します。テストが完了したら、最適化モードごとに推論結果を比較できます。

    Predictions:
    Precision:  native [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty',     u'lakeside, lakeshore', u'grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus']
    Precision:  FP32 [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty', u'lakeside,   lakeshore', u'sandbar, sand bar']
    Precision:  FP16 [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty', u'lakeside,   lakeshore', u'sandbar, sand bar']
    Precision:  INT8 [u'seashore, coast, seacoast, sea-coast', u'promontory, headland, head, foreland', u'breakwater, groin, groyne, mole, bulwark, seawall, jetty', u'grey         whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus', u'lakeside, lakeshore']
    

    すべての結果を見るには、次のコマンドを実行します。

    cat $WORKDIR/log.txt
    

    パフォーマンス結果のスクリーンショット

    FP32 と FP16 では同一の結果が出ています。したがって、TensorRT の動作に問題がなければ、FP16 から使用すべきでしょう。INT8 では、やや悪い結果になっています。

    さらに、TensorRT5 を使用してモデルを実行すると、次の結果が得られます。

    • FP32 に最適化すると、スループットが 314 fps から 440 fps に 40% 向上します。また、レイテンシは約 30% 短縮され、0.40 ミリ秒から 0.28 ミリ秒になります。
    • 元の TensorFlow グラフから FP16 に最適化すると、速度が 314 fps から 988 fps へと 214% 向上します。また、レイテンシは 0.12 ミリ秒になり、ほぼ 3 分の 1 に短縮されます。
    • INT8 を使用すると、314 fps から 1,524 fps へ、385% 高速化することがわかります。レイテンシは 0.08 ミリ秒に短縮されます。

カスタムモデルの TensorRT への変換

この変換には、INT8 モデルを使用できます。

  1. モデルをダウンロードします。カスタムモデルを TensorRT グラフに変換するには、保存済みのモデルが必要です。保存済みの INT8 ResNet モデルを入手するには、次のコマンドを実行します。

    wget http://download.tensorflow.org/models/official/20181001_resnet/savedmodels/resnet_v2_fp32_savedmodel_NCHW.tar.gz
    tar -xzvf resnet_v2_fp32_savedmodel_NCHW.tar.gz
    
  2. TFTools を使用してモデルを TensorRT グラフに変換します。変換を行うには、次のコマンドを実行します。

    git clone https://github.com/GoogleCloudPlatform/ml-on-gcp.git
    cd ml-on-gcp/dlvm/tools
    python ./convert_to_rt.py \
        --input_model_dir=$WORKDIR/resnet_v2_fp32_savedmodel_NCHW/1538687196 \
        --output_model_dir=$WORKDIR/resnet_v2_int8_NCHW/00001 \
        --batch_size=128 \
        --precision_mode="INT8"
    

    実行すると、$WORKDIR/resnet_v2_int8_NCHW/00001 ディレクトリに INT8 モデルが作成されます。

    すべてが正しく設定されていることを確認するために、推論テストを実行してみます。

    tensorflow_model_server --model_base_path=$WORKDIR/resnet_v2_int8_NCHW/ --rest_api_port=8888
    
  3. モデルを Google Cloud Storage にアップロードします。この手順は、次のセクションで設定するマルチゾーン クラスタからモデルを使用できるようにするために必要です。モデルをアップロードするには、次の手順を実行します。

    1. モデルをアーカイブします。

      tar -zcvf model.tar.gz ./resnet_v2_int8_NCHW/
      
    2. アーカイブをアップロードします。

      export GCS_PATH=<gcs_path>
      gsutil cp model.tar.gz $GCS_PATH
      

      必要な場合は、INT8 のフリーズされたグラフを Google Cloud Storage の次の URL から入手できます。

      gs://cloud-samples-data/dlvm/t4/model.tar.gz
      

マルチゾーン クラスタの設定

クラスタを作成する

Google Cloud Storage プラットフォームにモデルを用意したら、クラスタが作成できます。

  1. インスタンス テンプレートを作成します。インスタンス テンプレートは、新しいインスタンスを作成するのに役立つリソースです。インスタンス テンプレートをご覧ください。

    export INSTANCE_TEMPLATE_NAME="tf-inference-template"
    export IMAGE_FAMILY="tf-1-12-cu100"
    export PROJECT_NAME="your_project_name"
    
    gcloud beta compute --project=$PROJECT_NAME instance-templates create $INSTANCE_TEMPLATE_NAME \
         --machine-type=n1-standard-16 \
         --maintenance-policy=TERMINATE \
         --accelerator=type=nvidia-tesla-t4,count=4 \
         --min-cpu-platform=Intel\ Skylake \
         --tags=http-server,https-server \
         --image-family=$IMAGE_FAMILY \
         --image-project=deeplearning-platform-release \
         --boot-disk-size=100GB \
         --boot-disk-type=pd-ssd \
         --boot-disk-device-name=$INSTANCE_TEMPLATE_NAME \
         --metadata startup-script-url=gs://cloud-samples-data/dlvm/t4/start_agent_and_inf_server_4.sh
    
    • このインスタンス テンプレートには、メタデータ パラメータで指定された起動スクリプトが含まれています。
      • この起動スクリプトは、このテンプレートを使用するすべてのインスタンスで、インスタンス作成中に実行されます。
      • この起動スクリプトによって次の手順が実行されます。
        • インスタンス上の GPU の使用状況をモニタリングするモニタリング エージェントのインストール。
        • モデルのダウンロード。
        • 推論サービスの起動。
      • 起動スクリプトでは、tf_serve.py に推論ロジックが含まれています。今回の例では、TFServe パッケージを元にして、非常に小さな python ファイルを作成しました。
      • 起動スクリプトを表示するには、startup_inf_script.sh をご覧ください。
  2. マネージド インスタンス グループを作成します。このマネージド インスタンス グループは、特定のゾーンに複数の実行中インスタンスを設定する際に必要です。インスタンスは、前の手順で作成したインスタンス テンプレートに基づいて作成されます。

    export INSTANCE_GROUP_NAME="deeplearning-instance-group"
    export INSTANCE_TEMPLATE_NAME="tf-inference-template"
    gcloud compute instance-groups managed create $INSTANCE_GROUP_NAME \
        --template $INSTANCE_TEMPLATE_NAME \
        --base-instance-name deeplearning-instances \
        --size 2 \
        --zones us-central1-a,us-central1-b
    
    • このインスタンスは、T4 GPU をサポートしているゾーンであれば、どの利用可能なゾーンにでも作成できます。なお、ゾーンに利用可能な GPU 割り当てがあることを確認してください。
    • インスタンスの作成にはしばらく時間がかかります。次のコマンドを実行すれば、進行状況を確認できます。

      export INSTANCE_GROUP_NAME="deeplearning-instance-group"
      
      gcloud compute instance-groups managed list-instances $INSTANCE_GROUP_NAME --region us-central1
      

      インスタンス作成のスクリーンショット

    • マネージド インスタンス グループが作成されると、次のような出力が表示されます。

      実行中のインスタンスのスクリーンショット

  3. Google Cloud Platform の Stackdriver のページで、指標が利用できることを確認します。

    1. Stackdriver のページに移動します。
    2. gpu_utilization を検索します。

      Stackdriver 開始時のスクリーンショット

    3. データがきていれば、次のように表示されます。

      Stackdriver 実行時のスクリーンショット

自動スケーリングを有効にする

  1. マネージド インスタンス グループの自動スケーリングを有効にします。

    export INSTANCE_GROUP_NAME="deeplearning-instance-group"
    
    gcloud compute instance-groups managed set-autoscaling $INSTANCE_GROUP_NAME \
        --custom-metric-utilization metric=custom.googleapis.com/gpu_utilization,utilization-target-type=GAUGE,utilization-target=85 \
        --max-num-replicas 4 \
        --cool-down-period 360 \
        --region us-central1
    

    custom.googleapis.com/gpu_utilization は指標へのフルパスです。今回のサンプルでは、レベル 85 を指定しています。これは、GPU 使用率が 85 に達するたびに、プラットフォームがグループに新しいインスタンスを作成することを意味します。

  2. 自動スケーリングをテストします。自動スケーリングをテストするには、次の手順を実行する必要があります。

    1. インスタンスに SSH で接続します。インスタンスへの接続をご覧ください。
    2. gpu-burn ツールを使用して、GPU に使用率 100% で 600 秒間の負荷をかけます。

      git clone https://github.com/GoogleCloudPlatform/ml-on-gcp.git
      cd ml-on-gcp/third_party/gpu-burn
      git checkout c0b072aa09c360c17a065368294159a6cef59ddf
      make
      ./gpu_burn 600 > /dev/null &
      
    3. Stackdriver のページを表示して、自動スケーリングを確認します。クラスタがインスタンスをもう 1 つ追加して、スケールアップしています。

      自動スケーリングのスクリーンショット

    4. GCP Console の [インスタンス グループ] ページに移動します。

      [インスタンス グループ] ページに移動

    5. deeplearning-instance-group マネージド インスタンス グループをクリックします。

    6. [モニタリング] タブをクリックします。

      [モニタリング] タブのスクリーンショット

      この時点で、自動スケーリングのロジックが、可能な限り多くのインスタンスを起動させて負荷を軽減しようとしますが、対処しきれません。

      具体的には、次のような状況になります。

      追加のインスタンスのスクリーンショット

      この時点でインスタンスへの負荷を停止させると、システムのスケールダウンの様子が確認できます。

ロードバランサを設定する

ここまでで次のリソースの準備ができました。

  • TensorRT5(INT8)で最適化されたトレーニング済みのモデル。
  • インスタンスのマネージド グループ。これらのインスタンスは、使用可能な GPU 使用率に基づいて自動スケーリングを有効化します。

これで、各インスタンスの前にロードバランサを作成できます。

  1. ヘルスチェックを作成します。ヘルスチェックは、バックエンドの特定のホストがトラフィックを処理できるかどうかを判別するために使用します。

    export HEALTH_CHECK_NAME="http-basic-check"
    
    gcloud compute health-checks create http $HEALTH_CHECK_NAME \
        --request-path /v1/models/default \
        --port 8888
    
  2. インスタンス グループとヘルスチェックを含むバックエンド サービスを作成します。

    1. ヘルスチェックを作成します。

      export HEALTH_CHECK_NAME="http-basic-check"
      export WEB_BACKED_SERVICE_NAME="tensorflow-backend"
      
      gcloud compute backend-services create $WEB_BACKED_SERVICE_NAME \
          --protocol HTTP \
          --health-checks $HEALTH_CHECK_NAME \
          --global
      
    2. インスタンス グループを新しいバックエンド サービスに追加します。

      export INSTANCE_GROUP_NAME="deeplearning-instance-group"
      export WEB_BACKED_SERVICE_NAME="tensorflow-backend"
      
      gcloud compute backend-services add-backend $WEB_BACKED_SERVICE_NAME \
          --balancing-mode UTILIZATION \
          --max-utilization 0.8 \
          --capacity-scaler 1 \
          --instance-group $INSTANCE_GROUP_NAME \
          --instance-group-region us-central1 \
          --global
      
  3. 転送先 URL を設定します。ロードバランサにバックエンド サービスへの転送が可能な URL を定めておく必要があります。

    export WEB_BACKED_SERVICE_NAME="tensorflow-backend"
    export WEB_MAP_NAME="map-all"
    
    gcloud compute url-maps create $WEB_MAP_NAME \
        --default-service $WEB_BACKED_SERVICE_NAME
    
  4. ロードバランサを作成します。

    export WEB_MAP_NAME="map-all"
    export LB_NAME="tf-lb"
    
    gcloud compute target-http-proxies create $LB_NAME \
        --url-map $WEB_MAP_NAME
    
  5. ロードバランサに外部 IP アドレスを追加します。

    export IP4_NAME="lb-ip4"
    
    gcloud compute addresses create $IP4_NAME \
        --ip-version=IPV4 \
        --global
    
  6. 割り当てられた IP を確認します。

    gcloud compute addresses list
    
  7. パブリック IP からのすべてのリクエストをロードバランサに転送するように指示する転送ルールを設定します。

    export IP=$(gcloud compute addresses list | grep ${IP4_NAME} | awk '{print $2}')
    export LB_NAME="tf-lb"
    export FORWARDING_RULE="lb-fwd-rule"
    
    gcloud compute forwarding-rules create $FORWARDING_RULE \
        --address $IP \
        --global \
        --target-http-proxy $LB_NAME \
        --ports 80
    

    グローバル転送ルールの作成後、構成が反映されるまで数分かかることがあります。

ファイアウォールを有効にする

  1. 外部の接続元から VM インスタンスへの接続を許可するファイアウォール ルールがあるかどうかを確認します。

    gcloud compute firewall-rules list
    
  2. そのような接続を許可するファイアウォール ルールがない場合、作成する必要があります。ファイアウォール ルールを作成するには、次のコマンドを実行します。

    gcloud compute firewall-rules create www-firewall-80 \
        --target-tags http-server --allow tcp:80
    
    gcloud compute firewall-rules create www-firewall-8888 \
        --target-tags http-server --allow tcp:8888
    

推論の実行

  1. 次の python スクリプトを実行して、画像をサーバーにアップロードできる形式に変換します。

    from PIL import Image
    import numpy as np
    import json
    import codecs
    <br>
    img = Image.open("image.jpg").resize((240, 240))
    img_array=np.array(img)
    result = {
           "instances":[img_array.tolist()]
            }
    file_path="/tmp/out.json"
    print(json.dump(result, codecs.open(file_path, 'w', encoding='utf-8'), separators=(',', ':'), sort_keys=True, indent=4))
    
  2. 推論を実行します。

    curl -X POST $IP/v1/models/default:predict -d @/tmp/out.json
    

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud Platform アカウントに課金されないようにする手順は次のとおりです。

  1. 転送ルールを削除します。

    gcloud compute forwarding-rules delete $FORWARDING_RULE --global
    
  2. IPV4 アドレスを削除します。

    gcloud compute addresses delete $IP4_NAME --global
    
  3. ロードバランサを削除します。

    gcloud compute target-http-proxies delete $LB_NAME
    
  4. 転送先 URL を削除します。

    gcloud compute url-maps delete $WEB_MAP_NAME
    
  5. バックエンド サービスを削除します。

    gcloud compute backend-services delete $WEB_BACKED_SERVICE_NAME --global
    
  6. ヘルスチェックを削除します。

    gcloud compute health-checks delete $HEALTH_CHECK_NAME
    
  7. マネージド インスタンス グループを削除します。

    gcloud compute instance-groups managed delete $INSTANCE_GROUP_NAME --region us-central1
    
  8. インスタンス テンプレートを削除します。

    gcloud beta compute --project=$PROJECT_NAME instance-templates delete $INSTANCE_TEMPLATE_NAME
    
  9. ファイアウォール ルールを削除します。

    gcloud compute firewall-rules delete www-firewall-80
    gcloud compute firewall-rules delete www-firewall-8888
    
このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...

Compute Engine ドキュメント