Vertex AI: 予測のために同じ VM 上でモデルを共同ホストする

1. 概要

このラボでは、Vertex AI共同ホスティング モデル機能を使用して、オンライン予測のために同じ VM 上に複数のモデルをホストします。

学習内容

次の方法を学習します。

  • DeploymentResourcePool を作成する
  • DeploymentResourcePool 内にモデルをデプロイする

このラボを Google Cloud で実行するための総費用は約 $2 です。

2. Vertex AI の概要

このラボでは、Google Cloud で利用できる最新の AI プロダクトを使用します。Vertex AI は Google Cloud 全体の ML サービスを統合してシームレスな開発エクスペリエンスを提供します。以前は、AutoML でトレーニングしたモデルやカスタムモデルにそれぞれ個別のサービスを介してアクセスする必要がありましたが、Vertex AI は、これらの個別のサービスを他の新しいプロダクトとともに 1 つの API にまとめます。既存のプロジェクトを Vertex AI に移行することもできます。ご意見やご質問がありましたら、サポートページからお寄せください。

Vertex AI には、エンドツーエンドの ML ワークフローをサポートするさまざまなプロダクトが含まれています。このラボでは、以下でハイライト表示されているプロダクト(PredictionsWorkbench)を中心に学習します。

Vertex プロダクトの概要

3. ユースケースの概要

モデルを Vertex AI 予測サービスにデプロイする際、各モデルはデフォルトで独自の VM にデプロイされます。ホスティングの費用対効果を高めるため、同一の VM で複数のモデルをホストすることができ、メモリとコンピューティング リソースの使用率が向上します。同じ VM にデプロイするモデルの数はモデルのサイズとトラフィック パターンによりますが、この機能は特に、低トラフィックで多くのモデルをデプロイする場合に便利です。

共同ホスティング モデルのサポートには、モデルをグループ化して VM 内でリソースを共有するという、デプロイ リソースプールの概念が導入されています。エンドポイントを共有している複数のモデルが VM を共有できるだけでなく、異なるエンドポイントにデプロイされている場合でも VM の共有が可能です。現在、同じリソースプール内のモデルは、Vertex Prediction ビルド済みコンテナのフレームワーク バージョンを含む同じコンテナ イメージを使用している必要があります。また、このリリースでは Tensorflow モデル フレームワークを含む Vertex Prediction のビルド済みコンテナのみがサポートされています。その他のモデル フレームワークとカスタム コンテナはまだサポートされていません。

deployment_pool

4. 環境の設定

この Codelab を実行するには、課金が有効になっている Google Cloud Platform プロジェクトが必要です。プロジェクトを作成するには、こちらの手順を行ってください。

ステップ 1: Compute Engine API を有効にする

まだ有効になっていない場合は、[Compute Engine] に移動して [有効にする] を選択します。

ステップ 2: Vertex AI API を有効にする

Cloud コンソールの [Vertex AI] セクションに移動し、[Vertex AI API を有効にする] をクリックします。

Vertex AI ダッシュボード

ステップ 3: Vertex AI Workbench インスタンスを作成する

Cloud Console の [Vertex AI] セクションで [ワークベンチ] をクリックします。

Vertex AI メニュー

Notebooks API をまだ有効にしていない場合は、有効にします。

Notebook_api

有効にしたら、[マネージド ノートブック] をクリックします。

Notebooks_UI

[新しいノートブック] を選択します。

new_notebook

ノートブックの名前を指定して、[権限] で [Service account] を選択します。

create_notebook

[詳細設定] を選択します。

まだ有効になっていない場合は、[セキュリティ] で、[Enable terminal] を選択します。

enable_terminal

詳細設定のその他の設定はそのままで構いません。

[作成] をクリックします。インスタンスがプロビジョニングされるまでに数分かかります。

インスタンスが作成されたら、[JUPYTERLAB を開く] を選択します。

open_jupyterlab

5. モデルをトレーニングする

共同ホスティング機能を試す前に、まずモデルをトレーニングし、保存したモデル アーティファクトを Cloud Storage バケットに保存する必要があります。Workbench ノートブック エグゼキュータを使用して、トレーニング ジョブを起動します。

ステップ 1: Cloud Storage バケットを作成する

使用する既存のバケットがプロジェクトにある場合は、この手順を省略できます。それ以外の場合は、ランチャーから新しいターミナル セッションを開きます。

