Previsione con una pipeline scikit-learn personalizzata

Logo Colab Esegui questo tutorial come blocco note in Colab Logo di GitHub Visualizza il notebook su GitHub

Questo tutorial mostra come utilizzare AI Platform Prediction per eseguire il deployment di una pipeline di scikit-learn che utilizza trasformatori personalizzati.

Le pipeline di scikit-learn ti consentono di comporre più stimatori. Ad esempio, puoi utilizzare i trasformatori per pre-elaborare i dati e trasmetterli a un classificatore. scikit-learn fornisce molti trasformatori nel pacchetto sklearn.

Puoi anche utilizzare la classe FunctionTransformer o TransformerMixin di scikit-learn per creare il tuo trasformatore personalizzato. Se vuoi eseguire il deployment di una pipeline che utilizza trasformatori personalizzati in AI Platform Prediction, devi fornire il codice a AI Platform Prediction come pacchetto di distribuzione di origine.

Questo tutorial presenta un problema di esempio che coinvolge i dati del censimento per illustrare i seguenti passaggi:

  • Addestramento di una pipeline di scikit-learn con trasformatori personalizzati in AI Platform Training
  • Esegui il deployment della pipeline addestrata e del tuo codice personalizzato in AI Platform Prediction
  • Pubblicazione delle richieste di previsione da quel deployment

Set di dati

Questo tutorial utilizza il set di dati sul reddito del censimento degli Stati Uniti fornito dal repository UC Irvine Machine Learning. Questo set di dati contiene informazioni su persone di un database del censimento del 1994, tra cui età, istruzione, stato civile, professione e se guadagnano più di 50.000 $all'anno.

I dati utilizzati in questo tutorial sono disponibili in un bucket Cloud Storage pubblico: gs://cloud-samples-data/ai-platform/sklearn/census_data/

Obiettivo

L'obiettivo è addestrare una pipeline scikit-learn che preveda se una persona guadagna più di 50.000 $all'anno (etichetta target) in base ad altre informazioni del censimento sulla persona (funzionalità).

Questo tutorial si concentra più sull'utilizzo di questo modello con AI Platform Prediction che sul design del modello stesso. Tuttavia, è sempre importante pensare ai potenziali problemi e alle conseguenze indesiderate durante la creazione di sistemi di machine learning. Consulta l'esercizio del Machine Learning Crash Course sull'equità per scoprire le fonti di bias nel set di dati del censimento, nonché l'equità del machine learning in generale.

Costi

Questo tutorial utilizza i componenti fatturabili di Google Cloud:

  • AI Platform Training
  • AI Platform Prediction
  • Cloud Storage

Scopri di più sui prezzi di AI Platform Training, su quelli di AI Platform Prediction e su quelli di Cloud Storage e utilizza il Calcolatore prezzi per generare una stima dei costi in base all'utilizzo previsto.

Prima di iniziare

Prima di poter addestrare e implementare un modello su AI Platform Prediction, devi svolgere diverse operazioni:

  • Configura l'ambiente di sviluppo locale.
  • Configura un progetto Google Cloud con la fatturazione e le API necessarie abilitate.
  • Crea un bucket Cloud Storage per archiviare il pacchetto di addestramento e il modello addestrato.

Configura l'ambiente di sviluppo locale

Per completare questo tutorial, devi disporre di quanto segue:

  • Python 3
  • virtualenv
  • Google Cloud SDK

La guida di Google Cloud alla configurazione di un ambiente di sviluppo Python fornisce istruzioni dettagliate per soddisfare questi requisiti. I passaggi riportati di seguito forniscono un insieme di istruzioni condensate:

  1. Installa Python 3.

  2. Installa virtualenv e crea un ambiente virtuale che utilizzi Python 3.

  3. Attiva l'ambiente.

  4. Completa i passaggi descritti nella sezione seguente per installare l'Google Cloud SDK.

