Vertex AI:搭配 Sklearn 使用自訂預測處理常式,預先處理及後續處理資料以執行預測

1. 總覽

在本實驗室中,您將瞭解如何在 Vertex AI 上使用自訂預測處理常式,編寫自訂預先處理和後續處理邏輯。雖然本範例使用 Scikit-learn,但自訂預測處理常式可搭配其他 Python ML 架構使用,例如 XGBoost、PyTorch 和 TensorFlow。

課程內容

學習重點:

  • 使用自訂預測處理常式編寫自訂預測邏輯
  • 在本機測試自訂供應容器和模型
  • 在 Vertex AI 預測上測試自訂服務容器

在 Google Cloud 上執行本實驗室的總費用約為 $1 美元。

2. Vertex AI 簡介

這個實驗室使用 Google Cloud 最新推出的 AI 產品服務。Vertex AI 整合了 Google Cloud 中的機器學習產品,提供流暢的開發體驗。先前使用 AutoML 訓練的模型和自訂模型,都能透過不同的服務存取。新產品將這兩項功能與其他新產品整合至單一 API。您也可以將現有專案遷移至 Vertex AI。

Vertex AI 包含許多不同產品,可支援端對端機器學習工作流程。本實驗室將著重於預測工作台

Vertex 產品總覽

3. 用途簡介

用途

在本研究室中,您將建構隨機森林迴歸模型,根據切割、清晰度和尺寸等屬性預測鑽石的價格。

您將編寫自訂的預先處理邏輯,檢查提供時的資料是否採用模型預期的格式。此外,您也需要編寫自訂後處理邏輯,將預測結果四捨五入並轉換為字串。如要編寫這項邏輯,您將使用自訂預測處理常式。

自訂預測處理常式簡介

Vertex AI 預先建構的容器會執行機器學習架構的預測作業,以處理預測要求。在自訂預測處理常式之前,如果您想在執行預測前預先處理輸入內容,或是在傳回結果前對模型的預測結果進行後處理,就必須建構自訂容器。

如要建構自訂服務容器,您必須編寫 HTTP 伺服器,用於包裝已訓練的模型、將 HTTP 要求轉換為模型輸入內容,以及將模型輸出內容轉換為回應。

Vertex AI 會透過自訂預測例行程序提供服務相關元件,讓您專注於模型和資料轉換作業。

4. 設定環境

您必須擁有啟用計費功能的 Google Cloud Platform 專案,才能執行這個程式碼研究室。如要建立專案,請按照這篇文章中的操作說明進行。

步驟 1:啟用 Compute Engine API

前往「Compute Engine」,然後選取「啟用」 (如果尚未啟用)。您需要這項資訊才能建立 Notebook 執行個體。

步驟 2:啟用 Artifact Registry API

前往「Artifact Registry」,然後選取「Enable」(如果尚未啟用)。您將使用這組憑證建立自訂供應容器。

步驟 3:啟用 Vertex AI API

前往 Cloud 控制台的 Vertex AI 專區,然後按一下「啟用 Vertex AI API」

Vertex AI 資訊主頁

步驟 4:建立 Vertex AI Workbench 執行個體

在 Cloud 控制台的 Vertex AI 專區中,按一下「Workbench」:

Vertex AI 選單

如果尚未啟用 Notebooks API,請先啟用。

Notebook_api

啟用後,請按一下「執行個體」,然後選取「建立新執行個體」

接受預設選項,然後點選「建立」

執行個體準備就緒後,按一下「OPEN JUPYTERLAB」開啟執行個體。

5. 編寫訓練程式碼

步驟 1:建立 Cloud Storage 值區

您可以將模型和預先處理構件儲存至 Cloud Storage 值區。如果專案中已有要使用的桶,您可以略過這個步驟。

在啟動器中開啟新的終端機工作階段。

Open_terminal

在終端機中執行以下指令,為專案定義 env 變數,請務必將 your-cloud-project 替換為專案的 ID:

PROJECT_ID='your-cloud-project'

接著,請在終端機中執行下列指令,在專案中建立新的值區。

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

步驟 2:訓練模型

在終端機中建立名為 cpr-codelab 的新目錄,然後切換至該目錄。

mkdir cpr-codelab
cd cpr-codelab

在檔案瀏覽器中前往新的 cpr-codelab 目錄,然後使用啟動器建立名為 task.ipynb 的新 Python 3 筆記本。

