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 を共有できます。現在、同じリソースプール内のモデルには、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 インスタンスのランチャーから、新しい 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] ボタンを選択します。

execute_nb

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

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.']

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

endpoint.predict(instances=x_test)

お疲れさまでした

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

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

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

7. クリーンアップ

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

undeploy_model

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

インスタンスの停止

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

ストレージを削除