launcher_terminal

ターミナルで以下のように実行して、プロジェクトの環境変数を定義します。その際、your-cloud-project は実際のプロジェクト ID で置き換えてください。

PROJECT_ID='your-cloud-project'

次に、次のコマンドを実行して、プロジェクトに新しいバケットを作成します。

BUCKET="gs://${PROJECT_ID}-bucket"
gsutil mb -l us-central1 $BUCKET

ステップ 2: ノートブックの実行を開始する

Workbench インスタンスの Launcher から、新しい TensorFlow 2 ノートブックを開きます。

launcher_tf2

次のコードは、IMDB 映画レビュー データセットでバイナリ感情分類子(肯定的または否定的)をトレーニングします。コードをノートブックに貼り付けます。

{YOUR_BUCKET} は、前の手順で作成したバケット(またはプロジェクト内の別のバケット)に置き換えてください。ここに保存されたモデル アーティファクトを保存します。これは、後でモデルを Vertex AI Model Registry にアップロードするときに必要になります。

import numpy as np

import tensorflow_datasets as tfds
import tensorflow as tf

# REPLACE WITH YOUR BUCKET!
OUTPUT_PATH='gs://{YOUR_BUCKET}/model_output'

BUFFER_SIZE = 10000
BATCH_SIZE = 64
VOCAB_SIZE = 1000

# Load data
dataset, info = tfds.load('imdb_reviews', with_info=True,
                          as_supervised=True)
train_dataset, test_dataset = dataset['train'], dataset['test']

train_dataset = train_dataset.shuffle(BUFFER_SIZE).batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)
test_dataset = test_dataset.batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)

# Create text encoder
encoder = tf.keras.layers.TextVectorization(
    max_tokens=VOCAB_SIZE)
encoder.adapt(train_dataset.map(lambda text, label: text))

# Create model
model = tf.keras.Sequential([
    encoder,
    tf.keras.layers.Embedding(
        input_dim=len(encoder.get_vocabulary()),
        output_dim=64,
        # Use masking to handle the variable sequence lengths
        mask_zero=True),
    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64)),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dense(1)
])

# Compile model
model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              optimizer=tf.keras.optimizers.Adam(1e-4),
              metrics=['accuracy'])

# Fit model
history = model.fit(train_dataset, epochs=10,
                    validation_data=test_dataset,
                    validation_steps=30)

# Save model
model.save(OUTPUT_PATH)

次に、[実行] ボタンを選択します。

execute_nb

次のように実行を構成し、[送信] をクリックします。

execution_config

コンソールの [実行] タブで、トレーニング ジョブのステータスを追跡できます。

execution_status

6. モデルをデプロイする

ステップ 1: モデルをアップロードする

実行が完了したら、Workbench ノートブックに戻ってモデルをアップロードします。新しい TensorFlow ノートブックを作成します。

tf_nb

まず、Vertex AI Python SDK をインポートします。

from google.cloud import aiplatform

次に、モデルをアップロードします。{YOUR_BUCKET} は、トレーニング コードで指定したバケットに置き換えます。

# replace {YOUR_BUCKET}
model_1 = aiplatform.Model.upload(display_name='text-model-1',
                                  artifact_uri='gs://{YOUR_BUCKET}/model_output',
                                  serving_container_image_uri='us-docker.pkg.dev/vertex-ai/prediction/tf2-cpu.2-8:latest')

デモンストレーションのため、このモデルを 2 回アップロードし、Vertex AI に 2 つの異なるモデルリソースを作成します。これは、デプロイ リソースプール内の単一のエンドポイントに複数のモデルをデプロイするテストを行うためです。実際のシナリオでは、同じ保存済みアーティファクトからモデルを作成するのではなく、2 つの異なるモデルを使用しますが、これは別のトレーニング実行を起動する必要がないようにするためのショートカットです。また、同じデプロイ リソース プール内の異なるエンドポイントに 2 つのモデルをデプロイすることもできます。

# replace {YOUR_BUCKET}
model_2 = aiplatform.Model.upload(display_name='text-model-2',
                                  artifact_uri='gs://{YOUR_BUCKET}/model_output',
                                  serving_container_image_uri='us-docker.pkg.dev/vertex-ai/prediction/tf2-cpu.2-8:latest')