Configurare il progetto Google Cloud

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the AI Platform Training & Prediction and Compute Engine APIs.

    Enable the APIs

  5. Install the Google Cloud CLI.
  6. To initialize the gcloud CLI, run the following command:

    gcloud init
  7. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  8. Make sure that billing is enabled for your Google Cloud project.

  9. Enable the AI Platform Training & Prediction and Compute Engine APIs.

    Enable the APIs

  10. Install the Google Cloud CLI.
  11. To initialize the gcloud CLI, run the following command:

    gcloud init

Autentica il tuo account Google Cloud

Per configurare l'autenticazione, devi creare una chiave dell'account di servizio e impostare una variabile di ambiente per il percorso del file della chiave dell'account di servizio.

  1. Crea un account di servizio:

    1. Nella console Google Cloud, vai alla pagina Crea account di servizio.

      Vai a Crea account di servizio

    2. Inserisci un nome nel campo Nome account di servizio.
    3. (Facoltativo) Nel campo Descrizione account di servizio, inserisci una descrizione.
    4. Fai clic su Crea.
    5. Fai clic sul campo Seleziona un ruolo. In Tutti i ruoli, seleziona AI Platform > Amministratore AI Platform.
    6. Fai clic su Aggiungi un altro ruolo.
    7. Fai clic sul campo Seleziona un ruolo. In Tutti i ruoli, seleziona Storage > Storage Object Admin.

    8. Fai clic su Fine per creare l'account di servizio.

      Non chiudere la finestra del browser. Lo utilizzerai nel passaggio successivo.

  2. Crea una chiave dell'account di servizio per l'autenticazione:

    1. Nella console Google Cloud, fai clic sull'indirizzo email dell'account di servizio che hai creato.
    2. Fai clic su Chiavi.
    3. Fai clic su Aggiungi chiave, quindi su Crea nuova chiave.
    4. Fai clic su Crea. Un file della chiave JSON viene scaricato sul computer.
    5. Fai clic su Chiudi.
  3. Imposta la variabile di ambiente GOOGLE_APPLICATION_CREDENTIALS sul percorso del file JSON contenente la chiave dell'account di servizio. Questa variabile si applica solo alla sessione di shell corrente, quindi se apri una nuova sessione, imposta di nuovo la variabile.

Crea un bucket Cloud Storage

Questo tutorial utilizza Cloud Storage in diversi modi:

  • Quando invii un job di addestramento utilizzando Cloud SDK, carichi un pacchetto Python contenente il codice di addestramento in un bucket Cloud Storage. AI Platform Training esegue il codice di questo pacchetto.

  • In questo tutorial, AI Platform Training salva anche il modello addestrato generato dal tuo job nello stesso bucket.

  • Per eseguire il deployment della pipeline scikit-learn che utilizza codice personalizzato in AI Platform Prediction, devi caricare gli strumenti di trasformazione personalizzati utilizzati dalla pipeline su Cloud Storage.

Quando crei la risorsa della versione di AI Platform Prediction che genera le previsioni, fornisci la pipeline scikit-learn addestrata e il tuo codice personalizzato come URI di Cloud Storage.

Imposta il nome del bucket Cloud Storage come variabile di ambiente. Deve essere univoco in tutti i bucket Cloud Storage:

BUCKET_NAME="your-bucket-name"

Seleziona una regione in cui sono disponibili AI Platform Training e AI Platform Prediction e crea un'altra variabile di ambiente. Ad esempio:

REGION="us-central1"

Crea il bucket Cloud Storage in questa regione e, in un secondo momento, utilizza la stessa regione per l'addestramento e la previsione. Esegui il comando seguente per creare il bucket se non esiste già:

gcloud storage buckets create gs://$BUCKET_NAME --location=$REGION

Creazione di un'applicazione di addestramento e del codice della pipeline personalizzata

Crea un'applicazione per addestrare una pipeline scikit-learn con i dati del censimento. In questo tutorial, il pacchetto di addestramento contiene anche il codice personalizzato utilizzato dalla pipeline addestrata durante la previsione. Si tratta di un pattern utile, perché le pipeline sono generalmente progettate per utilizzare gli stessi trasformatori durante l'addestramento e la previsione.

Per creare una directory contenente tre file che corrisponde alla seguente struttura:

census_package/
    __init__.py
    my_pipeline.py
    train.py

