Vertex AI:utilizza routine di previsione personalizzate con Sklearn per pre-elaborare e post-elaborare i dati per le previsioni

1. Introduzione

In questo lab imparerai a utilizzare le routine di previsione personalizzate su Vertex AI per scrivere logica di preelaborazione e post-elaborazione personalizzata. Sebbene questo esempio utilizzi Scikit-learn, le routine di previsione personalizzate possono funzionare con altri framework ML Python come XGBoost, PyTorch e TensorFlow.

Cosa imparerai a fare

  • Scrivere una logica di previsione personalizzata con routine di previsione personalizzate
  • Testare localmente il container di servizio e il modello personalizzato
  • Testa il container di pubblicazione personalizzato su Vertex AI Predictions

2. Introduzione a Vertex AI

Questo lab utilizza la più recente offerta di prodotti AI disponibile su Google Cloud. Vertex AI integra le offerte ML di Google Cloud in un'esperienza di sviluppo fluida. In precedenza, i modelli addestrati con AutoML e i modelli personalizzati erano accessibili tramite servizi separati. La nuova offerta combina entrambi in un'unica API, insieme ad altri nuovi prodotti. Puoi anche migrare progetti esistenti su Vertex AI.

Vertex AI include molti prodotti diversi per supportare i flussi di lavoro ML end-to-end. Questo lab si concentrerà su Predictions e Workbench.

440e66b5fde4cee7.png

3. Panoramica del caso d'uso

In questo lab creerai un modello di regressione della foresta casuale per prevedere il prezzo di un diamante in base ad attributi come taglio, purezza e dimensioni.

Scriverai una logica di preelaborazione personalizzata per verificare che i dati al momento della pubblicazione siano nel formato previsto dal modello. Scriverai anche una logica di post-elaborazione personalizzata per arrotondare le previsioni e convertirle in stringhe. Per scrivere questa logica, utilizzerai le routine di previsione personalizzate.

Introduzione alle routine di previsione personalizzate

I container predefiniti di Vertex AI gestiscono le richieste di previsione eseguendo l'operazione di previsione del framework di machine learning. Prima delle routine di previsione personalizzate, se volevi preelaborare l'input prima che venisse eseguita la previsione o post-elaborare la previsione del modello prima di restituire il risultato, dovevi creare un container personalizzato.

La creazione di un container di servizio personalizzato richiede la scrittura di un server HTTP che esegue il wrapping del modello addestrato, traduce le richieste HTTP in input del modello e traduce gli output del modello in risposte.

Con le routine di previsione personalizzate, Vertex AI fornisce i componenti correlati alla pubblicazione, in modo che tu possa concentrarti sul modello e sulle trasformazioni dei dati.

Cosa creerai

Configurerai una rete VPC denominata aiml-vpc composta da una subnet workbench utilizzata per eseguire il deployment di un notebook gestito dall'utente e accedere all'endpoint di previsione e modello online di cui è stato eseguito il deployment in us-central1, come illustrato nella Figura 1 di seguito.

                                                                            Figure1

6ce21c7fdae12b4f.png

4. Abilita le API del tutorial

Passaggio 1: abilita l'API Compute Engine

Vai a Compute Engine e seleziona Abilita se non è già abilitato. Ne avrai bisogno per creare la tua istanza di blocco note.

Passaggio 2: abilita l'API Artifact Registry

Vai ad Artifact Registry e seleziona Abilita se non è già selezionato. Lo utilizzerai per creare un container di servizio personalizzato.

Passaggio 3: abilita l'API Vertex AI

Vai alla sezione Vertex AI della tua console Cloud e fai clic su Abilita API Vertex AI.

Passaggio 4: crea un'istanza di Vertex AI Workbench

Abilita l'API Notebooks, se non l'hai ancora fatto.

5. Crea aiml-vpc

Questo tutorial utilizza le variabili $per facilitare l'implementazione della configurazione di gcloud in Cloud Shell.

In Cloud Shell, esegui le seguenti operazioni:

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

Crea aiml-vpc

In Cloud Shell, esegui le seguenti operazioni:

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

Crea la subnet del notebook gestito dall'utente

In Cloud Shell, crea 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

Configurazione di Cloud Router e NAT

Cloud NAT viene utilizzato nel tutorial per scaricare pacchetti software poiché il notebook gestito dall'utente non dispone di un indirizzo IP esterno. Cloud NAT fornisce funzionalità NAT in uscita, il che significa che gli host internet non sono autorizzati a iniziare la comunicazione con un notebook gestito dall'utente, rendendolo più sicuro.

In Cloud Shell, crea il router Cloud regionale us-central1.

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

In Cloud Shell, crea il gateway Cloud NAT regionale 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. Crea il notebook gestito dall'utente

Crea un service account gestito dall'utente (notebook)

Nella sezione seguente creerai un service account gestito dall'utente che verrà associato a Vertex Workbench (notebook) utilizzato nel tutorial.

