使用 Vertex AI 提供 Spark ML 模型

Last reviewed 2023-07-11 UTC

数据科学家和机器学习 (ML) 工程师通常需要一个足够快的服务架构,以满足从机器学习模型生成在线(或实时)预测的需求。Vertex AI 能够满足此需求。

使用 Vertex AI,您可以通过各种机器学习框架提供模型。对于 TensorFlow、PyTorch、XGBoost 和 scikit-learn 等框架,Vertex AI 提供了在其中运行这些机器学习模型的预构建容器。如果您还没有使用其中任何机器学习框架,则必须创建自己的自定义容器供 Vertex AI 使用。

本文档适用于需要创建自定义容器以提供其 Spark ML 模型的用户。本文档中包含对自定义容器所需的服务架构的说明,以及演示 Spark MLib 模型的此架构的参考实现。

要充分利用本文档的参考实现部分,您应该熟悉如何将 Spark MLlib 模型导出为 MLeap 格式,了解如何使用 Vertex AI 提供预测服务,并具有使用容器映像的经验。

架构

虽然预构建容器可用于某些机器学习框架,但其他机器学习框架(例如 Spark)的用户需要构建自定义容器,Vertex AI 可以在其中运行预测。下图说明了传送 Spark MLib 模型和其他需要自定义容器的模型的服务架构:

本文档中使用的模型的服务架构。

此架构包括以下组件:

  • Cloud Storage:为运行模型所需的模型工件提供存储。对于附带参考实现中使用的 Spark ML 模型,模型工件由 MLeap 软件包和模型架构组成。
  • Cloud Build:使用构建器映像来构建名为“服务容器映像”的自定义容器映像。该构建流程会编译和打包模型服务代码,构建服务容器映像,然后将服务容器映像推送到 Artifact Registry。
  • Artifact Registry:包含以下对象:
    • Cloud Build 用于构建服务容器映像的 scala-sbt 构建器容器映像。
    • 由 Cloud Build 构建的服务容器映像。
  • Vertex AI:包含从 Cloud Storage 上传的机器学习模型。系统会使用 Cloud Storage 中模型工件的位置和 Artifact Registry 中服务容器映像的位置来配置上传的模型。Vertex AI 还包括已部署模型的端点。将模型部署到端点后,Vertex AI 会将物理资源与模型相关联,以便模型执行在线预测。

在实现此服务架构的过程中,您需要导出机器学习模型以供其他应用使用,并定义您自己的服务容器映像。本文档中提供的参考实现提供了用于定义和构建服务容器映像的代码。此代码还包括之前导出的 Spark 机器学习模型的模型工件。对于某些配置更改,您可以使用此参考实现来提供自己的 Spark 机器学习模型。

但是,您可以自行实现此传送架构,而不使用参考实现。如果您决定实现自己的架构,则需要执行以下操作:

  • 导出您的模型,以便其他应用使用该模型。此过程取决于您所使用的机器学习框架和工具。例如,您可以选择创建 MLeap 软件包,以导出 Spark MLlib 模型,如参考实现中所述。您可以在导出用于预测的模型工件中查看其他导出模型的示例。
  • 设计服务容器映像,以满足使该映像与 Vertex AI 兼容的自定义容器要求。代码可以采用您选择的编程语言。
  • 将代码软件包打包为与您使用的编程语言兼容的软件包文件格式。例如,您可以使用适用于 Java 代码的 JAR 文件,或 Python 代码的 Python Wheel。
  • 创建自定义容器映像,该映像能够处理自定义模式代码。

参考实现

以下参考实现提供了一个 Spark MLib 模型,该模型根据鸢尾花萼片和花瓣的长度和宽度来预测鸢尾花的种类。

您可以在 vertex-ai-spark-ml-serving.git 代码库example_model 目录中找到本实现中使用的模型。该目录包含服务容器用于运行预测的模型工件,并且包含以下文件:

  • example_model/model.zip 文件是一个使用 Spark MLlib 构建的逻辑回归模型,该模型已使用鸢尾花数据集进行训练并已转换为 MLeap 软件包。该模型会通过鸢尾花萼片和花瓣的长度和宽度来预测鸢尾花的种类。
  • example_model/schema.json 文件是描述模型架构的 JSON 文件。该模型架构描述了 MLeap 架构所需的针对预测实例的预期输入字段和针对预测结果的输出字段。

