Vertex AI:use rotinas de previsão personalizadas com o Sklearn para pré e pós-processamento de dados para previsões

1. Introdução

Neste laboratório, você vai aprender a usar rotinas de previsão personalizadas na Vertex AI para escrever uma lógica de pré-processamento e pós-processamento personalizada. Embora este exemplo use o Scikit-learn, as rotinas de previsão personalizadas podem funcionar com outros frameworks de ML do Python, como XGBoost, PyTorch e TensorFlow.

O que você vai aprender

  • Escrever uma lógica de previsão personalizada com rotinas de previsão personalizadas
  • Testar o contêiner e o modelo de veiculação personalizados localmente
  • Testar o contêiner de veiculação personalizado no Vertex AI Predictions

2. Introdução à Vertex AI

Este laboratório usa a mais nova oferta de produtos de IA disponível no Google Cloud. A Vertex AI integra as ofertas de ML do Google Cloud em uma experiência de desenvolvimento intuitiva. Anteriormente, modelos treinados com o AutoML e modelos personalizados eram acessíveis por serviços separados. A nova oferta combina ambos em uma única API, com outros novos produtos. Você também pode migrar projetos para a Vertex AI.

A Vertex AI inclui vários produtos diferentes para dar suporte a fluxos de trabalho integrais de ML. O foco deste laboratório é o Predictions e o Workbench.

440e66b5fde4cee7.png

3. Visão geral do caso de uso

Neste laboratório, você vai criar um modelo de regressão de floresta aleatória para prever o preço de um diamante com base em atributos como corte, clareza e tamanho.

Você vai escrever uma lógica de pré-processamento personalizada para verificar se os dados no momento da veiculação estão no formato esperado pelo modelo. Você também vai escrever uma lógica de pós-processamento personalizada para arredondar as previsões e convertê-las em strings. Para escrever essa lógica, você vai usar rotinas de previsão personalizadas.

Introdução às rotinas de previsão personalizadas

Os contêineres pré-criados da Vertex AI processam solicitações de previsão executando a operação de previsão do framework de machine learning. Antes das rotinas de previsão personalizadas, se você quisesse pré-processar a entrada antes da previsão ou pós-processar a previsão do modelo antes de retornar o resultado, seria necessário criar um contêiner personalizado.

A criação de um contêiner de veiculação personalizado exige a gravação de um servidor HTTP que envolve o modelo treinado, converte solicitações HTTP em entradas de modelo e converte saídas de modelo em respostas.

Com as rotinas de previsão personalizadas, a Vertex AI fornece os componentes relacionados à veiculação para que você possa se concentrar no modelo e nas transformações de dados.

O que você vai criar

Você vai configurar uma rede VPC chamada aiml-vpc, que consiste em uma sub-rede do Workbench usada para implantar um notebook gerenciado pelo usuário e acessar o endpoint de previsão e modelo on-line implantado em us-central1, ilustrado na Figura 1 abaixo.

                                                                            Figure1

6ce21c7fdae12b4f.png

4. Ativar as APIs do tutorial

Etapa 1: ativar a API Compute Engine

Navegue até Compute Engine e selecione "Ativar" se ele ainda não estiver ativado. Você vai precisar disso para criar sua instância de notebook.

Etapa 2: ativar a API Artifact Registry

Navegue até Artifact Registry e selecione "Ativar" se ele ainda não estiver ativado. Você vai usar isso para criar um contêiner de veiculação personalizado.

Etapa 3: ativar a API Vertex AI

Navegue até a seção "Vertex AI" do console do Cloud e clique em "Ativar API Vertex AI".

Etapa 4: criar uma instância do Vertex AI Workbench

Ative a API Notebooks se ela ainda não estiver ativada.

5. Criar a aiml-vpc

Este tutorial usa $variables para ajudar na implementação da configuração do gcloud no Cloud Shell.

No Cloud Shell, faça o seguinte:

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

Criar a aiml-vpc

No Cloud Shell, faça o seguinte:

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

Criar a sub-rede de notebook gerenciada pelo usuário

No Cloud Shell, crie a workbench-subnet.

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

Configuração do Cloud Router e do NAT

O Cloud NAT é usado no tutorial para fazer o download de pacotes de software, já que o notebook gerenciado pelo usuário não tem um endereço IP externo. O Cloud NAT oferece recursos de NAT de saída, o que significa que os hosts da Internet não podem iniciar a comunicação com um notebook gerenciado pelo usuário, tornando-o mais seguro.

No Cloud Shell, crie o Cloud Router regional, us-central1.

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

No Cloud Shell, crie o gateway NAT regional do Cloud, 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. Criar o notebook gerenciado pelo usuário

Criar uma conta de serviço gerenciada pelo usuário (notebook)