Vertex AI Model Registry に両方のモデルが表示されます。モデルをまだデプロイしていないため、デプロイ ステータスは空白になっています。

model_registry

ステップ 2: エンドポイントを作成する

エンドポイントを作成します。これは、モデルのエンドポイントへのデプロイとは異なります。

endpoint = aiplatform.Endpoint.create('cohost-endpoint')

エンドポイントが作成されると、コンソールに表示されます。

console_endpoint

ステップ 3: DeploymentResourcePool を作成する

次のコマンドを使用して DeploymentResourcePool を作成できます。{YOUR_PROJECT} は、プロジェクト ID に置き換えてください。

# replace {YOUR_PROJECT}
PROJECT_ID={YOUR_PROJECT}
REGION="us-central1"
VERTEX_API_URL=REGION + "-aiplatform.googleapis.com"
VERTEX_PREDICTION_API_URL=REGION + "-prediction-aiplatform.googleapis.com"
MULTI_MODEL_API_VERSION="v1beta1"

# Give the pool a name
DEPLOYMENT_RESOURCE_POOL_ID="my-resource-pool"

import json
import pprint
pp = pprint.PrettyPrinter(indent=4)

CREATE_RP_PAYLOAD = {
  "deployment_resource_pool":{
    "dedicated_resources":{
      "machine_spec":{
        "machine_type":"n1-standard-4"
      },
      "min_replica_count":1,
      "max_replica_count":2
    }
  },
  "deployment_resource_pool_id":DEPLOYMENT_RESOURCE_POOL_ID
}
CREATE_RP_REQUEST=json.dumps(CREATE_RP_PAYLOAD)
pp.pprint("CREATE_RP_REQUEST: " + CREATE_RP_REQUEST)

!curl \
-X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
https://{VERTEX_API_URL}/{MULTI_MODEL_API_VERSION}/projects/{PROJECT_ID}/locations/{REGION}/deploymentResourcePools \
-d '{CREATE_RP_REQUEST}'

プールを確認するには、次のコマンドを実行します。

!curl -X GET \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
https://{VERTEX_API_URL}/{MULTI_MODEL_API_VERSION}/projects/{PROJECT_ID}/locations/{REGION}/deploymentResourcePools/{DEPLOYMENT_RESOURCE_POOL_ID}

ステップ 4: モデルをエンドポイントにデプロイする

リソース プールが作成されたので、リソース プール内にモデルをデプロイできます。

まず、model_1 をデプロイします。MODEL_1_IDENDPOINT_ID は、それぞれの ID に置き換えてください。

MODEL_1_ID="{MODEL_1_ID}"
ENDPOINT_ID="{ENDPOINT_ID}"

次のコマンドは、リソース プール内のエンドポイントに model_1 をデプロイします。

MODEL_NAME = "projects/{project_id}/locations/{region}/models/{model_id}".format(project_id=PROJECT_ID, region=REGION, model_id=MODEL_1_ID)
SHARED_RESOURCE = "projects/{project_id}/locations/{region}/deploymentResourcePools/{deployment_resource_pool_id}".format(project_id=PROJECT_ID, region=REGION, deployment_resource_pool_id=DEPLOYMENT_RESOURCE_POOL_ID)

DEPLOY_MODEL_PAYLOAD = {
  "deployedModel": {
    "model": MODEL_NAME,
    "shared_resources": SHARED_RESOURCE
  },
  "trafficSplit": {
    "0": 100
  }
}
DEPLOY_MODEL_REQUEST=json.dumps(DEPLOY_MODEL_PAYLOAD)
pp.pprint("DEPLOY_MODEL_REQUEST: " + DEPLOY_MODEL_REQUEST)

!curl -X POST \
 -H "Authorization: Bearer $(gcloud auth print-access-token)" \
 -H "Content-Type: application/json" \
https://{VERTEX_API_URL}/{MULTI_MODEL_API_VERSION}/projects/{PROJECT_ID}/locations/{REGION}/endpoints/{ENDPOINT_ID}:deployModel \
-d '{DEPLOY_MODEL_REQUEST}'

この処理には数分かかりますが、完了すると、モデルがエンドポイントにデプロイされたことがコンソールに表示されます。

model_1_endpoint

