Vertex AI:Sklearn과 함께 커스텀 예측 루틴을 사용하여 예측을 위한 데이터 사전 처리 및 사후 처리

1. 소개

이 실습에서는 Vertex AI에서 커스텀 예측 루틴을 사용하여 커스텀 전처리 및 후처리 로직을 작성하는 방법을 알아봅니다. 이 샘플에서는 scikit-learn을 사용하지만 커스텀 예측 루틴은 XGBoost, PyTorch, TensorFlow와 같은 다른 Python ML 프레임워크와 함께 작동할 수 있습니다.

학습할 내용

  • 커스텀 예측 루틴으로 커스텀 예측 로직 작성
  • 로컬에서 커스텀 서빙 컨테이너 및 모델 테스트
  • Vertex AI Predictions에서 커스텀 서빙 컨테이너 테스트

2. Vertex AI 소개

이 실습에서는 Google Cloud에서 제공되는 최신 AI 제품을 사용합니다. Vertex AI는 Google Cloud 전반의 ML 제품을 원활한 개발 환경으로 통합합니다. 예전에는 AutoML로 학습된 모델과 커스텀 모델은 별도의 서비스를 통해 액세스할 수 있었습니다. 새 서비스는 다른 새로운 제품과 함께 두 가지 모두를 단일 API로 결합합니다. 기존 프로젝트를 Vertex AI로 이전할 수도 있습니다.

Vertex AI에는 엔드 투 엔드 ML 워크플로를 지원하는 다양한 제품이 포함되어 있습니다. 이 실습에서는 Predictions와 Workbench를 주로 살펴봅니다.

440e66b5fde4cee7.png

3. 사용 사례 개요

이 실습에서는 무작위 포레스트 회귀 모델을 만들어 잘라내기, 선명도, 크기와 같은 속성을 기반으로 다이아몬드의 가격을 예측합니다.

커스텀 사전 처리 로직을 작성하여 서빙 시점의 데이터가 모델에서 기대하는 형식인지 확인합니다. 또한 예측을 반올림하고 문자열로 변환하는 커스텀 후처리 로직을 작성합니다. 이 로직을 작성하려면 커스텀 예측 루틴을 사용합니다.

커스텀 예측 루틴 소개

Vertex AI 사전 빌드된 컨테이너는 머신러닝 프레임워크의 예측 작업을 수행하여 예측 요청을 처리합니다. 커스텀 예측 루틴 전에 예측이 수행되기 전에 입력을 사전 처리하거나 결과를 반환하기 전에 모델의 예측을 후처리하려면 커스텀 컨테이너를 빌드해야 합니다.

커스텀 서빙 컨테이너를 빌드하려면 학습된 모델을 래핑하고, HTTP 요청을 모델 입력으로 변환하고, 모델 출력을 응답으로 변환하는 HTTP 서버를 작성해야 합니다.

Vertex AI는 커스텀 예측 루틴을 통해 서빙 관련 구성요소를 제공하므로 모델 및 데이터 변환에 집중할 수 있습니다.

빌드할 항목

아래 그림 1에 나와 있는 것처럼 사용자 관리 노트북을 배포하고 us-central1에 배포된 온라인 예측 및 모델 엔드포인트에 액세스하는 데 사용되는 워크벤치 서브넷으로 구성된 goall-vpc라는 VPC 네트워크를 설정합니다.

                                                                            Figure1

6ce21c7fdae12b4f.png

4. 튜토리얼 API 사용 설정

1단계: Compute Engine API 사용 설정

아직 사용 설정되지 않은 경우 Compute Engine으로 이동하고 사용 설정을 선택합니다. 이것은 노트북 인스턴스를 생성하는 데 필요합니다.

2단계: Artifact Registry API 사용 설정하기

아직 사용 설정되지 않은 경우 Artifact Registry로 이동하여 '사용 설정'을 선택합니다. 이를 사용하여 맞춤 서빙 컨테이너를 만듭니다.