Nel tutorial, al service account verranno applicate le seguenti regole:

In Cloud Shell, crea il service account.

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

In Cloud Shell, aggiorna il service account con il ruolo Amministratore storage.

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

In Cloud Shell, aggiorna il service account con il ruolo Utente Vertex AI.

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

In Cloud Shell, aggiorna il service account con il ruolo Amministratore di Artifact Registry.

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

In Cloud Shell, elenca il service account e annota l'indirizzo email che verrà utilizzato durante la creazione del notebook gestito dall'utente.

gcloud iam service-accounts list

Crea il notebook gestito dall'utente

Nella sezione seguente, crea un notebook gestito dall'utente che incorpora il service account creato in precedenza, user-managed-notebook-sa.

In Cloud Shell, crea l'istanza 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. Scrivere il codice di allenamento

Passaggio 1: crea un bucket Cloud Storage

Memorizzerai il modello e gli artefatti di pre-elaborazione in un bucket Cloud Storage. Se hai già un bucket nel progetto che vuoi utilizzare, puoi saltare questo passaggio.

Da Avvio app, apri una nuova sessione di terminale.

84a53a5b528f2507.png

Dal terminale, esegui quanto segue per definire una variabile env per il tuo progetto, assicurandoti di sostituire your-cloud-project con l'ID del tuo progetto:

PROJECT_ID='your-cloud-project'

Successivamente, esegui questo comando nel terminale per creare un nuovo bucket nel tuo progetto.

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

Passaggio 2: addestra il modello

Dal terminale, crea una nuova directory chiamata cpr-codelab e accedi tramite cd.

mkdir cpr-codelab
cd cpr-codelab

Nel browser dei file, vai alla nuova directory cpr-codelab, quindi utilizza il launcher per creare un nuovo notebook Python 3 chiamato task.ipynb.

f230930e0b79650c.png

La directory cpr-codelab dovrebbe avere ora il seguente aspetto:

+ cpr-codelab/
    + task.ipynb

Nel notebook, incolla il seguente codice.

Innanzitutto, scrivi un file 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

Il modello che implementi avrà un insieme diverso di dipendenze preinstallate rispetto all'ambiente del notebook. Per questo motivo, devi elencare tutte le dipendenze del modello in requirements.txt e poi utilizzare pip per installare esattamente le stesse dipendenze nel notebook. Successivamente, testerai il modello localmente prima di eseguirne il deployment su Vertex AI per verificare che gli ambienti corrispondano.

Pip installa le dipendenze nel notebook.

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

Tieni presente che dovrai riavviare il kernel al termine dell'installazione di pip.

A questo punto, crea le directory in cui memorizzerai il modello e gli artefatti di preelaborazione.

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

La directory cpr-codelab dovrebbe avere ora il seguente aspetto:

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

Ora che la struttura delle directory è configurata, è il momento di addestrare un modello.

Innanzitutto, importa le librerie.

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)

Quindi, definisci le seguenti variabili. Assicurati di sostituire PROJECT_ID con il tuo ID progetto e BUCKET_NAME con il bucket che hai creato nel passaggio precedente.

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

Carica i dati dalla libreria seaborn e crea due data frame, uno con le funzionalità e l'altro con l'etichetta.

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

label = 'price'

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

Diamo un'occhiata ai dati di addestramento. Puoi notare che ogni riga rappresenta un diamante.

x_train.head()

e le etichette, ovvero i prezzi corrispondenti.

y_train.head()

Ora, definisci una trasformazione delle colonne sklearn per eseguire la codifica one-hot delle caratteristiche categoriche e scalare le caratteristiche numeriche.

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

Definisci il modello di foresta casuale

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

Successivamente, crea una pipeline sklearn. Ciò significa che i dati inseriti in questa pipeline verranno prima codificati/scalati e poi passati al modello.

my_pipeline = make_pipeline(column_transform, regr)

Adatta la pipeline ai dati di addestramento

my_pipeline.fit(x_train, y_train)

Proviamo il modello per assicurarci che funzioni come previsto. Chiama il metodo predict sul modello, passando un campione di test.

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

Ora possiamo salvare la pipeline nella directory model_artifacts e copiarla nel bucket Cloud Storage

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

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

Passaggio 3: salva un artefatto di preelaborazione

Il passaggio successivo è creare un artefatto di preelaborazione. Questo artefatto verrà caricato nel container personalizzato all'avvio del server del modello. L'artefatto di preelaborazione può essere di quasi qualsiasi forma (ad esempio un file pickle), ma in questo caso scriverai un dizionario in un file JSON.

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

La funzionalità di chiarezza nei nostri dati di addestramento è sempre stata in forma abbreviata (ad es. "FL" anziché "Flawless"). Al momento della pubblicazione, vogliamo verificare che anche i dati di questa funzionalità siano abbreviati. Questo perché il nostro modello sa come codificare "FL" con la codifica one-hot, ma non "Flawless". Scriverai questa logica di preelaborazione personalizzata in un secondo momento. Per ora, salva questa tabella di ricerca in un file JSON e poi scrivila nel bucket 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}/