file_browser

cpr-codelab 目錄現在應如下所示:

+ cpr-codelab/
    + task.ipynb

在筆記本中貼上下列程式碼。

首先,請寫入 requirements.txt 檔案。

%%writefile requirements.txt
fastapi
uvicorn==0.17.6
joblib~=1.0
numpy~=1.20
scikit-learn>=1.2.2
pandas
google-cloud-storage>=1.26.0,<2.0.0dev
google-cloud-aiplatform[prediction]>=1.16.0

您部署的模型會預先安裝一組與筆記本環境不同的依附元件。因此,您應該在 requirements.txt 中列出模型的所有依附元件,然後使用 pip 在筆記本中安裝完全相同的依附元件。稍後,您會在本機測試模型,再部署至 Vertex AI,以便再次確認環境是否相符。

Pip 會在筆記本中安裝依附元件。

!pip install -U --user -r requirements.txt

請注意,pip 安裝完成後,您必須重新啟動核心。

restart_kernel

接下來,請建立用於儲存模型和預先處理構件的目錄。

USER_SRC_DIR = "src_dir"
!mkdir $USER_SRC_DIR
!mkdir model_artifacts

# copy the requirements to the source dir
!cp requirements.txt $USER_SRC_DIR/requirements.txt

cpr-codelab 目錄現在應如下所示:

+ cpr-codelab/
    + model_artifacts/
    + scr_dir/
        + requirements.txt
    + task.ipynb
    + requirements.txt

目錄結構設定完成後,就可以開始訓練模型了!

首先,請匯入程式庫。

import seaborn as sns
import numpy as np
import pandas as pd

from sklearn import preprocessing
from sklearn.ensemble import RandomForestRegressor
from sklearn.pipeline import make_pipeline
from sklearn.compose import make_column_transformer

import joblib
import logging

# set logging to see the docker container logs
logging.basicConfig(level=logging.INFO)

接著定義下列變數。請務必將 PROJECT_ID 替換為您的專案 ID,並將 BUCKET_NAME 替換為您在上一個步驟中建立的值區。

REGION = "us-central1"
MODEL_ARTIFACT_DIR = "sklearn-model-artifacts"
REPOSITORY = "diamonds"
IMAGE = "sklearn-image"
MODEL_DISPLAY_NAME = "diamonds-cpr"

# Replace with your project
PROJECT_ID = "{PROJECT_ID}"

# Replace with your bucket
BUCKET_NAME = "gs://{BUCKET_NAME}"

從 seaborn 程式庫載入資料,然後建立兩個資料框架,一個包含特徵,另一個包含標籤。

data = sns.load_dataset('diamonds', cache=True, data_home=None)

label = 'price'

y_train = data['price']
x_train = data.drop(columns=['price'])

我們來看看訓練資料。您可以看到每列都代表一顆鑽石。

x_train.head()

以及對應的價格

y_train.head()

現在,請定義 sklearn 資料欄轉換,以一個熱編碼來為類別特徵進行熱編碼,並調整數值特徵

column_transform = make_column_transformer(
    (preprocessing.OneHotEncoder(), [1,2,3]),
    (preprocessing.StandardScaler(), [0,4,5,6,7,8]))

定義隨機樹系模型

regr = RandomForestRegressor(max_depth=10, random_state=0)

接下來,請建立 sklearn 管道。也就是說,饋送至這個管道的資料會先經過編碼/縮放,再傳遞至模型。

my_pipeline = make_pipeline(column_transform, regr)

在訓練資料上調整管道

my_pipeline.fit(x_train, y_train)

讓我們試用模型,確保模型正常運作。對模型呼叫 predict 方法,並傳入測試樣本。

my_pipeline.predict([[0.23, 'Ideal', 'E', 'SI2', 61.5, 55.0, 3.95, 3.98, 2.43]])

現在,我們可以將管道儲存至 model_artifacts 目錄,並將管道複製到 Cloud Storage 值區。

joblib.dump(my_pipeline, 'model_artifacts/model.joblib')

!gsutil cp model_artifacts/model.joblib {BUCKET_NAME}/{MODEL_ARTIFACT_DIR}/

步驟 3:儲存預先處理構件