3단계: Vertex AI API 사용 설정

Cloud 콘솔의 Vertex AI 섹션으로 이동하여 'Vertex AI API 사용 설정'을 클릭합니다.

4단계: Vertex AI Workbench 인스턴스 만들기

Notebooks API를 아직 사용 설정하지 않은 경우 사용 설정합니다.

5. rememberl-vpc 만들기

이 튜토리얼에서는 $variables를 사용하여 Cloud Shell에서 gcloud 구성을 구현하는 데 도움을 줍니다.

Cloud Shell 내에서 다음을 수행합니다.

gcloud config list project
gcloud config set project [YOUR-PROJECT-NAME]
projectid=YOUR-PROJECT-NAME
echo $projectid

Goal-vpc 만들기

Cloud Shell 내에서 다음을 수행합니다.

gcloud compute networks create aiml-vpc --project=$projectid --subnet-mode=custom

사용자 관리 노트북 서브넷 만들기

Cloud Shell 내에서 Workbench-서브넷을 만듭니다.

gcloud compute networks subnets create workbench-subnet --project=$projectid --range=172.16.10.0/28 --network=aiml-vpc --region=us-central1 --enable-private-ip-google-access

Cloud Router 및 NAT 구성

사용자 관리 노트북에는 외부 IP 주소가 없으므로 이 튜토리얼에서는 소프트웨어 패키지를 다운로드하는 데 Cloud NAT가 사용됩니다. Cloud NAT는 이그레스 NAT 기능을 제공합니다. 즉, 인터넷 호스트가 사용자 관리 노트북과 통신을 시작할 수 없으므로 보안이 향상됩니다.

Cloud Shell 내에서 리전별 클라우드 라우터인 us-central1을 만듭니다.

gcloud compute routers create cloud-router-us-central1-aiml-nat --network aiml-vpc --region us-central1

Cloud Shell 내에서 리전별 Cloud NAT 게이트웨이인 us-central1을 만듭니다.

gcloud compute routers nats create cloud-nat-us-central1 --router=cloud-router-us-central1-aiml-nat --auto-allocate-nat-external-ips --nat-all-subnet-ip-ranges --region us-central1

6. 사용자 관리 노트북 만들기

사용자 관리형 서비스 계정 만들기 (노트북)

다음 섹션에서는 튜토리얼에 사용되는 Vertex Workbench (노트북)와 연결할 사용자 관리형 서비스 계정을 만듭니다.

이 가이드에서는 서비스 계정에 다음 규칙이 적용됩니다.

Cloud Shell 내에서 서비스 계정을 만듭니다.

gcloud iam service-accounts create user-managed-notebook-sa \
    --display-name="user-managed-notebook-sa"

Cloud Shell 내에서 스토리지 관리자 역할로 서비스 계정을 업데이트합니다.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:user-managed-notebook-sa@$projectid.iam.gserviceaccount.com" --role="roles/storage.admin"

Cloud Shell 내에서 Vertex AI 사용자 역할로 서비스 계정을 업데이트합니다.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:user-managed-notebook-sa@$projectid.iam.gserviceaccount.com" --role="roles/aiplatform.user"

Cloud Shell 내에서 Artifact Registry 관리자 역할로 서비스 계정을 업데이트합니다.

gcloud projects add-iam-policy-binding $projectid --member="serviceAccount:user-managed-notebook-sa@$projectid.iam.gserviceaccount.com" --role="roles/artifactregistry.admin"

Cloud Shell 내에서 서비스 계정을 나열하고 사용자 관리 노트북을 만들 때 사용할 이메일 주소를 기록합니다.

gcloud iam service-accounts list

사용자 관리 노트북 만들기

다음 섹션에서는 이전에 만든 서비스 계정 user-managed-notebook-sa를 포함하는 사용자 관리 노트북을 만듭니다.

Cloud Shell 내에서 비공개 클라이언트 인스턴스를 만듭니다.

