Vorhersage mit einer benutzerdefinierten scikit-learn-Pipeline

Colab-LogoDiese Anleitung als Notebook in Colab ausführen Logo: GitHubNotebook auf GitHub ansehen

In dieser Anleitung erfahren Sie, wie Sie mit AI Platform eine scikit-learn-Pipeline mit benutzerdefinierten Transformern bereitstellen.

Mithilfe von scikit-learn-Pipelines können Sie mehrere Estimators zusammensetzen. Sie können zum Beispiel Transformer verwenden, um Daten vorzuverarbeiten und die transformierten Daten an einen Klassifikator zu übergeben. scikit-learn stellt viele Transformer im Paket sklearn bereit.

Sie können auch die Klasse FunctionTransformer oder TransformerMixin von scikit-learn verwenden, um einen eigenen benutzerdefinierten Transformer zu erstellen. Wenn Sie eine Pipeline mit benutzerdefinierten Transformern in AI Platform Prediction bereitstellen möchten, müssen Sie diesen Code als Distributionspaket der Quellen in AI Platform Prediction bereitstellen.

In dieser Anleitung wird ein Beispielproblem mit Zensusdaten beschrieben, in dem Sie durch die folgenden Schritte geführt werden:

  • Training einer scikit-learn-Pipeline mit benutzerdefinierten Transformern in AI Platform-Training
  • Bereitstellung der trainierten Pipeline und des benutzerdefinierten Codes in AI Platform Prediction
  • Bearbeitung von Vorhersageanfragen in dieser Bereitstellung

Dataset

In dieser Anleitung wird das vom UC Irvine Machine Learning Repository bereitgestellte United States Census Income Dataset (US-Dataset zur Einkommenserhebung) verwendet. Das Dataset enthält Informationen zu Personen aus einer Zensusdatenbank von 1994, einschließlich Alter, Bildungsgrad, Familienstand, Beruf und ob sie mehr als 50.000 $ pro Jahr verdienen.

Die in dieser Anleitung verwendeten Daten sind in einem öffentlichen Cloud Storage-Bucket verfügbar: gs://cloud-samples-data/ai-platform/sklearn/census_data/

Ziel

Das Ziel besteht darin, eine scikit-learn-Pipeline zu trainieren, die auf der Grundlage anderer Zensusinformationen einer Person (Merkmale) vorhersagt, ob eine Person mehr als 50.000 $ pro Jahr verdient (Ziellabel).

Der Schwerpunkt dieser Anleitung liegt mehr auf der Verwendung des Modells mit AI Platform Prediction als auf dem eigentlichen Modelldesign. Sie sollten beim Erstellen eines Systems für maschinelles Lernen jedoch immer mögliche Probleme und unbeabsichtigte Folgen berücksichtigen. In der Übung zum Thema Fairness im Intensivkurs zum maschinellen Lernen erhalten Sie Informationen zu Verzerrungsquellen im Zensus-Dataset sowie zum allgemeinen Thema Fairness beim maschinellen Lernen.

Kosten

In dieser Anleitung werden kostenpflichtige Komponenten von Google Cloud verwendet.

  • AI Platform Training
  • AI Platform Prediction
  • Cloud Storage

Informieren Sie sich über die Preise für AI Platform Training, die Preise für AI Platform Prediction und die Cloud Storage-Preise und verwenden Sie den Preisrechner, um eine Kostenschätzung anhand Ihrer prognostizierten Nutzung zu erstellen.

Hinweise

Bevor Sie ein Modell in AI Platform Prediction trainieren und bereitstellen können, müssen Sie einige Schritte ausführen:

  • Lokale Entwicklungsumgebung einrichten
  • Google Cloud-Projekt einrichten, für das die Abrechnungsfunktion und die erforderlichen APIs aktiviert sind
  • Cloud Storage-Bucket zum Speichern des Trainingspakets und des trainierten Modells erstellen

Lokale Entwicklungsumgebung einrichten