Innanzitutto, crea la directory census_package/ vuota:

mkdir census_package

In census_package/, crea un file vuoto denominato __init__.py :

touch ./census_package/__init__.py

In questo modo è possibile importare census_package/ come pacchetto in Python.

Creare trasformatori personalizzati

scikit-learn fornisce molti strumenti di trasformazione che puoi utilizzare all'interno di una pipeline, ma ti consente anche di definire i tuoi strumenti di trasformazione personalizzati. Questi trasformatori possono persino apprendere uno stato salvato durante l'addestramento che viene utilizzato in un secondo momento durante la previsione.

Estendi sklearn.base.TransformerMixin per definire tre trasformatori:

  • PositionalSelector: dato un elenco di indici C e una matrice M, restituisce una matrice con un sottoinsieme di colonne di M, indicato da C.

  • StripString: data una matrice di stringhe, rimuove gli spazi da ogni stringa.

  • SimpleOneHotEncoder: un semplice codificatore one-hot che può essere applicato a una matrice di stringhe.

Per farlo, scrivi il seguente codice in un file denominato census_package/my_pipeline.py.

import numpy as np
from sklearn.base import BaseEstimator, TransformerMixin


class PositionalSelector(BaseEstimator, TransformerMixin):
    def __init__(self, positions):
        self.positions = positions

    def fit(self, X, y=None):
        return self

    def transform(self, X):
        return np.array(X)[:, self.positions]


class StripString(BaseEstimator, TransformerMixin):
    def fit(self, X, y=None):
        return self

    def transform(self, X):
        strip = np.vectorize(str.strip)
        return strip(np.array(X))


class SimpleOneHotEncoder(BaseEstimator, TransformerMixin):
    def fit(self, X, y=None):
        self.values = []
        for c in range(X.shape[1]):
            Y = X[:, c]
            values = {v: i for i, v in enumerate(np.unique(Y))}
            self.values.append(values)
        return self

    def transform(self, X):
        X = np.array(X)
        matrices = []
        for c in range(X.shape[1]):
            Y = X[:, c]
            matrix = np.zeros(shape=(len(Y), len(self.values[c])), dtype=np.int8)
            for i, x in enumerate(Y):
                if x in self.values[c]:
                    matrix[i][self.values[c][x]] = 1
            matrices.append(matrix)
        res = np.concatenate(matrices, axis=1)
        return res

Definisci la pipeline e crea il modulo di addestramento

A questo punto, crea un modulo di addestramento per addestrare la pipeline scikit-learn sui dati del censimento. Parte di questo codice prevede la definizione della pipeline.

Questo modulo di formazione consente di svolgere diverse attività:

  • Scarica i dati di addestramento e li carica in un DataFrame Pandas che può essere utilizzato da Scikit-Learn.
  • Definisce la pipeline di scikit-learn da addestrare. Questo esempio utilizza solo tre caratteristiche numeriche ('age', 'education-num' e 'hours-per-week') e tre caratteristiche categoriche ('workclass', 'marital-status' e 'relationship') dai dati di input. Trasforma le caratteristiche numeriche utilizzando la funzione interna di scikit-learn StandardScaler e quelle categoriche con l'encoder one-hot personalizzato definito in my_pipeline.py. Quindi combina i dati pre-elaborati come input per un classificatore.
  • Infine, esporta il modello utilizzando la versione di joblib inclusa in scikit-learn e lo salva nel tuo bucket Cloud Storage.

Scrivi il seguente codice in census_package/train.py:

import warnings
import argparse
from google.cloud import storage

import pandas as pd
import numpy as np
from sklearn.externals import joblib
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.pipeline import Pipeline, FeatureUnion, make_pipeline
import census_package.my_pipeline as mp
warnings.filterwarnings('ignore')


def download_data(bucket_name, gcs_path, local_path):
    bucket = storage.Client().bucket(bucket_name)
    blob = bucket.blob(gcs_path)
    blob.download_to_filename(local_path)


def upload_data(bucket_name, gcs_path, local_path):
    bucket = storage.Client().bucket(bucket_name)
    blob = bucket.blob(gcs_path)
    blob.upload_from_filename(local_path)


