Vertex AI로 모델 빌드 및 배포

1. 개요

이 실습에서는 Google Cloud에서 새로 발표한 관리형 ML 플랫폼인 Vertex AI를 사용하여 엔드 투 엔드 ML 워크플로를 빌드하는 방법을 알아봅니다. 원시 데이터에서 배포된 모델로 이동하는 방법을 배우고, 이 워크숍은 Vertex AI를 사용하여 자체 ML 프로젝트를 개발하고 프로덕션화할 수 있도록 준비됩니다. 이 실습에서는 Cloud Shell을 사용하여 Vertex AI로 학습하기 위한 커스텀 컨테이너를 보여주는 커스텀 Docker 이미지를 빌드합니다.

여기서는 모델 코드에 TensorFlow를 사용하지만 다른 프레임워크로 쉽게 교체할 수 있습니다.

학습 내용

다음 작업을 수행하는 방법을 배우게 됩니다.

  • Cloud Shell을 사용하여 모델 학습 코드 빌드 및 컨테이너화
  • Vertex AI에 커스텀 모델 학습 작업 제출
  • 학습된 모델을 엔드포인트에 배포하고 해당 엔드포인트를 사용하여 예측 가져오기

Google Cloud에서 이 실습을 진행하는 데 드는 총 비용은 약 $2입니다.

2. Vertex AI 소개

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

아래 다이어그램에서 볼 수 있듯이 Vertex에는 ML 워크플로의 각 단계에 도움이 되는 다양한 도구가 포함되어 있습니다. 아래에 강조 표시된 Vertex 학습예측을 사용하는 방법을 중점적으로 살펴보겠습니다.

Vertex 서비스

3. 환경 설정

자습형 환경 설정

Cloud 콘솔에 로그인하고 새 프로젝트를 만들거나 기존 프로젝트를 다시 사용합니다. 아직 Gmail이나 Google Workspace 계정이 없는 경우 계정을 만들어야 합니다.

모든 Google Cloud 프로젝트에서 고유한 이름인 프로젝트 ID를 기억하세요(위의 이름은 이미 사용되었으므로 사용할 수 없습니다).

그런 후 Google Cloud 리소스를 사용할 수 있도록 Cloud Console에서 결제를 사용 설정해야 합니다.

이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 가이드를 마친 후 비용이 결제되지 않도록 리소스 종료 방법을 알려주는 '삭제' 섹션의 안내를 따르세요. Google Cloud 신규 사용자에게는 미화$300 상당의 무료 체험판 프로그램에 참여할 수 있는 자격이 부여됩니다.

1단계: Cloud Shell 시작

이 실습에서는 Google 클라우드에서 실행되는 가상 머신이 호스팅하는 명령어 인터프리터인 Cloud Shell 세션에서 작업합니다. 이 섹션은 사용자의 컴퓨터에서 로컬로 쉽게 실행할 수도 있지만, Cloud Shell을 사용하면 모든 사람이 일관되고 재현 가능한 환경에 액세스할 수 있습니다. 실습을 마치고 로컬 컴퓨터에서 이 섹션을 다시 시도하셔도 됩니다.

Cloud Shell 승인

Cloud Shell 활성화

Cloud 콘솔의 오른쪽 상단에서 아래 버튼을 클릭하여 Cloud Shell을 활성화합니다.

Cloud Shell 활성화

이전에 Cloud Shell을 시작한 적이 없는 경우 기능을 설명하는 중간 화면 (스크롤해야 볼 수 있는 부분)이 표시됩니다. 이 경우 계속을 클릭합니다 (다시 표시되지 않음). 이 일회성 화면은 다음과 같습니다.

Cloud Shell 설정

Cloud Shell을 프로비저닝하고 연결하는 데 몇 분 정도만 걸립니다.

Cloud Shell 초기화