La directory locale cpr-codelab dovrebbe avere il seguente aspetto:

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

8. Crea un container di servizio personalizzato utilizzando il server di modelli CPR

Ora che il modello è stato addestrato e l'artefatto di preelaborazione è stato salvato, è il momento di creare il container di pubblicazione personalizzato. In genere, la creazione di un container di pubblicazione richiede la scrittura di codice del server del modello. Tuttavia, con le routine di previsione personalizzate, Vertex AI Predictions genera un server di modelli e crea un'immagine container personalizzata per te.

Un container di servizio personalizzato contiene i seguenti tre blocchi di codice:

  1. Server del modello (verrà generato automaticamente dall'SDK e archiviato in scr_dir/)
  • Server HTTP che ospita il modello
  • Responsabile della configurazione di route/porte/ecc.
  1. Request Handler
  • Responsabile degli aspetti del web server della gestione di una richiesta, come la deserializzazione del corpo della richiesta e la serializzazione della risposta, l'impostazione delle intestazioni di risposta e così via.
  • In questo esempio, utilizzerai il gestore predefinito google.cloud.aiplatform.prediction.handler.PredictionHandler fornito nell'SDK.
  1. Predictor
  • Responsabile della logica ML per l'elaborazione di una richiesta di previsione.

Ciascuno di questi componenti può essere personalizzato in base ai requisiti del tuo caso d'uso. In questo esempio, implementerai solo il predittore.

Il predittore è responsabile della logica ML per l'elaborazione di una richiesta di previsione, ad esempio il pre-elaborazione e il post-elaborazione personalizzati. Per scrivere una logica di previsione personalizzata, devi creare una sottoclasse dell'interfaccia Vertex AI Predictor.

Questa release delle routine di previsione personalizzate include predittori XGBoost e Sklearn riutilizzabili, ma se devi utilizzare un framework diverso, puoi creare il tuo eseguendo la sottoclasse del predittore di base.

Di seguito è riportato un esempio di predittore Sklearn. Questo è tutto il codice che dovrai scrivere per creare questo server di modelli personalizzati.

262df1246b28657e.png

Nel notebook, incolla il seguente codice per creare una sottoclasse di SklearnPredictor e scriverla in un file Python in src_dir/. Tieni presente che in questo esempio personalizziamo solo i metodi di caricamento, preelaborazione e post-elaborazione e non il metodo di previsione.

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

Esaminiamo più da vicino ciascuno di questi metodi.

  • Il metodo di caricamento carica l'artefatto di preelaborazione, che in questo caso è un dizionario che mappa i valori di purezza del diamante alle relative abbreviazioni.
  • Il metodo di preelaborazione utilizza questo artefatto per garantire che al momento della pubblicazione la funzionalità di nitidezza sia nel formato abbreviato. In caso contrario, converte l'intera stringa nella sua abbreviazione.
  • Il metodo postprocess restituisce il valore previsto come stringa con il simbolo $ e arrotonda il valore.

Successivamente, utilizza l'SDK Vertex AI Python per creare l'immagine. Utilizzando le routine di previsione personalizzate, verrà generato il Dockerfile e verrà creata un'immagine.

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

Scrivi un file di test con due campioni per la previsione. Una delle istanze ha il nome abbreviato della chiarezza, ma l'altra deve essere convertita prima.

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)

Testa il container localmente eseguendo il deployment di un modello locale.

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

Puoi visualizzare i risultati della previsione con:

predict_response.content

9. Esegui il deployment del modello su Vertex AI

Ora che hai testato il container in locale, è il momento di eseguire il push dell'immagine in Artifact Registry e caricare il modello in Vertex AI Model Registry.

Innanzitutto, configura Docker per accedere ad 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

Quindi, esegui il push dell'immagine.

local_model.push_image()

e carica il modello.

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

Una volta caricato il modello, dovresti vederlo nella console:

Successivamente, esegui il deployment del modello in modo da poterlo utilizzare per le previsioni online. Le routine di previsione personalizzate funzionano anche con le previsioni batch, quindi se il tuo caso d'uso non richiede previsioni online, non devi eseguire il deployment del modello.

Quindi, esegui il push dell'immagine.

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

Infine, testa il modello di cui è stato eseguito il deployment ottenendo una previsione.

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

🎉 Congratulazioni! 🎉

Hai imparato come utilizzare Vertex AI per:

  • Scrivere logiche di pre-elaborazione e post-elaborazione personalizzate con routine di previsione personalizzate

Cosmopup pensa che i codelab siano fantastici.

e6d3675ca7c6911f.jpeg

Passaggi successivi

Ulteriori letture e video

Documentazione di riferimento