Für diese Anleitung benötigen Sie Folgendes:

  • Python 3
  • virtualenv
  • Das Google Cloud SDK

Der Google Cloud-Leitfaden zum Einrichten einer Python-Entwicklungsumgebung enthält detaillierte Anweisungen zur Erfüllung dieser Anforderungen. Die folgenden Schritte sind eine Zusammenfassung dieser Anweisungen:

  1. Installieren Sie Python 3.

  2. Installieren Sie virtualenv und erstellen Sie eine virtuelle Umgebung, die Python 3 verwendet.

  3. Aktivieren Sie die Umgebung.

  4. Führen Sie die Schritte im folgenden Abschnitt aus, um das Google Cloud SDK zu installieren.

Google Cloud-Projekt einrichten

  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

GCP-Konto authentifizieren

Für die Einrichtung der Authentifizierung müssen Sie einen Dienstkontoschlüssel erstellen und eine Umgebungsvariable für den Dateipfad zum Dienstkontoschlüssel festlegen.

  1. Erstellen Sie ein Dienstkonto:

    1. Wechseln Sie in der Google Cloud Console zur Seite Dienstkonto erstellen.

      Zur Seite „Dienstkonto erstellen“

    2. Geben Sie im Feld Dienstkontoname einen Namen ein.
    3. Optional: Geben Sie im Feld Dienstkontobeschreibung eine Beschreibung ein.
    4. Klicken Sie auf Erstellen.
    5. Klicken Sie auf das Feld Rolle auswählen. Wählen Sie unter Alle Rollen die Option AI Platform > AI Platform-Administrator aus.
    6. Klicken Sie auf Weitere Rolle hinzufügen.
    7. Klicken Sie auf das Feld Rolle auswählen. Wählen Sie unter Alle Rollen die Option Storage > Storage-Objekt-Administrator.

    8. Klicken Sie auf Fertig, um das Dienstkonto zu erstellen.

      Schließen Sie das Browserfenster nicht. Sie verwenden es in der nächsten Aufgabe.

  2. Erstellen Sie einen Dienstkontoschlüssel für die Authentifizierung:

    1. Klicken Sie in der Google Cloud Console auf die E-Mail-Adresse des von Ihnen erstellten Dienstkontos.
    2. Klicken Sie auf Schlüssel.
    3. Klicken Sie auf Schlüssel hinzufügen > Neuen Schlüssel erstellen.
    4. Klicken Sie auf Erstellen. Daraufhin wird eine JSON-Schlüsseldatei auf Ihren Computer heruntergeladen.
    5. Klicken Sie auf Schließen.
  3. Legen Sie die Umgebungsvariable GOOGLE_APPLICATION_CREDENTIALS auf den Pfad der JSON-Datei fest, die Ihren Dienstkontoschlüssel enthält. Diese Variable gilt nur für Ihre aktuelle Shell-Sitzung. Wenn Sie eine neue Sitzung öffnen, müssen Sie die Variable noch einmal festlegen.

Cloud Storage-Bucket erstellen

In dieser Anleitung wird Cloud Storage auf verschiedene Arten verwendet:

  • Wenn Sie einen Trainingsjob mit dem Cloud SDK senden, laden Sie ein Python-Paket mit Ihrem Trainingscode in einen Cloud Storage-Bucket hoch. AI Platform Training führt den Code aus diesem Paket aus.

  • In dieser Anleitung speichert AI Platform Training das im Rahmen des Jobs trainierte Modell auch im selben Bucket.

  • Wenn Sie Ihre scikit-learn-Pipeline mit benutzerdefiniertem Code in AI Platform Prediction bereitstellen möchten, müssen Sie die von der Pipeline verwendeten benutzerdefinierten Transformer in Cloud Storage hochladen.

Wenn Sie eine AI Platform Prediction-Versionsressource erstellen, die Vorhersagen bereitstellt, stellen Sie die trainierte scikit-learn-Pipeline und den benutzerdefinierten Code als Cloud Storage-URIs bereit.