接下來,您將建立預先處理構件。模型伺服器啟動時,系統會在自訂容器中載入這個構件。預先處理構件幾乎可以是任何形式 (例如 pickle 檔案),但在本例中,您會將字典寫入 JSON 檔案。

clarity_dict={"Flawless": "FL",
              "Internally Flawless": "IF",
              "Very Very Slightly Included": "VVS1",
              "Very Slightly Included": "VS2",
              "Slightly Included": "S12",
              "Included": "I3"}

訓練資料中的 clarity 功能一律以縮寫形式表示 (例如「FL」而非「Flawless」)。在放送時間點,我們會檢查這項功能的資料是否也經過縮寫。這是因為我們的模型知道如何為「FL」進行單一熱編碼,但不支援「Flawless」。您稍後會編寫這個自訂預先處理邏輯。但現階段,只要將這個查詢資料表儲存至 JSON 檔案,然後寫入 Cloud Storage 值區即可。

import json
with open("model_artifacts/preprocessor.json", "w") as f:
    json.dump(clarity_dict, f)

!gsutil cp model_artifacts/preprocessor.json {BUCKET_NAME}/{MODEL_ARTIFACT_DIR}/

您的本機 cpr-codelab 目錄現在應如下所示:

+ cpr-codelab/
    + model_artifacts/
        + model.joblib
        + preprocessor.json
    + scr_dir/
        + requirements.txt
    + task.ipynb
    + requirements.txt

6. 使用 CPR 模型伺服器建立自訂供應容器

現在模型已完成訓練,並儲存了預先處理構件,接著要建構自訂提供容器。一般來說,建構服務容器需要撰寫模型伺服器程式碼。不過,透過自訂預測處理常式,Vertex AI 預測會產生模型伺服器,並為您建構自訂容器映像檔。

自訂放送容器包含下列 3 個程式碼:

  1. 模型伺服器 (SDK 會自動產生並儲存在 scr_dir/ 中)
    • 託管模型的 HTTP 伺服器
    • 負責設定路徑/連接埠等。
  2. 要求處理常式
    • 負責處理要求的網路伺服器層面,例如將要求主體還原序列化,以及將存放區序列化、設定回應標頭等。
    • 在本例中,您將使用 SDK 提供的預設 Handler google.cloud.aiplatform.prediction.handler.PredictionHandler
  3. 預測器
    • 負責處理預測要求的機器學習邏輯。

您可以根據用途需求自訂每個元件。在這個範例中,您只會實作預測器。

預測器負責處理預測要求的機器學習邏輯,例如自訂預先處理和後續處理。如要編寫自訂預測邏輯,您必須將 Vertex AI 預測者介面設為子類別

這個版本的自訂預測處理常式隨附可重複使用的 XGBoost 和 Sklearn 預測工具,但如果需要使用其他架構,則可將基礎預測工具分類,以建立自己的架構。

您可以在下方查看 Sklearn 預測工具的範例。這是您為了建構這個自訂模型伺服器而需要編寫的所有程式碼。

sklearn_predictor

在筆記本中貼上下列程式碼,以便將 SklearnPredictor 設為子類別,並將其寫入 src_dir/ 中的 Python 檔案。請注意,本例只是自訂 loadpreprocesspostprocess 方法,而非 predict 方法。

%%writefile $USER_SRC_DIR/predictor.py

import joblib
import numpy as np
import json

from google.cloud import storage
from google.cloud.aiplatform.prediction.sklearn.predictor import SklearnPredictor


class CprPredictor(SklearnPredictor):

    def __init__(self):
        return

    def load(self, artifacts_uri: str) -> None:
        """Loads the sklearn pipeline and preprocessing artifact."""

        super().load(artifacts_uri)

        # open preprocessing artifact
        with open("preprocessor.json", "rb") as f:
            self._preprocessor = json.load(f)


    def preprocess(self, prediction_input: np.ndarray) -> np.ndarray:
        """Performs preprocessing by checking if clarity feature is in abbreviated form."""

        inputs = super().preprocess(prediction_input)

        for sample in inputs:
            if sample[3] not in self._preprocessor.values():
                sample[3] = self._preprocessor[sample[3]]
        return inputs

    def postprocess(self, prediction_results: np.ndarray) -> dict:
        """Performs postprocessing by rounding predictions and converting to str."""

        return {"predictions": [f"${value}" for value in np.round(prediction_results)]}