Na seção a seguir, você vai criar uma conta de serviço gerenciada pelo usuário que será associada ao Vertex Workbench (notebook) usado no tutorial.

No tutorial, a conta de serviço terá as seguintes regras aplicadas:

No Cloud Shell, crie a conta de serviço.

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

No Cloud Shell, atualize a conta de serviço com a função de administrador do Storage.

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

No Cloud Shell, atualize a conta de serviço com a função de usuário da Vertex AI.

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

No Cloud Shell, atualize a conta de serviço com a função de administrador do Artifact Registry.

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

No Cloud Shell, liste a conta de serviço e anote o endereço de e-mail que será usado ao criar o notebook gerenciado pelo usuário.

gcloud iam service-accounts list

Criar o notebook gerenciado pelo usuário

Na seção a seguir, crie um notebook gerenciado pelo usuário que incorpore a conta de serviço criada anteriormente, user-managed-notebook-sa.

No Cloud Shell, crie a instância private-client.

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. Escrever o código de treinamento

Etapa 1: criar um bucket do Cloud Storage

Você vai armazenar o modelo e os artefatos de pré-processamento em um bucket do Cloud Storage. Se você já tiver um bucket no projeto que gostaria de usar, pule esta etapa.

Na tela de início, abra uma nova sessão de terminal.

84a53a5b528f2507.png

No Terminal, execute o seguinte para definir uma variável de ambiente para seu projeto. Não se esqueça de substituir your-cloud-project pelo ID do seu projeto:

PROJECT_ID='your-cloud-project'

Depois execute o comando a seguir no terminal para criar um novo bucket no projeto:

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

Etapa 2: treinar o modelo

No terminal, crie um novo diretório chamado cpr-codelab e coloque cd nele.

mkdir cpr-codelab
cd cpr-codelab

No navegador de arquivos, navegue até o novo diretório cpr-codelab e use a tela de início para criar um novo notebook do Python 3 chamado task.ipynb.

f230930e0b79650c.png

Seu diretório cpr-codelab agora deve ser parecido com este:

+ cpr-codelab/
    + task.ipynb

No notebook, cole o código a seguir.

Primeiro, escreva um arquivo 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

O modelo implantado terá um conjunto diferente de dependências pré-instaladas do que o ambiente do notebook. Por isso, liste todas as dependências do modelo em requirements.txt e use o pip para instalar as mesmas dependências no notebook. Mais tarde, você vai testar o modelo localmente antes de implantá-lo na Vertex AI para verificar se os ambientes correspondem.

O pip instala as dependências no notebook.

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

É necessário reiniciar o kernel após a conclusão da instalação do pip.

Em seguida, crie os diretórios em que você vai armazenar o modelo e os artefatos de pré-processamento.

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

Seu diretório cpr-codelab agora deve ser parecido com este:

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

Agora que a estrutura de diretórios está configurada, é hora de treinar um modelo.

Primeiro, importe as bibliotecas.

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)

Em seguida, defina as variáveis a seguir. Substitua PROJECT_ID pelo ID do projeto e BUCKET_NAME pelo bucket criado na etapa anterior.

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

Carregue os dados da biblioteca do Seaborn e crie dois data frames, um com os atributos e outro com o rótulo.

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

label = 'price'

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

Vamos analisar os dados de treinamento. Cada linha representa um diamante.

x_train.head()

E os rótulos, que são os preços correspondentes.

y_train.head()

Agora, defina uma transformação de coluna do sklearn column transform para codificar em one-hot os atributos categóricos e escalonar os recursos numéricos.

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

Defina o modelo de floresta aleatória.

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

Em seguida, crie um pipeline sklearn. Isso significa que os dados transmitidos a esse pipeline serão codificados/escalonados e transmitidos ao modelo.

my_pipeline = make_pipeline(column_transform, regr)

Ajuste o pipeline nos dados de treinamento.

my_pipeline.fit(x_train, y_train)

Vamos testar o modelo para garantir que ele esteja funcionando conforme o esperado. Chame o método de previsão no modelo, transmitindo um exemplo de teste.

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

Agora podemos salvar o pipeline no diretório model_artifacts e copiá-lo para o bucket do Cloud Storage.

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

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

Etapa 3: salvar um artefato de pré-processamento

Em seguida, você vai criar um artefato de pré-processamento. Esse artefato será carregado no contêiner personalizado quando o servidor de modelo for iniciado. O artefato de pré-processamento pode ter quase qualquer forma (como um arquivo Pickle), mas nesse caso você vai gravar um dicionário em um arquivo JSON.

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