使用您自己的 Mlib 模型

如需将您自己的模型与此参考实现搭配使用,请先确保您的 Spark MLlib 模型已导出到 MLeap 软件包。然后,为了提供 Spark MLib 模型,您必须提供适当的模型工件:MLeap 软件包和模型架构。

MLeap 软件包

服务容器使用在启动时从 Vertex AI 传递到容器的 AIP_STORAGE_URI 环境变量来确定 MLeap 软件包的位置。AIP_STORAGE_URI 变量的值会在您将模型上传到 Vertex AI 时指定。

模型架构

模型架构描述了模型的输入特征和预测输出。模型架构使用 JSON 数据表示。以下是本参考实现中使用的架构,用于根据花的长度以及萼片和花瓣的宽度来预测鸢尾花的种类:

{
  "input": [
    {
      "name": "sepal_length",
      "type": "FLOAT"
    },
    {
      "name": "sepal_width",
      "type": "FLOAT"
    },
    {
      "name": "petal_length",
      "type": "FLOAT"
    },
    {
      "name": "petal_width",
      "type": "FLOAT"
    }
  ],
  "output": [
    {
      "name": "probability",
      "type": "DOUBLE",
      "struct": "VECTOR"
    }
  ]
}

在示例架构中,input 数组包含模型的输入字段(列),而 output 数组包含要从模型返回的输出字段(列)。在这两个数组中,数组的每个对象都包含以下属性:

  • name:字段(列)名称。
  • type:字段(列)类型。有效类型包括 BOOLEANBYTEDOUBLEFLOATINTEGERLONGSHORTSTRING
  • (可选)struct:字段结构,例如标量或数组。有效结构包括 BASIC(标量类型)、ARRAY (Spark Array) 和 VECTOR (Spark DenseVector)。如果 struct 字段不存在,则使用 BASIC

如需将模型架构传递给服务容器,您可以使用以下方法之一:

  • MLEAP_SCHEMA 环境变量中指定定义架构的 JSON 数据。MLEAP_SCHEMA 环境变量应包含 JSON 数据本身,而不是仅提供包含 JSON 架构的文件的路径。
  • 将 JSON 数据存储在名为 schema.json 的文件中,并使该文件在 ${AIP_STORAGE_URI}/schema.json 位置可供容器使用。这是用于本文档提供的示例 MLib 模型的方法。

如果同时使用这两种方法将模型架构传递给服务容器,则存储在 MLEAP_SCHEMA 环境变量中的 JSON 数据优先。

费用

此参考实现使用 Google Cloud 的以下收费组件:

如需根据您的预计使用量来估算费用,请使用价格计算器

完成本参考实现后,您可以删除所创建的资源以避免继续计费。如需了解详情,请参阅清理

须知事项

  1. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  2. 确保您的 Google Cloud 项目已启用结算功能

  3. 启用 Vertex AI, Cloud Build, Cloud Storage, and Artifact Registry API。

    启用 API

  4. 在 Google Cloud 控制台中,激活 Cloud Shell。

    激活 Cloud Shell

  5. 查找您的项目 ID 并在 Cloud Shell 中进行设置。
    export PROJECT_ID=YOUR_PROJECT_ID
    gcloud config set project ${PROJECT_ID}
    

    YOUR_PROJECT_ID 替换为您的项目 ID。

创建 scala-sbt 构建器映像

您可以将 Cloud Build 与 scala-sbt 社区构建器搭配使用,来构建服务容器映像。此构建流程要求在项目的 Container Registry 中具备 sbt-scala 构建器映像。

  1. 在 Cloud Shell 中,克隆 cloud-builders-community 代码库:

    git clone https://github.com/GoogleCloudPlatform/cloud-builders-community.git
    
  2. 转到项目目录:

    cd cloud-builders-community/scala-sbt
    
  3. 构建 scala-sbt 构建器映像并将其推送到 Container Registry:

    gcloud builds submit .
    

构建服务容器映像