次に、同じデプロイ プール内に model_2 をデプロイできます。これは model_1 と同じエンドポイントにデプロイします。ただし、同じリソース プール内の別のエンドポイントに model_2 をデプロイすることもできます。

MODEL_IDmodel_2 の ID に更新します。この ID は、model_2.name を実行して取得できます。

MODEL_2_ID="{MODEL_2_ID}"

次に、model_2 をデプロイします。model_1 はすでにエンドポイントにデプロイされているため、トラフィックが 2 つのモデル間で分割されるように trafficSplit を更新する必要があります。同じリソースプール内の別のエンドポイントに model_2 をデプロイする場合は、trafficSplit を更新する必要はありません。

トラフィック分割を更新するには、model_1 の DeployedModel ID を定義する必要があります。これはモデル ID とは異なります。

DEPLOYED_MODEL_1_ID = {DEPLOYED_MODEL_1_ID}

次に、次のコマンドを実行して 2 番目のモデルをデプロイします。

MODEL_NAME = "projects/{project_id}/locations/{region}/models/{model_id}".format(project_id=PROJECT_ID, region=REGION, model_id=MODEL_2_ID)
SHARED_RESOURCE = "projects/{project_id}/locations/{region}/deploymentResourcePools/{deployment_resource_pool_id}".format(project_id=PROJECT_ID, region=REGION, deployment_resource_pool_id=DEPLOYMENT_RESOURCE_POOL_ID)

#`trafficSplit` is a map from a DeployedModel's ID to the percentage of this Endpoint's traffic that should be forwarded to that DeployedModel.
# The traffic percentage values for an endpoint must add up to 100.
# The key for the model being deployed is "0".

DEPLOY_MODEL_PAYLOAD = {
  "deployedModel": {
    "model": MODEL_NAME,
    "shared_resources": SHARED_RESOURCE
  },
  "trafficSplit": {
    "0": 50,
    DEPLOYED_MODEL_1_ID: 50
  }
}
DEPLOY_MODEL_REQUEST=json.dumps(DEPLOY_MODEL_PAYLOAD)
pp.pprint("DEPLOY_MODEL_REQUEST: " + DEPLOY_MODEL_REQUEST)

!curl -X POST \
 -H "Authorization: Bearer $(gcloud auth print-access-token)" \
 -H "Content-Type: application/json" \
https://{VERTEX_API_URL}/{MULTI_MODEL_API_VERSION}/projects/{PROJECT_ID}/locations/{REGION}/endpoints/{ENDPOINT_ID}:deployModel \
-d '{DEPLOY_MODEL_REQUEST}'

この例では、2 つのモデルが同じエンドポイントにデプロイされていますが、異なるエンドポイントにデプロイされているモデルを同じリソースプールに共同ホストすることもできます。その場合、トラフィックの分割について心配する必要はありません。

2 つ目のモデルがデプロイされると、両方のモデルがコンソールに表示されます。

deployed_models

ステップ 5: 予測を取得する

最後のステップは、エンドポイントをテストして予測を取得することです。

まず、テスト文を定義します。

x_test=['The movie was cool. The animation and the graphics were out of this world. I would recommend this movie.']

次に、エンドポイントで predict を呼び出します。これにより、エンドポイントにデプロイされたモデルのいずれかから予測が返されます。

endpoint.predict(instances=x_test)

お疲れさまでした

Vertex AI を使って次のことを行う方法を学びました。

  • オンライン予測用に同じ VM でモデルを共同ホストする

Vertex のさまざまな部分の説明については、ドキュメントをご覧ください。

7. クリーンアップ

今後使用する予定がなければ、エンドポイントからモデルのデプロイを解除します。エンドポイント全体を削除することもできます。必要であれば、いつでもエンドポイントにモデルをデプロイできます。

undeploy_model

Workbench マネージド ノートブックは、アイドル状態が 180 分続くと自動的にタイムアウトします。インスタンスのシャットダウンを気にする必要はありません。インスタンスを手動でシャットダウンする場合は、コンソールで [Vertex AI] の [ワークベンチ] セクションにある [停止] ボタンをクリックします。ノートブックを完全に削除する場合は、[削除] ボタンをクリックします。

インスタンスの停止

ストレージ バケットを削除するには、Cloud コンソールのナビゲーション メニューで [ストレージ] に移動してバケットを選択し、[削除] をクリックします。

ストレージを削除