Vertex AI:在同一虚拟机上共同托管模型以进行预测

1. 概览

在本实验中,您将使用 Vertex AI 中的共同托管模型功能在同一虚拟机上托管多个模型,以进行在线预测。

学习内容

您将了解如何:

  • 创建 DeploymentResourcePool
  • DeploymentResourcePool 中部署模型

在 Google Cloud 上运行此实验的总费用约为 2 美元

2. Vertex AI 简介

本实验使用的是 Google Cloud 上提供的最新 AI 产品。Vertex AI 将整个 Google Cloud 的机器学习产品集成到无缝的开发体验中。以前,使用 AutoML 训练的模型和自定义模型是通过不同的服务访问的。现在,该新产品与其他新产品一起将这两种模型合并到一个 API 中。您还可以将现有项目迁移到 Vertex AI。如果您有任何反馈,请参阅支持页面

Vertex AI 包含许多不同的产品,可支持端到端机器学习工作流。本实验将重点介绍下面突出显示的产品:PredictionsWorkbench

Vertex 产品概览

3. 使用场景概览

将模型部署到 Vertex AI 预测服务时,每个模型默认都会部署到自己的虚拟机。为了提高托管成本效益,您可以在同一虚拟机上托管多个模型,从而提高内存和计算资源利用率。您选择部署到同一虚拟机的模型数量取决于模型大小和流量模式,但此功能特别适合您部署了许多流量稀疏的模型的情况。

共同托管模型支持引入了部署资源池的概念,部署资源池可将模型组合在一起,以便在虚拟机内共享资源。如果模型共享一个端点,或者它们部署到不同的端点,那么它们可以共享一个虚拟机。目前,同一资源池中的模型必须具有相同的容器映像,包括 Vertex Prediction 预构建容器的框架版本。此外,此版本仅支持采用 Tensorflow 模型框架的 Vertex Prediction 预构建容器,尚不支持其他模型框架和自定义容器。

deployment_pool

4. 设置您的环境

您需要一个启用了结算功能的 Google Cloud Platform 项目才能运行此 Codelab。如需创建项目,请按照此处的说明操作。

第 1 步:启用 Compute Engine API

前往 Compute Engine,然后选择启用(如果尚未启用)。

第 2 步:启用 Vertex AI API

前往 Cloud Console 的 Vertex AI 部分,然后点击启用 Vertex AI API

Vertex AI 信息中心

第 3 步:创建 Vertex AI Workbench 实例

在 Cloud Console 的 Vertex AI 部分中,点击“Workbench”:

Vertex AI 菜单

启用 Notebooks API(如果尚未启用)。

Notebook_api

启用后,点击代管式笔记本

Notebooks_UI

然后选择新建笔记本

new_notebook

为您的笔记本命名,然后在权限下选择服务账号

create_notebook

选择高级设置

安全性下,选择“启用终端”(如果尚未启用)。

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_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')

为便于演示,我们将上传此模型两次,在 Vertex AI 中创建两种不同的模型资源。这样,我们就可以测试将多个模型部署到部署资源池中的单个端点的效果。在实际场景中,您会有两个不同的模型,而不是根据相同的已保存工件创建模型,但这是一种捷径,让我们不必启动另一个训练作业。此外,您还可以选择将两个模型部署到同一部署资源池中的不同端点。

# 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_2 的 ID 更新 MODEL_ID。同样,您可以通过运行 model_2.name 来获取此 ID。

MODEL_2_ID="{MODEL_2_ID}"

然后部署 model_2。由于我们已将 model_1 部署到端点,因此需要更新 trafficSplit,以便在两个模型之间拆分流量。如果我们选择将 model_2 部署到同一资源池中的其他端点,则需更新 trafficSplit

如需更新流量分配比例,您需要为 model_1 定义 DeployedModel ID。请注意,这与模型 ID 不同。

DEPLOYED_MODEL_1_ID = {DEPLOYED_MODEL_1_ID}

然后执行以下命令,部署第二个模型。

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}'

同样,在此示例中,两个模型已部署到同一端点,但您也可以将模型共同托管到部署到不同端点的同一资源池。在这种情况下,您不必担心流量分配问题。

部署第二个模型后,您会在控制台中看到它们。

deployed_models

第 5 步:获取预测结果

最后一步是测试端点并获取预测结果。

首先,定义测试语句。

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

然后,在端点上调用预测,这将从部署到端点的某个模型返回预测结果。

endpoint.predict(instances=x_test)

🎉 恭喜!🎉

您学习了如何使用 Vertex AI 执行以下操作:

  • 在同一虚拟机上共同托管模型以进行在线预测

如需详细了解 Vertex 的不同部分,请参阅相关文档

7. 清理

如果您不打算使用模型,则需要从端点取消部署模型。您也可以完全删除端点。如果需要,您可以随时将模型重新部署到端点。

undeploy_model

Workbench 代管式笔记本会在 180 分钟空闲后自动超时,因此您无需担心关停实例。如果您要手动关停实例,请点击控制台的 Vertex AI Workbench 部分中的“停止”按钮。如果您想完全删除该笔记本,请点击“删除”按钮。

可停止实例

如需删除存储桶,请使用 Cloud Console 中的导航菜单,浏览到“存储空间”,选择您的存储桶,然后点击“删除”:

删除存储空间