Vertex AI 使用服务容器来运行示例模型的预测请求。如需构建服务容器映像,首先在 Artifact Registry 中创建用于存储映像的 Docker 代码库。然后,您需要向 Vertex AI 授予从代码库中拉取服务容器映像的权限。创建代码库并授予权限后,您便可以构建服务容器映像并将该映像推送到 Artifact Registry。

  1. 通过 Cloud Shell 在 Artifact Registry 中创建 Docker 代码库:

    REPOSITORY="vertex-ai-prediction"
    LOCATION="us-central1"
    
    gcloud artifacts repositories create $REPOSITORY \
        --repository-format=docker \
        --location=$LOCATION
    
  2. 向 Vertex AI Service Agent 授予 Artifact Registry Reader 角色

    PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
        --format="value(projectNumber)")
    SERVICE_ACCOUNT="service-$PROJECT_NUMBER@gcp-sa-aiplatform.iam.gserviceaccount.com"
    
    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$SERVICE_ACCOUNT" \
        --role="roles/artifactregistry.reader"
    
  3. 克隆 spark-ml-serving 代码库:

    git clone https://github.com/GoogleCloudPlatform/vertex-ai-spark-ml-serving.git
    
  4. 转到项目目录:

    cd vertex-ai-spark-ml-serving
    
  5. 在您的项目中构建服务容器映像:

    IMAGE=spark-ml-serving
    
    gcloud builds submit --config=cloudbuild.yaml \
        --substitutions="_LOCATION=$LOCATION,_REPOSITORY=$REPOSITORY,_IMAGE=$IMAGE" .
    

    cloudbuild.yaml 文件指定了两个构建器:scala-sbt 构建器和 docker 映像构建器。Cloud Build 将使用 scala-sbt 构建器编译来自 Cloud Storage 的模型服务代码,然后将编译好的代码打包为一个可执行的 JAR 文件。然后,Cloud Build 会使用 docker 构建器构建包含该 JAR 文件的服务容器映像。构建服务容器映像后,该映像会被推送到 Artifact Registry。

将模型导入 Vertex AI