gcloud notebooks instances create workbench-tutorial \
      --vm-image-project=deeplearning-platform-release \
      --vm-image-family=common-cpu-notebooks \
      --machine-type=n1-standard-4 \
      --location=us-central1-a \
      --shielded-secure-boot \
      --subnet-region=us-central1 \
      --subnet=workbench-subnet \
      --no-public-ip    --service-account=user-managed-notebook-sa@$projectid.iam.gserviceaccount.com

7. 학습 코드 작성

1단계: Cloud Storage 버킷 만들기

모델과 사전 처리 아티팩트를 Cloud Storage 버킷에 저장합니다. 프로젝트에 사용할 버킷이 이미 있는 경우 이 단계를 건너뛰어도 됩니다.

런처에서 새 터미널 세션을 엽니다.

84a53a5b528f2507.png

터미널에서 다음을 실행하여 프로젝트의 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이라는 새 디렉터리를 만들고 이 디렉터리로 cd하세요.

mkdir cpr-codelab
cd cpr-codelab

파일 브라우저에서 새 cpr-codelab 디렉터리로 이동한 다음 런처를 사용하여 task.ipynb라는 새 Python 3 노트북을 만듭니다.

f230930e0b79650c.png

이제 cpr-codelab 디렉터리가 다음과 같이 표시됩니다.

+ cpr-codelab/
    + task.ipynb

노트북에 다음 코드를 붙여넣습니다.

먼저 requirements.txt 파일을 작성합니다.

%%writefile requirements.txt
fastapi
uvicorn==0.17.6
joblib~=1.1.1
numpy>=1.17.3, <1.24.0
scikit-learn~=1.0.0
pandas
google-cloud-storage>=2.2.1,<3.0.0dev
google-cloud-aiplatform[prediction]>=1.18.2

배포하는 모델에는 노트북 환경과 다른 종속 항목 세트가 사전 설치되어 있습니다. 따라서 requirements.txt에 모델의 모든 종속 항목을 나열한 다음 pip를 사용하여 정확히 동일한 종속 항목을 노트북에 설치합니다. 나중에 모델을 Vertex AI에 배포하기 전에 로컬에서 테스트하여 환경이 일치하는지 다시 확인합니다.

Pip은 노트북에 종속 항목을 설치합니다.

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

pip 설치가 완료된 후 커널을 다시 시작해야 합니다.

다음으로 모델과 사전 처리 아티팩트를 저장할 디렉터리를 만듭니다.

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(sparse=False), [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)

모델이 예상대로 작동하는지 확인해 보겠습니다. 모델에서 예측 메서드를 호출하여 테스트 샘플을 전달합니다.

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

이제 파이프라인을 model_artifacts dir에 저장하고 Cloud Storage 버킷에 복사할 수 있습니다.

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

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

3단계: 사전 처리 아티팩트 저장

다음으로 전처리 아티팩트를 만듭니다. 이 아티팩트는 모델 서버가 시작될 때 커스텀 컨테이너에 로드됩니다. 전처리 아티팩트는 거의 모든 형태 (예: 피클 파일)가 될 수 있지만, 이 경우에는 JSON 파일에 사전을 작성하게 됩니다.

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

학습 데이터의 명확성 기능은 항상 축약된 형태였습니다 (즉, 'Flawless' 대신 'FL'). 서빙 시점에 이 특성의 데이터도 축약되었는지 확인하려고 합니다. 모델이 '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

8. CPR 모델 서버를 사용하여 커스텀 서빙 컨테이너 빌드

모델을 학습시키고 전처리 아티팩트를 저장했으므로 이제 커스텀 서빙 컨테이너를 빌드해 보겠습니다. 일반적으로 서빙 컨테이너를 빌드하려면 모델 서버 코드를 작성해야 합니다. 하지만 Vertex AI Predictions는 커스텀 예측 루틴을 사용하여 모델 서버를 생성하고 커스텀 컨테이너 이미지를 빌드합니다.