def get_features_target(local_path):
    strip = np.vectorize(str.strip)
    raw_df = pd.read_csv(local_path, header=None)
    target_index = len(raw_df.columns) - 1  # Last columns, 'income-level', is the target

    features_df = raw_df.drop(target_index, axis=1)
    features = features_df.as_matrix()
    target = strip(raw_df[target_index].values)
    return features, target


def create_pipeline():
    # We want to use 3 categorical and 3 numerical features in this sample.
    # Categorical features: age, education-num, and hours-per-week
    # Numerical features: workclass, marital-status, and relationship
    numerical_indices = [0, 4, 12]  # age, education-num, and hours-per-week
    categorical_indices = [1, 5, 7]  # workclass, marital-status, and relationship

    p1 = make_pipeline(mp.PositionalSelector(categorical_indices), mp.StripString(), mp.SimpleOneHotEncoder())
    p2 = make_pipeline(mp.PositionalSelector(numerical_indices), StandardScaler())

    feats = FeatureUnion([
        ('numericals', p1),
        ('categoricals', p2),
    ])

    pipeline = Pipeline([
        ('pre', feats),
        ('estimator', GradientBoostingClassifier(max_depth=4, n_estimators=100))
    ])
    return pipeline


def get_bucket_path(gcs_uri):
    if not gcs_uri.startswith('gs://'):
        raise Exception('{} does not start with gs://'.format(gcs_uri))
    no_gs_uri = gcs_uri[len('gs://'):]
    first_slash_index = no_gs_uri.find('/')
    bucket_name = no_gs_uri[:first_slash_index]
    gcs_path = no_gs_uri[first_slash_index + 1:]
    return bucket_name, gcs_path


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--gcs_data_path', action="store", required=True)
    parser.add_argument('--gcs_model_path', action="store", required=True)

    arguments, others = parser.parse_known_args()

    local_path = '/tmp/adul.data'
    data_bucket, data_path = get_bucket_path(arguments.gcs_data_path)
    print('Downloading the data...')
    download_data(data_bucket, data_path, local_path)
    features, target = get_features_target(local_path)
    pipeline = create_pipeline()

    print('Training the model...')
    pipeline.fit(features, target)

    joblib.dump(pipeline, './model.joblib')

    model_bucket, model_path = get_bucket_path(arguments.gcs_model_path)
    upload_data(model_bucket, model_path, './model.joblib')
    print('Model was successfully uploaded.')

Addestramento della pipeline su AI Platform Training

Utilizza gcloud per inviare un job di addestramento ad AI Platform Training. Il seguente comando pacchettizza l'applicazione di addestramento, la carica su Cloud Storage e indica ad AI Platform Training di eseguire il modulo di addestramento.

L'argomento -- è un separatore: il servizio di AI Platform Training non utilizza gli argomenti che seguono il separatore, ma il modulo di addestramento può comunque accedervi.

gcloud ai-platform jobs submit training census_training_$(date +"%Y%m%d_%H%M%S") \
  --job-dir gs://$BUCKET_NAME/custom_pipeline_tutorial/job \
  --package-path ./census_package \
  --module-name census_package.train \
  --region $REGION \
  --runtime-version 1.13 \
  --python-version 3.5 \
  --scale-tier BASIC \
  --stream-logs \
  -- \
  --gcs_data_path gs://cloud-samples-data/ai-platform/census/data/adult.data.csv \
  --gcs_model_path gs://$BUCKET_NAME/custom_pipeline_tutorial/model/model.joblib

Esegui il deployment della pipeline e pubblica le previsioni

Per pubblicare le previsioni di AI Platform Prediction, devi eseguire il deployment di una risorsa modello e di una risorsa versione. Il modello ti aiuta a organizzare più deployment se modifichi e addestri la pipeline più volte. La versione utilizza il modello addestrato e il codice personalizzato per fornire le previsioni.

