このチュートリアルでは、NVIDIA TensorRT 5 および T4 GPU で大規模に推論を実行する方法を説明します。NVIDIA TensorRT™ は、高性能のディープ ラーニングによる推論を実現するプラットフォームです。このプラットフォームに組み込まれた、ディープ ラーニングによる推論向けのオプティマイザーとランタイムが、ディープ ラーニングを使用した推論アプリケーションで低レイテンシと高スループットを実現します。
このチュートリアルでは、GPU 使用率ベースの自動スケーリング グループを使用して推論を実行できるよう、マルチゾーン クラスタを設定します。
概要
このチュートリアルでは、次の項目について説明します。
- 開発環境に適したスケーラブルな機械学習推論システムを Google Cloud に実装するためのリファレンス アーキテクチャ。インフラストラクチャとセキュリティのニーズはさまざまに異なるため、このチュートリアルで説明している構成はニーズに応じて調整できるようになっています。
- このチュートリアルで TensorFlow モデルやその他の必要なコンポーネントをインストールするために使用するスクリプトが格納されている GitHub リポジトリ。
- TensorRT を使用して TensorFlow モデルを量子化する方法、スクリプトをデプロイする方法、リファレンス アーキテクチャをデプロイする方法。
- Cloud Load Balancing の構成手順。
このチュートリアルを完了すると、トレーニング済みの量子化されたモデルが Cloud Storage に格納されます。また、それぞれ異なるリージョン内でクラスタ化された 2 つの Compute Engine インスタンス グループが作成され、これらのインスタンス グループの前面で Cloud Load Balancing がウェブ トラフィックを負荷分散します。次の図に、このアーキテクチャを示します。
目標
- 事前にトレーニングされたグラフを出発点として使用する。
- TensorRT を使用してモデルを最適化し、さまざまな最適化ごとにモデルがどれだけ高速化されるかを確認する。
- モデルを仕上げた後、TensorFlow、TensorFlow Serving、TensorRT 5 がプリインストールされた Compute Engine ディープ ラーニング VM をベースにクラスタを作成する。
料金
このチュートリアルでは、課金対象である次の Google Cloud コンポーネントを使用します。
- Compute Engine
- Persistent Disk
- Cloud Storage
- ネットワーキング
- NVIDIA T4 GPU
料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。新しい Google Cloud ユーザーは無料トライアルをご利用いただけます。
始める前に
-
Google Cloud Console で [プロジェクトの選択] ページに移動します。
-
Google Cloud プロジェクトを選択または作成します。
-
Cloud プロジェクトに対して課金が有効になっていることを確認します。プロジェクトに対して課金が有効になっていることを確認する方法を学習する。
- Compute Engine and Cloud Logging API を有効にします。
- VM を作成するのに十分な GPU 割り当てがあることを確認します。
このチュートリアルを終了した後、作成したリソースを削除すると、それ以上の請求は発生しません。詳しくは、クリーンアップをご覧ください。
環境の準備
このセクションでは、チュートリアル全体で使用される値(リージョンやゾーンなど)のデフォルトの設定を行います。このチュートリアルでは、デフォルト リージョンとして us-central1
を使用し、デフォルト ゾーンとして us-central1-b
を使用します。
また、Cloud Shell を再度開いて、設定を再初期化する必要がある場合に、変数を自動的に読み込めるように、すべての設定を含むファイルも作成します。
Cloud Shell を開きます。
デフォルトのリージョンとゾーンを設定します。
gcloud compute project-info add-metadata \ --metadata google-compute-default-region=us-central1,google-compute-default-zone=us-central1-a
シェルを再初期化します。
gcloud init --console-only
最初の 3 つの質問には
1
を押し、最後の質問にはプロジェクト ID を入力します。
TensorRT を使用してモデルを最適化する
Cloud Shell で、モデルを準備するために使用できるインスタンスを作成します。
export IMAGE_FAMILY="tf-latest-cu100" export INSTANCE_NAME="model-prep" gcloud compute instances create $INSTANCE_NAME \ --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"
TensorRT のさまざまな最適化モードを比較するのにも、単一の GPU をどれだけ高速化できるかを把握するのにも、1 つの GPU があれば十分です。
VM インスタンスを作成したら、
ssh
を使用して VM に接続します。このインスタンス内で、TensorRT の最適化をテストするための
resnetv2
モデルを公式の TensorFlow リポジトリからダウンロードします。wget -q http://download.tensorflow.org/models/official/resnetv2_imagenet_frozen_graph.pb
TensorRT によって推論を高速化できますが、さらに高速化するにはモデルを量子化します。線形モデル量子化では、重みと活性化が浮動小数点数から整数に変換されます。たとえば、モデルの初期の重みが FP32(浮動小数点型 32 ビット)の場合、精度を下げることによって INT8 を使用できます。ただし、量子化には犠牲が伴います。ストレージ表現を縮小すると、ごくわずかでもモデルの精度低下につながる可能性があります。ただし、FP32 から FP16 に変換する場合は、ほとんど影響はありません。
速度(重みの精度)とモデルの精度の間で適切な妥協点を見つけるにはどうすればよいでしょうか。そのためのコードは存在します。これにより、速度やその他の指標に照らして精度を測定できます。このコードでのテスト対象は画像認識モデルに限られていますが、このコードに基づくカスタムテストを実装するのは難しいことではありません。
Cloud Shell で、カスタムテストをダウンロードして実装します。
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 .
テストを実行できるよう準備します。
python -m research.tensorrt.tensorrt \ --frozen_graph=$HOME/resnetv2_imagenet_frozen_graph.pb \ --image_file=$HOME/models/image.jpg \ --native --fp32 --fp16 --int8 \ --output_dir=$HOME
テストを実行するには、フリーズされたグラフ(先ほどダウンロードした resnetv2 モデル)と、テスト対象のさまざまな量子化モードに応じた引数が必要です。このコマンドは完了するまでに時間がかかります。
コマンドの実行が完了すると、グラフの別のバージョンに対する推論結果の比較が出力されます。
FP32 による結果と FP16 による結果は同じで、この 2 つの間で精度に変わりはありません。つまり、TensorRT で問題がなければ、すぐに FP16 を使い始められるということです。一方、INT8 による結果では、精度がわずかに下がっています。
精度の数値を表示します。
cat $HOME/log.txt
このコマンドでは、次の出力が表示されます。
TensorRT 5 に示される次の結果は、すべてネイティブと比較されています。
- FP32 の場合、スループットは約 34% 向上しています(319.1 fps から 428.2 fps に高速化)。
- FP16 の場合、スループットは約 207% 向上しています(319.1 fps から 979.6 fps に高速化)。
- INT8 の場合、スループットは約 376% 向上しています(319.1 fps から 1519.5 fps に高速化)。
以上の結果から、次のことがわかります。
- ネイティブから TensorRT への移行は、不確実性を伴います。ただし、多少の犠牲を払ってもかまわないのであれば、直接 FP16 に移行できます。
- INT8 は非常に高速ですが、不確実性はさらに大きくなります。
次のセクションでは INT8 モデルを使用します。
カスタムモデルを TensorRT に変換する
モデルを TensorRT グラフに変換するには、SavedModel が必要です。
Cloud Shell で、事前にトレーニングされた次の SavedModel をダウンロードします。
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
フリーズされたモデルを TensorRT グラフに変換する Python スクリプトを作成します。
cat <<EOF > convert_to_rt.py import tensorflow.contrib.tensorrt as trt import argparse parser = argparse.ArgumentParser(description="Converts TF SavedModel to the TensorRT enabled graph.") parser.add_argument("--input_model_dir", required=True) parser.add_argument("--output_model_dir", required=True) parser.add_argument("--batch_size", type=int, required=True) parser.add_argument("--precision_mode", choices=["FP32", "FP16", "INT8"], required=True) args = parser.parse_args() trt.create_inference_graph( None, None, max_batch_size=args.batch_size, input_saved_model_dir=args.input_model_dir, output_saved_model_dir=args.output_model_dir, precision_mode=args.precision_mode) EOF
モデルを TensorRT グラフに変換します。
python ./convert_to_rt.py \ --input_model_dir=$HOME/resnet_v2_fp32_savedmodel_NCHW/1538687196 \ --output_model_dir=$HOME/resnet_v2_int8_NCHW/00001 \ --batch_size=128 \ --precision_mode="INT8"
これで、INT8 モデルが
$HOME/resnet_v2_int8_NCHW/00001
フォルダに格納されました。すべてが正常に機能することを確認するために、推論を実行します。
tensorflow_model_server --model_base_path=$HOME/resnet_v2_int8_NCHW/ --rest_api_port=8888
推論が機能していることを確認するには、次のサンプル入力を送信します。
curl -X POST localhost:8888/v1/models/default:predict -d '{"instances": [[[[1,1,1]]]]}'
この
curl
コマンドによる結果が表示されたら、Ctrl+C キーを押して推論の実行を終了します。最適化されたモデルをクラスタから使用するには、モデルを Cloud Storage にアップロードします。
[GCS_PATH]
は、実際の Cloud Storage バケット名に置き換えます。tar -zcvf model.tar.gz ./resnet_v2_int8_NCHW/ export GCS_PATH=[GCS_PATH] gsutil cp model.tar.gz $GCS_PATH
次回、このモデルを使用するときには、このプロセス全体を繰り返す必要はありません。代わりに、Cloud Storage バケットに格納されている INT8 のフリーズされたグラフを使用できます。
gs://solutions-public-assets/tensorrt-t4-gpu/model.tar.gz
クラスタを設定する
Cloud Storage 内にモデルが格納された状態になったので、クラスタの作成を開始します。最初のステップは、VM テンプレートを作成することです。クラスタは VM テンプレートを使用して新しいインスタンスを作成します。
Cloud Shell で、クラスタの設定に必要なコードをダウンロードします。
git clone https://github.com/GoogleCloudPlatform/tensorflow-inference-tensorrt5-t4-gpu.git
VM テンプレートを作成します。
[PROJECT_NAME]
は、実際のプロジェクト名に置き換えます。export PROJECT_NAME=[PROJECT_NAME] export INSTANCE_TEMPLATE_NAME="tf-inference-template" export IMAGE_FAMILY="tf-latest-cu100" 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://solutions-public-assets/tensorrt-t4-gpu/start_agent_and_inf_server.sh
metadata
パラメータで、起動スクリプトを指定します。この起動スクリプトが、VM テンプレートによって作成されるすべてのインスタンスにインストールされます。起動スクリプトは、VM インスタンスの起動時に次の処理を行います。- NVIDIA ドライバをインストールします。
- GPU の使用状況をモニタリングするモニタリング エージェントをインストールします。
- モデルをダウンロードします。
- 推論サービスを開始します。
テンプレートが使用可能になったら、マネージド インスタンス グループを作成できます。このグループはスケーリング グループではなく、ヘルスチェックも行われません。作成するグループでは、特定の複数のゾーン内における 2 つのインスタンスの稼働のみが保証されます。
マネージド インスタンス グループを作成します。
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
INSTANCE_TEMPLATE_NAME
の値は、前の手順で設定したインスタンスの名前です。GPU の可用性(すべての GPU がすべてのゾーンで利用可能なわけではありません)と割り当てに基づいてゾーンを選んでください。グループの作成には時間がかかります。
次のコマンドを実行して進行状況を確認します。
gcloud compute instance-groups managed list-instances $INSTANCE_GROUP_NAME --region us-central1
出力は次のようになります。
作成が完了すると、次のような出力が表示されます。
Cloud Console で [モニタリング] ページを開きます。
モニタリング ページに移動
正しいプロジェクト ワークスペースを使用していることを確認します。ワークスペース名は左上隅に示されます。このページにアクセスするのが初めての場合は、新しいワークスペースを作成する必要があります。
[Metrics Explorer] ページで、リソースタイプに
GCE VM Instance
を選択し、指標にcustom/gpu_utilization
を選択します。データが取り込まれると、次のように表示されます。
Cloud Shell で、グループに対して自動スケーリングを有効にします。
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% に達するたびに、新しいインスタンスがグループ内に作成される点にも注意してください。
自動スケーリングをテストする
前のセクションで設定した自動スケーリングをテストするには、次の操作を行う必要があります。
- SSH を使用して、ディープ ラーニング用 GPU インスタンスのいずれかに接続します。
- すべての GPU に 100% の負荷をかけます。
- もう 1 つのインスタンスを作成して、自動スケーリング グループがスケールアップする様子を観察します。
ssh
を使用してインスタンスに接続します。600 秒間 GPU に 100% の負荷をかけます。
git clone https://github.com/GoogleCloudPlatform/tensorflow-inference-tensorrt5-t4-gpu.git cd tensorflow-inference-tensorrt5-t4-gpu git submodule update --init --recursive cd third_party/gpu-burn make ./gpu_burn 600 > /dev/null &
Cloud Console の [Metrics Explorer] ページで、アクティビティを確認します。
2 つ目のインスタンスを作成します。
GCE Compute のページに移動し、[インスタンス グループ] の [モニタリング] タブでアクティビティを観察します。
この時点で、オートスケーラーが可能な限り多くのインスタンスを起動させて負荷を軽減しようとしています(ただし、対処しきれていません)。それが、現在の状況です。
インスタンスの起動を停止させて、アクティビティがスケールダウンする様子を観察します。
これまでの手順で、次のものが揃いました。
- TensorRT 5(INT8)で最適化されたトレーニング済みモデル
- ディープ ラーニング用インスタンスからなるマネージド グループ
- GPU 使用率に基づく自動スケーリング
ロードバランサを作成する
最後のステップは、インスタンスの前面に配置するロードバランサを作成することです。
Cloud Shell で、バックエンドの特定のホストがトラフィックを処理できるかどうかを判別するヘルスチェックを作成します。
gcloud compute health-checks create http $HEALTH_CHECK_NAME \ --request-path /v1/models/default \ --port 8888
ポート 8888 を介して提供される推論サービスに対し、ロードバランサがポート 80 を介して推論リクエストを転送できるよう、インスタンス グループの名前付きポートを構成します。
gcloud compute instance-groups set-named-ports $INSTANCE_GROUP_NAME \ --named-ports http:8888 \ --region us-central1
バックエンド サービスを作成します。
export WEB_BACKED_SERVICE_NAME="tensorflow-backend" gcloud compute backend-services create $WEB_BACKED_SERVICE_NAME \ --protocol HTTP \ --health-checks $HEALTH_CHECK_NAME \ --global
実質的に、バックエンド サービスはヘルスチェックを行うインスタンス グループです。
新しく作成したバックエンド サービスにインスタンス グループを追加します。
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
ロードバランサに対し、バックエンド サービスへの転送に使用する URL を指示します。
export WEB_MAP_NAME="map-all" gcloud compute url-maps create $WEB_MAP_NAME \ --default-service $WEB_BACKED_SERVICE_NAME
ロードバランサを作成します。
export LB_NAME="tf-lb" gcloud compute target-http-proxies create $LB_NAME \ --url-map $WEB_MAP_NAME
ロードバランサの外部 IP アドレスを作成します。
export IP4_NAME="lb-ip4" gcloud compute addresses create $IP4_NAME \ --ip-version=IPV4 \ --global
作成した IP アドレスが割り当てられたことを確認します。
gcloud compute addresses list
Google Cloud がパブリック IP からのすべてのリクエストをロードバランサに転送するために使用する転送ルールを確認します。
export IP=$(gcloud compute addresses list | grep ${IP4_NAME} | awk '{print $2}') export FORWARDING_RULE="lb-fwd-rule" gcloud compute forwarding-rules create $FORWARDING_RULE \ --address $IP \ --global \ --target-http-proxy $LB_NAME \ --ports 80
グローバル転送ルールを作成した後、構成が伝播されるまでに数分かかることがあります。
外部インスタンスに接続するには、プロジェクトに対してファイアウォールを有効にします。
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
画像をサーバーに送信できる形式に変換します。
cat <<EOF > load_and_convert_image.py 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)) EOF
推論を実行します。
wget https://pixnio.com/free-images/2017/10/31/2017-10-31-10-43-58-1032x825.jpg -O image.jpg python load_and_convert_image.py curl -X POST $IP/v1/models/default:predict -d @/tmp/out.json
推論が正しく機能していれば、結果は次のようになります。
クリーンアップ
このチュートリアルが終了したら、Google Cloud で作成したリソースをクリーンアップして、今後割り当ての消費や課金が発生しないようにします。次のセクションで、リソースを削除または無効にする方法を説明します。
- Cloud Console で [リソースの管理] ページに移動します。
- プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
- ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。
次のステップ
- ドキュメントで TensorRT について学習する。
- NVIDIA T4 GPU のドキュメントを読む。
- カスタム指標を作成する方法とカスタム指標を使用する方法を学習する。
- 自動スケーリング グループ インスタンスについて学習する。
- Google Cloud のその他の機能を試す。チュートリアルをご覧ください。