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

1. Panoramica

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

Cosa imparerai

Al termine del corso sarai in grado di:

  • Scrivere una logica di previsione personalizzata con routine di previsione personalizzate
  • Testa il contenitore e il modello di pubblicazione personalizzati in locale
  • Testa il container di pubblicazione personalizzato su Vertex AI Predictions

Il costo totale per eseguire questo lab su Google Cloud è di circa 1$.

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 è incentrato su Predizioni e Workbench.

Panoramica dei prodotti Vertex

3. Panoramica del caso d'uso

Caso d'uso

In questo lab creerai un modello di regressione con foresta casuale per prevedere il prezzo di un diamante in base ad attributi come taglio, chiarezza 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 pre-elaborare l'input prima di eseguire la previsione o post-elaborare la previsione del modello prima di restituire il risultato, dovevi creare un contenitore personalizzato.

La creazione di un contenitore di pubblicazione personalizzato richiede la scrittura di un server HTTP che ingloba il modello addestrato, traduce le richieste HTTP in input del modello e le uscite del modello in risposte.

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

4. Configura l'ambiente

Per eseguire questo codelab, devi avere un progetto Google Cloud con la fatturazione abilitata. Per creare un progetto, segui le istruzioni riportate qui.

Passaggio 1: abilita l'API Compute Engine

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

Passaggio 2: abilita l'API Artifact Registry

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

Passaggio 3: abilita l'API Vertex AI

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

Dashboard di Vertex AI

Passaggio 4: crea un'istanza di Vertex AI Workbench

Nella sezione Vertex AI della console Cloud, fai clic su Workbench:

Menu Vertex AI

Abilita l'API Notebooks, se non lo è già.

Notebook_api

Una volta attivata, fai clic su ISTANZE e poi seleziona CREA NUOVA.

Accetta le opzioni predefinite e fai clic su Crea.

Quando l'istanza è pronta, fai clic su APRI JUPYTERLAB per aprirla.

5. Scrivere codice di addestramento

Passaggio 1: crea un bucket Cloud Storage

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

Dal programma di avvio, apri una nuova sessione di terminale.

Open_terminal

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

PROJECT_ID='your-cloud-project'

Successivamente, esegui il seguente comando nel terminale per creare un nuovo bucket nel progetto.

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

Passaggio 2: addestrare il modello

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

mkdir cpr-codelab
cd cpr-codelab

Nel browser di file, vai alla nuova directory cpr-codelab e utilizza il programma di avvio per creare un nuovo blocco note Python 3 denominato task.ipynb.

file_browser

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

+ cpr-codelab/
    + task.ipynb

Incolla il codice seguente nel blocco note.

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

Il modello di cui esegui il deployment avrà un set di dipendenze diverso preinstallato rispetto all'ambiente del tuo blocco note. Per questo motivo, ti consigliamo di elencare tutte le dipendenze del modello in requirements.txt e di utilizzare pip per installare le stesse dipendenze nel notebook. Successivamente, testerai il modello localmente prima di eseguirne il deployment in Vertex AI per verificare la corrispondenza degli ambienti.

Pip installa le dipendenze nel blocco note.

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

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

restart_kernel

Quindi, crea le directory in cui archivierai il modello e gli artefatti di pre-elaborazione.

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 ora avere il seguente aspetto:

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

Ora che la struttura della 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)

Poi 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 poi crea due dataframe, 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 vedere che ogni riga rappresenta un diamante.

x_train.head()

e le etichette, ovvero i prezzi corrispondenti.

y_train.head()

Ora definisci una trasformazione della colonna sklearn per eseguire la codifica one-hot delle caratteristiche categoriche e la scalatura delle caratteristiche numeriche