커스텀 서빙 컨테이너에는 다음과 같은 3가지 코드가 포함됩니다.

  1. 모델 서버 (SDK에서 자동으로 생성되어 scr_dir/에 저장됨)
  • 모델을 호스팅하는 HTTP 서버
  • 경로/포트 등을 설정합니다.
  1. 요청 핸들러
  • 요청 본문 역직렬화, 응답 직렬화, 응답 헤더 설정 등 요청을 처리하는 웹서버 측면을 담당합니다.
  • 이 예시에서는 SDK에서 제공하는 기본 핸들러인 google.cloud.aiplatform.predict.handler.PredictionHandler를 사용합니다.
  1. 예측자
  • 예측 요청을 처리하는 ML 로직을 담당합니다.

이러한 각 구성요소는 사용 사례의 요구사항에 따라 맞춤설정할 수 있습니다. 이 예시에서는 예측자만 구현합니다.

예측자는 커스텀 전처리 및 후처리와 같은 예측 요청을 처리하는 ML 로직을 담당합니다. 커스텀 예측 로직을 작성하려면 Vertex AI Predictor 인터페이스를 서브클래스로 생성합니다.

이 커스텀 예측 루틴 출시에는 재사용 가능한 XGBoost 및 Sklearn 예측자가 함께 제공되지만, 다른 프레임워크를 사용해야 하는 경우 기본 예측자를 서브클래스화하여 자체 예측자를 만들 수 있습니다.

아래에서 Sklearn 예측자의 예를 확인할 수 있습니다. 이는 커스텀 모델 서버를 빌드하기 위해 작성해야 하는 모든 코드입니다.

262df1246b28657e.png

아래 코드를 노트북에 붙여넣어 SklearnPredictor를 서브클래스로 만들고 src_dir/의 Python 파일에 씁니다. 이 예시에서는 예측 메서드가 아닌 로드, 사전 처리, 후처리 메서드만 맞춤설정합니다.

%%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)]}

각 방법을 자세히 살펴보겠습니다.

  • 로드 메서드는 사전 처리 아티팩트에 로드됩니다. 이 경우에는 다이아몬드 명확성 값을 약어에 매핑하는 사전입니다.
  • 전처리 메서드는 이 아티팩트를 사용하여 서빙 시점에 명확성 특성이 축약된 형식인지 확인합니다. 그렇지 않은 경우 전체 문자열을 약어로 변환합니다.
  • 후처리 메서드는 예측 값을 $ 기호가 있는 문자열로 반환하고 값을 반올림합니다.

다음으로 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"),
)

예측을 위한 샘플 2개가 포함된 테스트 파일을 작성합니다. 인스턴스 중 하나는 축약된 명확성 이름을 가지고 있지만, 다른 하나는 먼저 변환해야 합니다.

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

9. Vertex AI에 모델 배포

컨테이너를 로컬에서 테스트했으므로 이제 이미지를 Artifact Registry로 푸시하고 모델을 Vertex AI Model Registry에 업로드합니다.

먼저 Artifact Registry에 액세스하도록 Docker를 구성합니다.

!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}",)

모델이 업로드되면 콘솔에 표시됩니다.

다음으로 온라인 예측에 사용할 수 있도록 모델을 배포합니다. 커스텀 예측 루틴은 일괄 예측에서도 작동하므로 사용 사례에 온라인 예측이 필요하지 않은 경우 모델을 배포할 필요가 없습니다.

그런 다음 이미지를 푸시합니다.

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를 사용하여 다음을 수행하는 방법을 배웠습니다.

  • 커스텀 예측 루틴을 사용하여 커스텀 전처리 및 후처리 로직 작성

Cosmopup은 Codelab이 멋지다고 생각합니다.

e6d3675ca7c6911f.jpeg

다음 단계

추가 자료 및 동영상

참조 문서