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


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

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

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

目標

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

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

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

料金

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

料金計算ツールを使用して費用を計算できます。

モデルを準備し、さまざまな最適化速度で推論速度をテストする費用を見積もるには、次の仕様を使用します。

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

マルチゾーン クラスタの設定費用を見積もるには、次の仕様を使用します。

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

始める前に

プロジェクト設定

  1. Google Cloud アカウントにログインします。Google Cloud を初めて使用する場合は、アカウントを作成して、実際のシナリオでの Google プロダクトのパフォーマンスを評価してください。新規のお客様には、ワークロードの実行、テスト、デプロイができる無料クレジット $300 分を差し上げます。
  2. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

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

  3. Google Cloud プロジェクトで課金が有効になっていることを確認します

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

    API を有効にする

  5. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

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

  6. Google Cloud プロジェクトで課金が有効になっていることを確認します

  7. Compute Engine and Cloud Machine Learning API を有効にします。

    API を有効にする

ツール設定

このチュートリアルで Google Cloud CLI を使用するには:

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

モデルの準備

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

  1. VM インスタンスを作成します。このチュートリアルは、tf-ent-2-10-cu113 を使用して作成されています。最新のイメージ バージョンについては、Deep Learning VM Image のドキュメントのオペレーティング システムの選択をご覧ください。

    export IMAGE_FAMILY="tf-ent-2-10-cu113"
    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 変数に保存します。MODEL_LOCATION は、ダウンロードしたモデルを含む作業ディレクトリに置き換えます。

    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"
    

    これで、INT8 モデルが $WORKDIR/resnet_v2_int8_NCHW/00001 ディレクトリに格納されました。

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

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

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

      tar -zcvf model.tar.gz ./resnet_v2_int8_NCHW/
    2. アーカイブをアップロードします。GCS_PATH は、Cloud Storage バケットへのパスに置き換えます。

      export GCS_PATH=GCS_PATH
      gsutil cp model.tar.gz $GCS_PATH
      

      必要に応じて、Cloud Storage の次の URL から INT8 のフリーズされたグラフを入手できます。

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

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

クラスタを作成する

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

  1. インスタンス テンプレートを作成します。インスタンス テンプレートは、新しいインスタンスの作成時に便利なリソースです。インスタンス テンプレートをご覧ください。YOUR_PROJECT_NAME は実際のプロジェクト ID に置き換えます。

    export INSTANCE_TEMPLATE_NAME="tf-inference-template"
    export IMAGE_FAMILY="tf-ent-2-10-cu113"
    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. マネージド インスタンス グループ(MIG)を作成します。このマネージド インスタンス グループは、特定のゾーンに複数の実行中インスタンスを設定する際に必要です。インスタンスは、前の手順で作成したインスタンス テンプレートに基づいて作成されます。

    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 の Cloud Monitoring ページで指標が使用可能であることを確認します。

    1. Google Cloud コンソールで [Monitoring] ページに移動します。

      [Monitoring] に移動

    2. ナビゲーション パネルに Metrics Explorer が表示されている場合は、[Metrics Explorer] をクリックします。それ以外の場合は、[Resources] を選択して [Metrics Explorer] を選択します。

    3. gpu_utilization を検索します。

      モニタリング開始。

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

      モニタリング実行中。

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

  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. Cloud Monitoring ページを表示します。自動スケーリングを確認します。クラスタがインスタンスをもう 1 つ追加して、スケールアップしています。

      クラスタの自動スケーリング。

    4. Google Cloud コンソールの [インスタンス グループ] ページに移動します。

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

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

    6. [Monitoring] タブをクリックします。

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

      追加のインスタンス。

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

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

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

  • 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 \
       --network-tier=PREMIUM \
       --global
    
  6. 割り振られている IP アドレスを見つけます。

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

    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 \
       --load-balancing-scheme=EXTERNAL \
       --network-tier=PREMIUM \
       --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
    
    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 アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

  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