Legen Sie den Namen Ihres Cloud Storage-Buckets als Umgebungsvariable fest. Der Name muss in allen Cloud Storage-Buckets eindeutig sein:

BUCKET_NAME="your-bucket-name"

Wählen Sie eine Region aus, in der AI Platform Training und AI Platform Prediction verfügbar sind, und erstellen Sie eine weitere Umgebungsvariable. Beispiel:

REGION="us-central1"

Erstellen Sie in dieser Region einen Cloud Storage-Bucket und verwenden Sie später dieselbe Region für Training und Vorhersage. Führen Sie den folgenden Befehl aus, wenn noch kein Bucket vorhanden ist:

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

Trainingsanwendung und benutzerdefinierten Pipeline-Code erstellen

Erstellen Sie eine Anwendung zum Trainieren einer scikit-learn-Pipeline mit den Zensusdaten. In dieser Anleitung enthält das Trainingspaket auch den benutzerdefinierten Code, den die trainierte Pipeline während der Vorhersage verwendet. Das ist praktisch, weil Pipelines im Allgemeinen während des Trainings und der Vorhersage dieselben Transformer verwenden.

Führen Sie die folgenden Schritte aus, um ein Verzeichnis mit drei Dateien zu erstellen, das der folgenden Struktur entspricht:

census_package/
    __init__.py
    my_pipeline.py
    train.py

Erstellen Sie zuerst das leere Verzeichnis census_package/:

mkdir census_package

Erstellen Sie in census_package/ eine leere Datei mit dem Namen __init__.py:

touch ./census_package/__init__.py

Dies ermöglicht es Ihnen, census_package/ als Paket in Python zu importieren.

Benutzerdefinierte Transformer erstellen

scikit-learn stellt viele Transformer bereit, die Sie als Teil einer Pipeline verwenden können, aber Sie können auch Ihre eigenen benutzerdefinierten Transformer definieren. Diese Transformer können während des Trainings sogar einen gespeicherten Zustand erlernen, der später während der Vorhersage verwendet wird.

Erweitern Sie sklearn.base.TransformerMixin, um drei Transformer zu definieren:

  • PositionalSelector: Akzeptiert eine Indexliste C und eine Matrix M und gibt eine Matrix zurück, die die in C angegebenen Spalten von M enthält.

  • StripString: Akzeptiert eine Matrix mit Strings und entfernt die Leerzeichen aus ihnen.

  • SimpleOneHotEncoder: Ein einfacher One-Hot-Encoder, der auf eine Matrix mit Strings angewendet werden kann.

Schreiben Sie dazu den folgenden Code in eine Datei mit dem Namen 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

Pipeline definieren und Trainingsmodul erstellen

Als Nächstes erstellen Sie ein Trainingsmodul, um Ihre scikit-learn-Pipeline mit den Zensusdaten zu trainieren. Ein Teil dieses Codes definiert die Pipeline.

Dieses Trainingsmodul führt mehrere Vorgänge aus:

  • Die Trainingsdaten werden heruntergeladen und in einen Pandas-DataFrame geladen, der von scikit-learn verwendet werden kann.
  • Die zu trainierende scikit-learn-Pipeline wird definiert. In diesem Beispiel werden drei numerische Merkmale ('age', 'education-num', 'hours-per-week') und drei kategoriale Merkmale ('workclass', 'marital-status', 'relationship') der Eingabedaten verwendet. Die numerischen Merkmale werden mit dem integrierten StandardScaler von scikit-learn transformiert. Die kategorialen Merkmale werden mit dem benutzerdefinierten One-Hot-Encoder transformiert, den Sie in my_pipeline.py definiert haben. Dann werden die vorverarbeiteten Daten als Eingabe für einen Klassifikator kombiniert.
  • Schließlich wird das Modell mit der in scikit-learn enthaltenen Version von joblib exportiert und in Ihrem Cloud Storage-Bucket gespeichert.