Per eseguire il deployment di queste risorse, devi fornire due elementi:

  • Una directory Cloud Storage contenente la pipeline addestrata. Il job di addestramento del passaggio precedente ha creato questo file durante l'esportazione di model.joblib nel tuo bucket.
  • Un pacchetto di distribuzione di origine .tar.gz in Cloud Storage contenente tutti gli strumenti di trasformazione personalizzati utilizzati dalla pipeline. Creala nel passaggio successivo.

Crea un pacchetto dei trasformatori personalizzati

Se esegui il deployment di una versione senza fornire il codice di my_pipeline.py, AI Platform Prediction non potrà importare i trasformatori personalizzati (ad es. mp.SimpleOneHotEncoder) e non potrà fornire le previsioni.

Crea il seguente setup.py per definire un pacchetto di distribuzione di origine per il tuo codice:

import setuptools
setuptools.setup(name='census_package',
      packages=['census_package'],
      version="1.0",
      )

Quindi, esegui il seguente comando per creare dist/census_package-1.0.tar.gz:

python setup.py sdist --formats=gztar

Infine, carica questo file tarball nel tuo bucket Cloud Storage:

gcloud storage cp ./dist/census_package-1.0.tar.gz gs://$BUCKET_NAME/custom_pipeline_tutorial/code/census_package-1.0.tar.gz

Creare risorse di modelli e versioni

Innanzitutto, definisci i nomi del modello e della versione:

MODEL_NAME='CensusPredictor'
VERSION_NAME='v1'

Utilizza quindi il seguente comando per creare la risorsa modello:

gcloud ai-platform models create $MODEL_NAME \
  --regions $REGION

Infine, crea la risorsa della versione fornendo i percorsi Cloud Storage alla directory del modello (quella che contiene model.joblib) e al codice personalizzato (census_package-1.0.tar.gz):

gcloud components install beta

gcloud beta ai-platform versions create $VERSION_NAME --model $MODEL_NAME \
  --origin gs://$BUCKET_NAME/custom_pipeline_tutorial/model/ \
  --runtime-version 1.13 \
  --python-version 3.5 \
  --framework SCIKIT_LEARN \
  --package-uris gs://$BUCKET_NAME/custom_pipeline_tutorial/code/census_package-1.0.tar.gz

Pubblicazione di previsioni online

Prova il deployment inviando una richiesta di previsione online. Innanzitutto, installa la libreria client delle API di Google per Python:

pip install --upgrade google-api-python-client

Quindi, invia due istanze di dati del censimento alla versione di cui è stato eseguito il deployment:

import googleapiclient.discovery

instances = [
  [39, 'State-gov', 77516, ' Bachelors .  ', 13, 'Never-married', 'Adm-clerical', 'Not-in-family',
   'White', 'Male', 2174, 0, 40, 'United-States', '<=50K'],
  [50, 'Self-emp-not-inc', 83311, 'Bachelors', 13, 'Married-civ-spouse', 'Exec-managerial', 'Husband',
   'White', 'Male', 0, 0, 13, 'United-States', '<=50K']
]

service = googleapiclient.discovery.build('ml', 'v1')
name = 'projects/{}/models/{}/versions/{}'.format(PROJECT_ID, MODEL_NAME, VERSION_NAME)

response = service.projects().predict(
    name=name,
    body={'instances': instances}
).execute()

if 'error' in response:
    raise RuntimeError(response['error'])
else:
  print(response['predictions'])

La versione passa i dati di input attraverso la pipeline addestrata e restituisce i risultati del classificatore: <=50K o >50K per ogni istanza, a seconda della previsione per la fascia di reddito della persona.

Pulizia

Per eliminare tutte le risorse Google Cloud utilizzate in questo progetto, puoi eliminare il progetto Google Cloud utilizzato per il tutorial.

In alternativa, puoi ripulire le singole risorse eseguendo i seguenti comandi:

# Delete version resource
gcloud ai-platform versions delete $VERSION_NAME --quiet --model $MODEL_NAME

# Delete model resource
gcloud ai-platform models delete $MODEL_NAME --quiet

# Delete Cloud Storage objects that were created
gcloud storage rm gs://$BUCKET_NAME/custom_pipeline_tutorial --recursive

Passaggi successivi