O recurso de clareza nos nossos dados de treinamento sempre estava na forma abreviada (ou seja, "FL" em vez de "Flawless"). No momento da veiculação, queremos verificar se os dados desse atributo também são abreviados. Isso ocorre porque nosso modelo sabe como fazer uma codificação one-hot "FL", mas não "Flawless". Você escreverá essa lógica de pré-processamento personalizada mais tarde. Mas, por enquanto, salve essa tabela de consulta em um arquivo JSON e, em seguida, grave-a no bucket do 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}/

Seu diretório cpr-codelab local agora deve ser parecido com este:

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

8. Crie um contêiner de veiculação personalizado usando o servidor do modelo de CPR

Agora que o modelo foi treinado e o artefato de pré-processamento foi salvo, é hora de criar o contêiner de veiculação personalizado. Normalmente, a criação de um contêiner de veiculação exige a gravação de um código de servidor de modelo. No entanto, com rotinas de previsão personalizadas, o Vertex AI Predictions gera um servidor de modelo e cria uma imagem de contêiner personalizada para você.

Um contêiner de veiculação personalizado contém os três códigos a seguir:

  1. Servidor de modelo (será gerado automaticamente pelo SDK e armazenado em scr_dir/)
  • Servidor HTTP que hospeda o modelo
  • Responsável pela configuração de rotas/portas/etc.
  1. Processador de solicitações
  • Responsável pelos aspectos do servidor da Web de processamento de uma solicitação, como desserializar o corpo da solicitação e serializar a resposta, definir cabeçalhos de resposta etc.
  • Neste exemplo, você vai usar o processador padrão, google.cloud.aiplatform.prediction.handler.PredictionHandler, fornecido no SDK.
  1. Predictor
  • Responsável pela lógica de ML para processar uma solicitação de previsão.

Cada um desses componentes pode ser personalizado com base nos requisitos do seu caso de uso. Neste exemplo, você só vai implementar o predictor.

O predictor é responsável pela lógica de ML para processar uma solicitação de previsão, como pré-processamento e pós-processamento personalizados. Para escrever uma lógica de previsão personalizada, você cria uma subclasse da interface do predictor da Vertex AI.

Essa versão de rotinas de previsão personalizadas vem com predictors XGBoost e Sklearn reutilizáveis, mas, se você precisar usar um framework diferente, poderá criar seu próprio criando uma subclasse do predictor de base.

Confira um exemplo do predictor Sklearn abaixo. Esse é todo o código necessário para criar esse servidor de modelo personalizado.

262df1246b28657e.png

No notebook, cole o código abaixo para criar uma subclasse do SklearnPredictor e gravá-la em um arquivo Python em src_dir/. Neste exemplo, estamos apenas personalizando os métodos de carregamento, pré-processamento e pós-processamento, e não o método de previsão.

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

Vamos analisar cada um desses métodos.

  • O método de carregamento carrega o artefato de pré-processamento, que, nesse caso, é um dicionário que mapeia os valores de clareza do diamante para as abreviações.
  • O método de pré-processamento usa esse artefato para garantir que, no momento da veiculação, o recurso de clareza esteja no formato abreviado. Caso contrário, ele converte a string completa para a abreviação.
  • O método de pós-processamento retorna o valor previsto como uma string com um sinal de dólar e arredonda o valor.

Em seguida, use o SDK da Vertex AI para Python para criar a imagem. Usando rotinas de previsão personalizadas, o Dockerfile será gerado e uma imagem será criada para você.

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

Escreva um arquivo de teste com dois exemplos para previsão. Uma das instâncias tem o nome abreviado, mas a outra precisa ser convertida primeiro.

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)

Teste o contêiner localmente implantando um modelo local.

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()

Para conferir os resultados da previsão, use:

predict_response.content

9. Implantar o modelo na Vertex AI

Agora que você testou o contêiner localmente, é hora de enviar a imagem para o Artifact Registry e fazer upload do modelo para o Vertex AI Model Registry.

Primeiro, configure o Docker para acessar o 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

Em seguida, envie a imagem.

local_model.push_image()

E faça o upload do modelo.

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

Quando o modelo for enviado, ele vai aparecer no console:

Em seguida, implante o modelo para que você possa usá-lo para previsões on-line. As rotinas de previsão personalizadas também funcionam com a previsão em lote. Portanto, se o caso de uso não exigir previsões on-line, não será necessário implantar o modelo.

Em seguida, envie a imagem.

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

Por fim, teste o modelo implantado recebendo uma previsão.

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

Parabéns! 🎉

Você aprendeu a usar a Vertex AI para:

  • Escrever uma lógica de pré-processamento e pós-processamento personalizada com rotinas de previsão personalizadas

O Cosmopup acha que os codelabs são incríveis.

e6d3675ca7c6911f.jpeg

Qual é a próxima etapa?

Leituras e vídeos adicionais

Documentos de referência