column_transform = make_column_transformer(
    (preprocessing.OneHotEncoder(), [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)

A questo punto, crea una pipeline sklearn. Ciò significa che i dati inviati a questa pipeline verranno prima codificati/riscalati e poi trasmessi 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 esempio 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 pre-elaborazione

Ora crea un artefatto di preelaborazione. Questo artefatto verrà caricato nel contenitore personalizzato all'avvio del server di modelli. L'elemento pre-elaborazione 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à clarity nei nostri dati di addestramento era sempre in forma abbreviata (ovvero "FL" invece di "Flawless"). Al momento della pubblicazione, vogliamo verificare che i dati per questa funzionalità siano anche abbreviati. Questo perché il nostro modello sa come codificare in one hot "FL", ma non "Flawless". Scriverai questa logica di pre-elaborazione personalizzata in un secondo momento. Per il momento, però, salva questa tabella di ricerca in un file json e poi scrivilo 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 cpr-codelab locale ora dovrebbe avere il seguente aspetto:

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

6. Crea un contenitore di pubblicazione personalizzato utilizzando il server del modello CPR

Ora che il modello è stato addestrato e l'elemento di preelaborazione è stato salvato, è il momento di creare il contenitore di pubblicazione personalizzato. In genere, la creazione di un contenitore 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 contenitore di pubblicazione personalizzato contiene i seguenti tre frammenti di codice:

  1. Server modello (viene generato automaticamente dall'SDK e archiviato in scr_dir/)
    • Server HTTP che ospita il modello
    • Responsabile della configurazione di route/porte ecc.
  2. Gestore delle richieste
    • Responsabile degli aspetti del web server per la 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 l'Handler predefinito google.cloud.aiplatform.prediction.handler.PredictionHandler fornito nell'SDK.
  3. Predizione
    • Responsabile della logica ML per l'elaborazione di una richiesta di previsione.

Ognuno 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 la pre-elaborazione e la post-elaborazione personalizzate. Per scrivere una logica di previsione personalizzata, dovrai creare una sottoclasse dell'interfaccia di Vertex AI Predictor.

Questa release delle routine di previsione personalizzate include predittori XGBoost e Sklearn riutilizzabili, ma se devi utilizzare un framework diverso, puoi crearne uno tuo sottoclassificando il predittore di base.

Di seguito è riportato un esempio di predittore Sklearn. Questo è tutto il codice da scrivere per creare il server del modello personalizzato.

sklearn_predictor

Nel notebook, incolla il seguente codice per creare una sottoclasse di SklearnPredictor e scrivilo in un file Python in src_dir/. Tieni presente che in questo esempio personalizziamo solo i metodi load, preprocess e postprocess, non il metodo 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)]}

Esaminiamo più da vicino ciascuno di questi metodi.

  • Il metodo load viene caricato nell'elemento artefatto di preelaborazione, che in questo caso è un dizionario che mappa i valori di purezza del diamante alle relative abbreviazioni.
  • il metodo preprocess utilizza questo artefatto per garantire che al momento della pubblicazione la funzionalità di chiarezza sia nel formato abbreviato. In caso contrario, la stringa completa viene convertita nella relativa abbreviazione.
  • Il metodo postprocess restituisce il valore previsto come stringa con un segno $ e lo arrotondamento.

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

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 esempi per la previsione. Una delle istanze ha il nome chiaro abbreviato, ma l'altra deve essere prima convertita.

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 contenitore 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

7. Esegui il deployment del modello in Vertex AI

Ora che hai testato il container in locale, è il momento di eseguire il push dell'immagine ad Artifact Registry e di 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, invia l'immagine.

local_model.push_image()

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 dovrebbe essere visualizzato nella console:

model_registry

Poi, 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 è necessario eseguire il deployment del modello.

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

🎉 Complimenti! 🎉

Hai imparato come utilizzare Vertex AI per:

  • Scrivi una logica di preelaborazione e postelaborazione personalizzata con routine di previsione personalizzate

Per saperne di più sulle diverse parti di Vertex AI, consulta la documentazione.

8. Esegui la pulizia

Se vuoi continuare a utilizzare il blocco note creato in questo lab, ti consigliamo di disattivarlo quando non lo usi. Dall'interfaccia utente di Workbench nella console Google Cloud, seleziona il blocco note e poi Interrompi.

Se vuoi eliminare completamente il blocco note, fai clic sul pulsante Elimina in alto a destra.

Stop_nb

Per eliminare l'endpoint di cui hai eseguito il deployment, vai alla sezione Endpoint della console, fai clic sull'endpoint che hai creato e seleziona Annulla il deployment del modello nell'endpoint:

delete_endpoint

Per eliminare l'immagine container, vai ad Artifact Registry, seleziona il repository che hai creato e seleziona Elimina.

delete_image

Per eliminare il bucket di archiviazione, utilizza il menu di navigazione nella console Cloud, vai a Archiviazione, seleziona il bucket e fai clic su Elimina:

Eliminare lo spazio di archiviazione