가상 머신에는 필요한 개발 도구가 모두 들어 있습니다. 영구적인 5GB 홈 디렉터리를 제공하고 Google Cloud에서 실행되므로 네트워크 성능과 인증이 크게 개선됩니다. 이 Codelab에서 대부분의 작업은 브라우저나 Chromebook만 사용하여 수행할 수 있습니다.

Cloud Shell에 연결되면 인증이 완료되었고 프로젝트가 해당 프로젝트 ID로 이미 설정된 것을 볼 수 있습니다.

Cloud Shell에서 다음 명령어를 실행하여 인증되었는지 확인합니다.

gcloud auth list

명령어 결과

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`

Cloud Shell에서 다음 명령어를 실행하여 gcloud 명령어가 프로젝트를 알고 있는지 확인합니다.

gcloud config list project

명령어 결과

[core]
project = <PROJECT_ID>

또는 다음 명령어로 설정할 수 있습니다.

gcloud config set project <PROJECT_ID>

명령어 결과

Updated property [core/project].

Cloud Shell에는 현재 Cloud 프로젝트의 이름이 포함된 GOOGLE_CLOUD_PROJECT를 비롯한 몇 가지 환경 변수가 있습니다. 이 실습의 다양한 위치에서 이를 사용할 것입니다. 다음을 실행하여 환경 변수를 확인할 수 있습니다.

echo $GOOGLE_CLOUD_PROJECT

2단계: API 사용 설정

이후 단계에서는 이러한 서비스가 필요한 위치와 이유를 설명하겠지만, 지금은 이 명령어를 실행하여 프로젝트에 Compute Engine, Container Registry, Vertex AI 서비스에 대한 액세스 권한을 부여해 보겠습니다.

gcloud services enable compute.googleapis.com         \
                       containerregistry.googleapis.com  \
                       aiplatform.googleapis.com

그러면 다음과 비슷한 성공 메시지가 표시될 것입니다.

Operation "operations/acf.cc11852d-40af-47ad-9d59-477a12847c9e" finished successfully.

3단계: Cloud Storage 버킷 만들기

Vertex AI에서 학습 작업을 실행하려면 저장된 모델 애셋을 저장할 스토리지 버킷이 필요합니다. Cloud Shell 터미널에서 다음 명령어를 실행하여 버킷을 만듭니다.

BUCKET_NAME=gs://$GOOGLE_CLOUD_PROJECT-bucket
gsutil mb -l us-central1 $BUCKET_NAME

4단계: 별칭 Python 3

이 실습의 코드는 Python 3을 사용합니다. 이 실습에서 만들 스크립트를 실행할 때 Python 3를 사용하려면 Cloud Shell에서 다음을 실행하여 별칭을 만듭니다.

alias python=python3

이 실습에서 학습하고 제공할 모델은 TensorFlow 문서의 이 튜토리얼을 기반으로 합니다. 이 튜토리얼에서는 Kaggle의 Auto MPG 데이터 세트를 사용하여 차량의 연비를 예측합니다.

4. 학습 코드 컨테이너화

학습 코드를 Docker 컨테이너에 넣고 이 컨테이너를 Google Container Registry로 푸시하여 이 학습 작업을 Vertex에 제출합니다. 이 접근 방식을 사용하면 모든 프레임워크로 빌드된 모델을 학습시킬 수 있습니다.

1단계: 파일 설정

시작하려면 Cloud Shell의 터미널에서 다음 명령어를 실행하여 Docker 컨테이너에 필요한 파일을 만듭니다.

mkdir mpg
cd mpg
touch Dockerfile
mkdir trainer
touch trainer/train.py

이제 다음과 같은 mpg/ 디렉터리가 생성됩니다.

+ Dockerfile
+ trainer/
    + train.py

이러한 파일을 보고 편집하기 위해 Cloud Shell에 내장된 코드 편집기를 사용합니다. Cloud Shell의 오른쪽 상단 메뉴 바에서 버튼을 클릭하여 편집기와 터미널 간에 전환할 수 있습니다.

Cloud Shell에서 편집기로 전환

2단계: Dockerfile 만들기

코드를 컨테이너화하기 위해 먼저 Dockerfile을 만듭니다. Dockerfile에는 이미지를 실행하는 데 필요한 모든 명령어가 포함됩니다. 사용 중인 모든 라이브러리를 설치하고 학습 코드의 진입점을 설정합니다.

Cloud Shell 파일 편집기에서 mpg/ 디렉터리를 열고 더블클릭하여 Dockerfile을 엽니다.

Dockerfile 열기

그런 다음 아래 내용을 이 파일에 복사합니다.

FROM gcr.io/deeplearning-platform-release/tf2-cpu.2-3
WORKDIR /

# Copies the trainer code to the docker image.
COPY trainer /trainer

# Sets up the entry point to invoke the trainer.
ENTRYPOINT ["python", "-m", "trainer.train"]

이 Dockerfile은 Deep Learning Container TensorFlow Enterprise 2.3 Docker 이미지를 사용합니다. Google Cloud의 Deep Learning Containers에는 많은 수의 일반적인 ML 및 데이터 과학 프레임워크가 사전 설치된 상태로 제공됩니다. 우리가 사용하고 있는 것은 TF Enterprise 2.3, Pandas, scikit-learn 등이 포함됩니다. 이 Dockerfile은 이미지를 다운로드한 후 학습 코드의 진입점을 설정하며 다음 단계에서 추가합니다.

3단계: 모델 학습 코드 추가

다음으로 Cloud Shell 편집기에서 train.py 파일을 열고 아래 코드를 복사합니다 (TensorFlow 문서의 튜토리얼에서 조정됨).

# This will be replaced with your bucket name after running the `sed` command in the tutorial
BUCKET = "BUCKET_NAME"

import numpy as np
import pandas as pd
import pathlib
import tensorflow as tf

from tensorflow import keras
from tensorflow.keras import layers

print(tf.__version__)

"""## The Auto MPG dataset

The dataset is available from the [UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/).

### Get the data
First download the dataset.
"""

"""Import it using pandas"""

dataset_path = "https://storage.googleapis.com/io-vertex-codelab/auto-mpg.csv"
dataset = pd.read_csv(dataset_path, na_values = "?")

dataset.tail()

"""### Clean the data

The dataset contains a few unknown values.
"""

dataset.isna().sum()

"""To keep this initial tutorial simple drop those rows."""

dataset = dataset.dropna()

"""The `"origin"` column is really categorical, not numeric. So convert that to a one-hot:"""

dataset['origin'] = dataset['origin'].map({1: 'USA', 2: 'Europe', 3: 'Japan'})

dataset = pd.get_dummies(dataset, prefix='', prefix_sep='')
dataset.tail()

"""### Split the data into train and test

Now split the dataset into a training set and a test set.

We will use the test set in the final evaluation of our model.
"""

train_dataset = dataset.sample(frac=0.8,random_state=0)
test_dataset = dataset.drop(train_dataset.index)

"""### Inspect the data

Have a quick look at the joint distribution of a few pairs of columns from the training set.

Also look at the overall statistics:
"""

train_stats = train_dataset.describe()
train_stats.pop("mpg")
train_stats = train_stats.transpose()
train_stats

"""### Split features from labels

Separate the target value, or "label", from the features. This label is the value that you will train the model to predict.
"""

train_labels = train_dataset.pop('mpg')
test_labels = test_dataset.pop('mpg')

"""### Normalize the data

Look again at the `train_stats` block above and note how different the ranges of each feature are.

It is good practice to normalize features that use different scales and ranges. Although the model *might* converge without feature normalization, it makes training more difficult, and it makes the resulting model dependent on the choice of units used in the input.

Note: Although we intentionally generate these statistics from only the training dataset, these statistics will also be used to normalize the test dataset. We need to do that to project the test dataset into the same distribution that the model has been trained on.
"""

def norm(x):
  return (x - train_stats['mean']) / train_stats['std']
normed_train_data = norm(train_dataset)
normed_test_data = norm(test_dataset)

"""This normalized data is what we will use to train the model.

Caution: The statistics used to normalize the inputs here (mean and standard deviation) need to be applied to any other data that is fed to the model, along with the one-hot encoding that we did earlier.  That includes the test set as well as live data when the model is used in production.

## The model

### Build the model

Let's build our model. Here, we'll use a `Sequential` model with two densely connected hidden layers, and an output layer that returns a single, continuous value. The model building steps are wrapped in a function, `build_model`, since we'll create a second model, later on.
"""

def build_model():
  model = keras.Sequential([
    layers.Dense(64, activation='relu', input_shape=[len(train_dataset.keys())]),
    layers.Dense(64, activation='relu'),
    layers.Dense(1)
  ])

  optimizer = tf.keras.optimizers.RMSprop(0.001)

  model.compile(loss='mse',
                optimizer=optimizer,
                metrics=['mae', 'mse'])
  return model

model = build_model()

"""### Inspect the model

Use the `.summary` method to print a simple description of the model
"""

model.summary()

"""Now try out the model. Take a batch of `10` examples from the training data and call `model.predict` on it.

It seems to be working, and it produces a result of the expected shape and type.

### Train the model

Train the model for 1000 epochs, and record the training and validation accuracy in the `history` object.

Visualize the model's training progress using the stats stored in the `history` object.

This graph shows little improvement, or even degradation in the validation error after about 100 epochs. Let's update the `model.fit` call to automatically stop training when the validation score doesn't improve. We'll use an *EarlyStopping callback* that tests a training condition for  every epoch. If a set amount of epochs elapses without showing improvement, then automatically stop the training.

You can learn more about this callback [here](https://www.tensorflow.org/api_docs/python/tf/keras/callbacks/EarlyStopping).
"""

model = build_model()

EPOCHS = 1000

# The patience parameter is the amount of epochs to check for improvement
early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=10)

early_history = model.fit(normed_train_data, train_labels, 
                    epochs=EPOCHS, validation_split = 0.2, 
                    callbacks=[early_stop])


# Export model and save to GCS
model.save(BUCKET + '/mpg/model')

위의 코드를 mpg/trainer/train.py 파일에 복사한 후 Cloud Shell의 터미널로 돌아가 다음 명령어를 실행하여 파일에 자체 버킷 이름을 추가합니다.

sed -i "s|BUCKET_NAME|$BUCKET_NAME|g" trainer/train.py

4단계: 로컬에서 컨테이너 빌드 및 테스트

터미널에서 다음을 실행하여 Google Container Registry에 있는 컨테이너 이미지의 URI로 변수를 정의합니다.

IMAGE_URI="gcr.io/$GOOGLE_CLOUD_PROJECT/mpg:v1"

그런 다음 mpg 디렉터리의 루트에서 다음을 실행하여 컨테이너를 빌드합니다.

docker build ./ -t $IMAGE_URI

컨테이너를 빌드한 후에는 Google Container Registry로 푸시합니다.

docker push $IMAGE_URI

이미지가 Container Registry에 푸시되었는지 확인하려면 콘솔의 Container Registry 섹션으로 이동하면 다음과 같은 내용이 표시됩니다.

Container Registry 미리보기

컨테이너가 Container Registry로 푸시되었으므로 이제 커스텀 모델 학습 작업을 시작할 준비가 되었습니다.

5. Vertex AI에서 학습 작업 실행

Vertex는 학습 모델을 위한 두 가지 옵션을 제공합니다.

  • AutoML: 최소한의 수고와 ML 전문 지식으로 고품질 모델을 학습시킵니다.
  • 커스텀 학습: Google Cloud의 사전 빌드된 컨테이너 중 하나를 사용하거나 자체 컨테이너를 사용하여 클라우드에서 커스텀 학습 애플리케이션을 실행합니다.

이 실습에서는 Google Container Registry에서 자체 커스텀 컨테이너를 통해 커스텀 학습을 사용합니다. 시작하려면 Cloud 콘솔의 Vertex 섹션에서 학습 섹션으로 이동합니다.

Vertex 사이드바 메뉴 - 학습

1단계: 학습 작업 시작

만들기를 클릭하여 학습 작업 및 배포된 모델의 매개변수를 입력합니다.

  • 데이터 세트에서 관리형 데이터 세트 없음을 선택합니다.
  • 그런 다음 학습 방법으로 커스텀 학습(고급)을 선택하고 계속을 클릭합니다.
  • 모델 이름mpg (또는 원하는 모델 이름)을 입력합니다.
  • 계속을 클릭합니다.

컨테이너 설정 단계에서 커스텀 컨테이너를 선택합니다.

커스텀 컨테이너 옵션

첫 번째 상자 (컨테이너 이미지)에서 찾아보기를 클릭하고 방금 Container Registry로 푸시한 컨테이너를 찾습니다. 예를 들면 다음과 같습니다.

컨테이너 찾기

나머지 필드는 비워 두고 계속을 클릭합니다.

이 튜토리얼에서는 초매개변수 조정을 사용하지 않으므로 '초매개변수 조정 사용 설정' 체크박스를 선택 해제하고 계속을 클릭합니다.

컴퓨팅 및 가격 책정에서 선택한 리전을 그대로 두고 머신 유형으로 n1-standard-4를 선택합니다.

머신 유형

이 데모의 모델은 학습 속도가 빠르므로 더 작은 머신 유형을 사용합니다.

예측 컨테이너 단계에서 예측 컨테이너 없음을 선택합니다.

예측 컨테이너 없음

6. 모델 엔드포인트 배포

이 단계에서는 학습된 모델의 엔드포인트를 만듭니다. 이를 사용하여 Vertex AI API를 통해 모델에 대한 예측을 수행할 수 있습니다. 이를 위해 내보낸 학습 모델 애셋의 버전을 공개 GCS 버킷에서 사용할 수 있도록 만들었습니다.

조직에서는 한 팀이나 개인이 모델 빌드를 담당하고 다른 팀에서 모델 배포를 담당하는 것이 일반적입니다. 여기서 진행할 단계에서는 이미 학습된 모델을 예측용으로 배포하는 방법을 보여줍니다.

여기서는 Vertex AI SDK를 사용하여 모델을 만들고 엔드포인트에 배포하고 예측을 수행합니다.

1단계: Vertex SDK 설치

Cloud Shell 터미널에서 다음을 실행하여 Vertex AI SDK를 설치합니다.

pip3 install google-cloud-aiplatform --upgrade --user

이 SDK를 사용하여 Vertex의 다양한 부분과 상호작용할 수 있습니다.

2단계: 모델 만들기 및 엔드포인트 배포

다음으로 Python 파일을 만들고 SDK를 사용하여 모델 리소스를 만들고 엔드포인트에 배포합니다. Cloud Shell의 파일 편집기에서 파일새 파일을 차례로 선택합니다.

Cloud Shell의 새 파일

파일 이름을 deploy.py으로 지정합니다. 편집기에서 이 파일을 열고 다음 코드를 복사합니다.

from google.cloud import aiplatform

# Create a model resource from public model assets
model = aiplatform.Model.upload(
    display_name="mpg-imported",
    artifact_uri="gs://io-vertex-codelab/mpg-model/",
    serving_container_image_uri="gcr.io/cloud-aiplatform/prediction/tf2-cpu.2-3:latest"
)

# Deploy the above model to an endpoint
endpoint = model.deploy(
    machine_type="n1-standard-4"
)

그런 다음 Cloud Shell의 터미널로 돌아가서 cd를 다시 루트 디렉터리로 이동한 다음 방금 만든 이 Python 스크립트를 실행합니다.

cd ..
python3 deploy.py | tee deploy-output.txt

리소스가 생성될 때 터미널에 업데이트가 로깅되는 것을 확인할 수 있습니다. 실행하는 데 10~15분 정도 걸립니다. 올바르게 작동하는지 확인하려면 Vertex AI에서 콘솔의 모델 섹션으로 이동합니다.

Vertex 콘솔의 모델

mgp-imported를 클릭하면 해당 모델의 엔드포인트가 생성되는 것을 볼 수 있습니다.

대기 중인 엔드포인트

엔드포인트 배포가 완료되면 Cloud Shell 터미널에 다음 로그가 표시됩니다.

Endpoint model deployed. Resource name: projects/your-project-id/locations/us-central1/endpoints/your-endpoint-id

다음 단계에서 이를 사용하여 배포된 엔드포인트에 대한 예측을 얻습니다.

3단계: 배포된 엔드포인트에서 예측 가져오기

Cloud Shell 편집기에서 predict.py이라는 새 파일을 만듭니다.

예측 파일 만들기

predict.py를 열고 다음 코드를 붙여넣습니다.

from google.cloud import aiplatform

endpoint = aiplatform.Endpoint(
    endpoint_name="ENDPOINT_STRING"
)

# A test example we'll send to our model for prediction
test_mpg = [1.4838871833555929,
 1.8659883497083019,
 2.234620276849616,
 1.0187816540094903,
 -2.530890710602246,
 -1.6046416850441676,
 -0.4651483719733302,
 -0.4952254087173721,
 0.7746763768735953]

response = endpoint.predict([test_mpg])

print('API response: ', response)

print('Predicted MPG: ', response.predictions[0][0])

다음으로 터미널로 돌아가 다음을 입력하여 예측 파일의 ENDPOINT_STRING를 자체 엔드포인트로 바꿉니다.

ENDPOINT=$(cat deploy-output.txt | sed -nre 's:.*Resource name\: (.*):\1:p' | tail -1)
sed -i "s|ENDPOINT_STRING|$ENDPOINT|g" predict.py

이제 predict.py 파일을 실행하여 배포된 모델 엔드포인트에서 예측을 가져올 차례입니다.

python3 predict.py

테스트 예측을 위한 예상 연비 예상과 함께 API의 응답이 로깅됩니다.

🎉 수고하셨습니다. 🎉

Vertex AI를 사용하여 다음을 수행하는 방법을 배웠습니다.

  • 커스텀 컨테이너에 학습 코드를 제공하여 모델을 학습시킵니다. 이 예에서는 TensorFlow 모델을 사용했지만 커스텀 컨테이너를 사용하여 모든 프레임워크로 빌드된 모델을 학습시킬 수 있습니다.
  • 학습에 사용한 것과 동일한 워크플로의 일부로 사전 빌드된 컨테이너를 사용하여 TensorFlow 모델을 배포합니다.
  • 모델 엔드포인트를 만들고 예측을 생성합니다.

Vertex AI의 다른 부분에 대해 자세히 알아보려면 문서를 확인하세요. 5단계에서 시작한 학습 작업의 결과를 확인하려면 Vertex 콘솔의 학습 섹션으로 이동합니다.

7. 삭제

배포한 엔드포인트를 삭제하려면 Vertex 콘솔의 엔드포인트 섹션으로 이동하여 삭제 아이콘을 클릭합니다.

엔드포인트 삭제

스토리지 버킷을 삭제하려면 Cloud 콘솔의 탐색 메뉴를 사용하여 스토리지로 이동하고 버킷을 선택하고 '삭제'를 클릭합니다.

스토리지 삭제