讓我們進一步瞭解這些方法。

  • load 方法會載入預處理構件,在本例中為字典,用於將鑽石清晰度值對應至其縮寫。
  • preprocess 方法會使用該構件,確保在放送時,clarity 功能會以簡略格式顯示。如果不是,則會將完整字串轉換為縮寫。
  • postprocess 方法會以包含 $ 符號的字串傳回預測值,並將值四捨五入。

接著,使用 Vertex AI Python SDK 建構映像檔。使用自訂預測處理常式,系統就會產生 Dockerfile,並為您建構映像檔。

from google.cloud import aiplatform

aiplatform.init(project=PROJECT_ID, location=REGION)

import os

from google.cloud.aiplatform.prediction import LocalModel

from src_dir.predictor import CprPredictor  # Should be path of variable $USER_SRC_DIR

local_model = LocalModel.build_cpr_model(
    USER_SRC_DIR,
    f"{REGION}-docker.pkg.dev/{PROJECT_ID}/{REPOSITORY}/{IMAGE}",
    predictor=CprPredictor,
    requirements_path=os.path.join(USER_SRC_DIR, "requirements.txt"),
)

編寫包含兩個預測樣本的測試檔案。其中一個執行個體有縮寫,但其他必須先轉換。

import json

sample = {"instances": [
  [0.23, 'Ideal', 'E', 'VS2', 61.5, 55.0, 3.95, 3.98, 2.43],
  [0.29, 'Premium', 'J', 'Internally Flawless', 52.5, 49.0, 4.00, 2.13, 3.11]]}

with open('instances.json', 'w') as fp:
    json.dump(sample, fp)

部署本機模型,在本機測試容器。

with local_model.deploy_to_local_endpoint(
    artifact_uri = 'model_artifacts/', # local path to artifacts
) as local_endpoint:
    predict_response = local_endpoint.predict(
        request_file='instances.json',
        headers={"Content-Type": "application/json"},
    )

    health_check_response = local_endpoint.run_health_check()

您可以透過以下方式查看預測結果:

predict_response.content

7. 將模型部署至 Vertex AI

您已在本機測試容器,現在可以將映像檔推送至 Artifact Registry,並將模型上傳至 Vertex AI Model Registry。

首先,請設定 Docker 以存取 Artifact Registry。

!gcloud artifacts repositories create {REPOSITORY} --repository-format=docker \
--location=us-central1 --description="Docker repository"


!gcloud auth configure-docker {REGION}-docker.pkg.dev --quiet

然後推送映像檔。

local_model.push_image()

然後上傳模型。

model = aiplatform.Model.upload(local_model = local_model,
                                display_name=MODEL_DISPLAY_NAME,
                                artifact_uri=f"{BUCKET_NAME}/{MODEL_ARTIFACT_DIR}",)

模型上傳完畢後,應該會在控制台中顯示:

model_registry

接下來,您可以部署模型,以便進行線上預測。自訂預測處理常式也適用於批次預測,因此如果用途不需要線上預測,您就不需要部署模型。

endpoint = model.deploy(machine_type="n1-standard-2")

最後,取得預測結果來測試已部署的模型。

endpoint.predict(instances=[[0.23, 'Ideal', 'E', 'VS2', 61.5, 55.0, 3.95, 3.98, 2.43]])

🎉 恭喜!🎉

您已瞭解如何使用 Vertex AI 執行下列作業:

  • 使用自訂預測處理常式撰寫自訂預先處理和後續處理邏輯

如要進一步瞭解 Vertex AI 的其他部分,請參閱說明文件

8. 清除

如果想繼續使用您在這個研究室中建立的筆記本,建議在不使用時將其關閉。在 Google Cloud 控制台的 Workbench UI 中,選取 Notebook,然後選取「Stop」

如要刪除整個筆記本,請按一下右上方的「刪除」按鈕。

Stop_nb

如要刪除已部署的端點,請前往控制台的「端點」部分,按一下您建立的端點,然後選取「從端點取消部署模型」

delete_endpoint

如要刪除容器映像檔,請前往 Artifact Registry,選取您建立的存放區,然後選取「Delete」

delete_image

如要刪除儲存體值區,請使用 Cloud 控制台的「導覽」選單,前往「儲存體」並選取所需值區,然後按一下「刪除」

刪除儲存空間