服务容器会从 Cloud Storage 中读取模型工件。在将模型导入 Vertex AI 之前,您需要为这些工件创建存储位置。然后,在导入模型时,您需要使用该模型工件存储位置以及 Artifact Registry 中的服务容器映像。

  1. 在 Cloud Shell 中,为这些模型工件创建一个存储桶:

    REGION="us-central1"
    BUCKET="YOUR_BUCKET_NAME"
    gsutil mb -l $REGION gs://$BUCKET
    

    YOUR_BUCKET_NAME 替换为您的存储桶名称。

  2. 将模型工件复制到该存储桶:

    gsutil cp example_model/* gs://$BUCKET/example_model/
    
  3. 将模型导入 Vertex AI:

    DISPLAY_NAME="iris-$(date +'%Y%m%d%H%M%S')"
    IMAGE_URI="${LOCATION}-docker.pkg.dev/$PROJECT_ID/${REPOSITORY}/${IMAGE}"
    ARTIFACT_URI="gs://$BUCKET/example_model/"
    
    gcloud ai models upload \
        --region=$REGION \
        --display-name=$DISPLAY_NAME \
        --container-image-uri=$IMAGE_URI \
        --artifact-uri=$ARTIFACT_URI \
        --container-health-route="/health" \
        --container-predict-route="/predict"
    

    gcloud ai models upload 命令中,--artifact-uri 参数的值指定 AIP_STORAGE_URI 变量的值。此变量提供要导入 Vertex AI 的 MLeap 软件包的位置。

将模型部署到新端点

为了让 Vertex AI 能够运行预测,您需要将导入的模型部署到一个端点。部署模型时,您需要使用端点 ID 和模型 ID。

  1. 在 Cloud Shell 中,创建模型端点:

    gcloud ai endpoints create \
        --region=$REGION \
        --display-name=$DISPLAY_NAME
    

    gcloud 命令行工具可能需要几秒钟时间来创建端点。

  2. 获取新创建的端点的 ID:

    ENDPOINT_ID=$(gcloud ai endpoints list \
        --region=$REGION \
        --filter=display_name=$DISPLAY_NAME \
        --format='value(name)')
    
    # Print ENDPOINT_ID to the console
    echo "Your endpoint ID is: $ENDPOINT_ID"
    
  3. 获取您在将模型导入 Vertex AI 部分导入的模型的 ID:

    MODEL_ID=$(gcloud ai models list \
        --region=$REGION \
        --filter=display_name=$DISPLAY_NAME \
        --format='value(name)')
    
    # Print MODEL_ID to the console
    echo "Your model ID is: $MODEL_ID"
    
  4. 将模型部署到端点:

    gcloud ai endpoints deploy-model $ENDPOINT_ID \
        --region=$REGION \
        --model=$MODEL_ID \
        --display-name=$DISPLAY_NAME \
        --traffic-split="0=100"
    

    gcloud 命令会将模型部署到端点。机器资源类型、最小和最大节点数以及其他配置选项均使用默认值。如需详细了解模型的部署选项,请参阅 Vertex AI 文档

测试端点

将模型部署到端点后,您便可以测试您的实现。如需测试端点,您可以使用参考实现代码中包含的示例客户端。示例客户端会生成预测实例并将预测请求发送到端点。每个预测实例都包含 sepal_lengthsepal_widthpetal_lengthpetal_width 的随机值。默认情况下,示例客户端会将多个预测实例合并为一个请求。端点响应将包含对请求中发送的每个实例的预测。预测将包含鸢尾花数据集中每个类(setosaversicolorvirginica)的概率。

  • 在 Cloud Shell 中,运行示例预测客户端:

    cd example_client
    ./run_client.sh --project $PROJECT_ID \
        --location $LOCATION \
        --endpoint $ENDPOINT_ID
    

    首次运行脚本时,该脚本会创建一个 Python 虚拟环境并安装依赖项。安装依赖项后,该脚本会运行示例客户端。对于每个请求,客户端会将预测实例和相应的类概率输出到终端。下面显示了输出的一段摘录:

    Sending 10 asynchronous prediction requests with 3 instances per request ...
    
    ==> Response from request #10:
    
    Instance 1:     sepal_length:   5.925825137450266
                    sepal_width:    4.5047557888651
                    petal_length:   1.0432434310300223
                    petal_width:    0.5050397721287457
    
    Prediction 1:   setosa:         0.2036041134824573
                    versicolor:     0.6062980065549213
                    virginica:      0.1900978799626214
    
    Instance 2:     sepal_length:   6.121228622484405
                    sepal_width:    3.406317728235072
                    petal_length:   3.178583759980504
                    petal_width:    2.815141143581328
    
    Prediction 2:   setosa:         0.471811302254083
                    versicolor:     0.2063720436033448
                    virginica:      0.3218166541425723
    
    Instance 3:     sepal_length:   7.005781590327274
                    sepal_width:    2.532116893508745
                    petal_length:   2.6351337947193474
                    petal_width:    2.270855223519198
    
    Prediction 3:   setosa:         0.453579051699638
                    versicolor:     0.2132869980698818
                    virginica:      0.3331339502304803
    

清理

为避免因本参考实现中使用的资源导致您的 Google Cloud 账号产生费用,请删除包含这些资源的项目,或者保留项目但删除各个资源。

删除项目

  1. 在 Google Cloud 控制台中,进入管理资源页面。

    转到“管理资源”

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

删除各个资源

  1. 在 Cloud Shell 中,从端点取消部署模型:

    DEPLOYED_MODEL_ID=$(gcloud ai endpoints describe $ENDPOINT_ID \
        --region=$REGION \
        --format='value(deployedModels.id)')
    
    gcloud ai endpoints undeploy-model $ENDPOINT_ID \
        --region=$REGION \
        --deployed-model-id=$DEPLOYED_MODEL_ID
    
  2. 删除端点:

    gcloud ai endpoints delete $ENDPOINT_ID \
        --region=$REGION \
        --quiet
    
  3. 删除模型:

    gcloud ai models delete $MODEL_ID \
        --region=$REGION
    
  4. 删除服务容器映像:

    gcloud artifacts docker images delete \
        $LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$IMAGE \
        --delete-tags \
        --quiet
    
  5. 删除 scala-sbt 构建器容器:

    gcloud container images delete gcr.io/$PROJECT_ID/scala-sbt \
        --force-delete-tags \
        --quiet
    
  6. 删除不再需要的任何 Cloud Storage 存储桶:

    gsutil rm -r YOUR_BUCKET_NAME
    

    删除存储桶也会删除存储在该存储桶中的所有对象。删除的存储桶及对象一经删除便无法恢复。

后续步骤