Schreiben Sie den folgenden Code 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.')

Pipeline in AI Platform Training trainieren

Verwenden Sie gcloud, um einen Trainingsjob an AI Platform Training zu senden. Der folgende Befehl erstellt ein Paket aus Ihrer Trainingsanwendung, lädt sie in Cloud Storage hoch und weist AI Platform Training an, Ihr Trainingsmodul auszuführen.

Das Argument -- ist ein Trennzeichen: Der AI Platform Training-Dienst verwendet keine Argumente, die auf das Trennzeichen folgen. Das Trainingsmodul kann jedoch trotzdem darauf zugreifen.

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

Pipeline bereitstellen und Vorhersagen erstellen

Wenn Sie in AI Platform Prediction Vorhersagen erstellen möchten, müssen Sie eine Modellressource und eine Versionsressource bereitstellen. Das Modell unterstützt Sie beim Organisieren mehrerer Bereitstellungen, wenn Sie die Pipeline mehrmals ändern und trainieren. Die Version verwendet das trainierte Modell und den benutzerdefinierten Code für Vorhersagen.

Zur Bereitstellung dieser Ressourcen müssen Sie zwei Artefakte bereitstellen:

  • Ein Cloud Storage-Verzeichnis, das die trainierte Pipeline enthält. Diese Datei wurde durch den Trainingsjob im vorherigen Schritt erstellt, als model.joblib in Ihren Bucket exportiert wurde.
  • Ein .tar.gz-Quelldistributionspaket in Cloud Storage, das alle benutzerdefinierten Transformer enthält, die von der Pipeline verwendet werden. Dieses erstellen Sie im nächsten Schritt.

Paket der benutzerdefinierten Transformer erstellen

Wenn Sie eine Version ohne den Code aus my_pipeline.py erstellen, kann AI Platform Prediction die benutzerdefinierten Transformer (z. B. mp.SimpleOneHotEncoder) nicht importieren und keine Vorhersagen bereitstellen.

Erstellen Sie die folgende setup.py-Datei, um ein Quelldistributionspaket für Ihren Code zu definieren:

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

Führen Sie dann den folgenden Befehl aus, um dist/census_package-1.0.tar.gz zu erstellen:

python setup.py sdist --formats=gztar

Abschließend laden Sie dieses Tarball-Paket in Ihren Cloud Storage-Bucket hoch:

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

Modell- und Versionsressourcen erstellen

Zuerst definieren Sie die Namen für das Modell und die Version:

MODEL_NAME='CensusPredictor'
VERSION_NAME='v1'

Anschließend erstellen Sie die Modellressource mit dem folgenden Befehl:

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

Für das Erstellen der Versionsressource geben Sie Cloud Storage-Pfade zu Ihrem Modellverzeichnis (in dem sich model.joblib befindet) und Ihrem benutzerdefinierten Code (census_package-1.0.tar.gz) an:

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

Onlinevorhersagen bereitstellen

Testen Sie Ihre Bereitstellung mit einer Anfrage für eine Onlinevorhersage. Dafür installieren Sie zuerst die Google API-Clientbibliothek für Python:

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

Dann senden Sie zwei Instanzen von Zensusdaten an die bereitgestellte Version:

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

Die Version verarbeitet die Eingabedaten in der trainierten Pipeline und gibt die Ergebnisse des Klassifikators zurück, also für jede Instanz entweder <=50K oder >50K. Dies ist die Vorhersage der Einkommensklasse der Person.

Bereinigen

Wenn Sie alle für dieses Projekt verwendeten Google Cloud-Ressourcen bereinigen möchten, können Sie das Google Cloud-Projekt löschen, das Sie für diese Anleitung verwendet haben.

Alternativ können Sie mit den folgenden Befehlen einzelne Ressourcen bereinigen:

# 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

Nächste Schritte