In diesem Artikel verwenden wir eine Bibliothek namens Kedro, um einen Workflow zur Vorhersage der Titanic-Überlebensrate zu erstellen.
In letzter Zeit sind viele Arten von Workflow-Management-Tools für maschinelles Lernen und Tools zur Unterstützung der Konstruktion erschienen. Auch wenn du es gehört hast
Und so weiter.
Vergleichen wir die Leistung dieser Tools anhand eines gemeinsamen Vorhersageprojekts! Das ist der Anfang dieses Artikels.
Versuchen Sie es also zuerst mit Kedro.
Deshalb habe ich mich für Kedro entschieden:
――Es war eine Weile auf Twitter beliebt, weil es einfach zu bedienen war.
kedro ist ein Workflow-Management-Tool für maschinelles Lernen für Python, das von McKinseys Datenanalyseunternehmen QuantumBlack entwickelt wurde.
Wie unten aufgeführt, ist es ein nützliches Werkzeug für die Verwaltung von Experimenten im PoC-Stadium, hat jedoch schwache Funktionen für die Produktion.
Reibungslose experimentelle Entwicklung von Modellen für maschinelles Lernen
--Erstellen von Verzeichnissen und Python-Codevorlagen
Im Folgenden möchte ich Ihnen die Verwendung von Kedro am Beispiel der in der Datenanalyse bekannten Titanic vorstellen.
Grundsätzlich wird es unter Bezugnahme auf Official Tutorial erstellt. Der Code wurde auf GitHub hochgeladen.
kedro new
kedro run
Wenn Sie "kedro new" über die Befehlszeile ausführen, werden Sie aufgefordert, den Projektnamen, den Repository-Namen und den Paketnamen wie unten gezeigt einzugeben.
$ kedro new
Project Name:
=============
Please enter a human readable name for your new project.
Spaces and punctuation are allowed.
[New Kedro Project]: Titanic with Kedro
Repository Name:
================
Please enter a directory name for your new project repository.
Alphanumeric characters, hyphens and underscores are allowed.
Lowercase is recommended.
[titanic-with-kedro]: titanic-with-kedro
Python Package Name:
====================
Please enter a valid Python package name for your project package.
Alphanumeric characters and underscores are allowed.
Lowercase is recommended. Package name must start with a letter or underscore.
[titanic_with_kedro]: titanic_with_kedro
Generate Example Pipeline:
==========================
Do you want to generate an example pipeline in your project?
Good for first-time users. (default=N)
[y/N]: N
Es wird ein Projektverzeichnis mit dem Namen erstellt, den Sie unter "Repository-Name" eingegeben haben. Wenn man nach innen schaut, sieht es wie folgt aus.
titanic-with-kedro
├── README.md
├── conf
│ ├── README.md
│ ├── base
│ │ ├── catalog.yml
│ │ ├── credentials.yml
│ │ ├── logging.yml
│ │ └── parameters.yml
│ └── local
├── data
│ ├── 01_raw
│ ├── 02_intermediate
│ ├── 03_primary
│ ├── 04_features
│ ├── 05_model_input
│ ├── 06_models
│ ├── 07_model_output
│ └── 08_reporting
├── docs
│ └── source
│ ├── conf.py
│ └── index.rst
├── errors.log
├── info.log
├── kedro_cli.py
├── logs
├── notebooks
├── references
├── results
├── setup.cfg
└── src
├── requirements.txt
├── setup.py
├── tests
│ ├── __init__.py
│ └── test_run.py
└── titanic_with_kedro
├── __init__.py
├── nodes
│ └── __init__.py
├── pipeline.py
├── pipelines
│ └── __init__.py
└── run.py
Der "Python-Paketname", der unterwegs abgefragt wird, wird als Name des Verzeichnisses verwendet, in dem der generierte Pipeline-Code unter "src" abgelegt wird (diesmal "titanic_with_kedro").
Schließlich werden Sie gefragt, ob Sie eine Beispielpipeline in Ihrem Projekt generieren möchten. Wenn Sie hier jedoch auf y drücken, wird der Code für das Lernprogramm als Satz generiert. Da dies ab dem zweiten Mal nicht mehr erforderlich ist, drücken Sie die Eingabetaste, ohne N einzugeben.
Dieses Mal werde ich die Daten von kaggle mithilfe der API abrufen und in data / 01_raw /
einfügen.
Die Registrierung zum Kaggle und der Erwerb des Authentifizierungstokens sind separat erforderlich.
$ cd data/01_raw/
$ kaggle competitions download -c titanic
$ unzip titanic.zip
Bearbeiten Sie außerdem den Datenkatalog wie folgt.
conf/base/catalog.yml
train:
type: CSVLocalDataSet
filepath: data/01_raw/train.csv
test:
type: CSVLocalDataSet
filepath: data/01_raw/test.csv
Die Datennamen "Zug" und "Test" werden auch beim Lesen von Daten verwendet.
Mit type:
können Sie das von kedro vorbereitete Datenleseformat auswählen. [^ 2]
[^ 2]: Sie können auch eine benutzerdefinierte Funktion zum Laden von Daten anwenden.
Versuchen wir zu sehen, ob die Daten gelesen werden können.
Führen Sie den folgenden kedro-Befehl aus, um das Jupyter-Notebook (oder IPython) zu starten. Das Notizbuch startet mit dem "Katalog" zum Lesen der im Voraus importierten Daten [^ 3].
$ kedro jupyter notebook
df_train = catalog.load("train")
df_train.head()
[^ 3]: Standardmäßig kann die Ausführung aufgrund eines Modulladefehlers möglicherweise nicht durchgeführt werden. Öffnen Sie in diesem Fall "src /
Beschreiben Sie die Datenvorverarbeitungspipeline gemäß dem Kedro-Format.
src/titanic_with_kedro/pipelines/data_engineering/pipeline.py
from kedro.pipeline import node, Pipeline
from titanic_with_kedro.nodes import preprocess
def create_pipeline(**kwargs):
return Pipeline(
[
node(
func=preprocess.preprocess,
inputs="train",
outputs="train_prep",
name="preprocess",
),
],
tags=['de_tag'],
)
Die Verarbeitungseinheit "Knoten" wird in der von "kedro" bereitgestellten Klasse "Pipeline" gespeichert.
Für die Funktion "Knoten"
--func: Funktion, die den Prozess beschreibt --inputs: Name der Eingabedaten --outputs: Name der Ausgabedaten --name: Knotenname
Angegeben.
Die vom Knoten durchgeführte Verarbeitung wird angegeben, indem ein Funktionsobjekt an das Argument "func" übergeben wird.
In diesem Beispiel wird die Funktion "preprocess ()" als ein Knoten verwendet, um fehlende Werte zu vervollständigen und die Etikettencodierung durchzuführen.
Zu diesem Zeitpunkt werden die durch das Argument "Eingaben" angegebenen Daten für die Eingabe der Funktion "preprocess ()" verwendet. Im obigen Beispiel wird "Zug" angegeben, dies zeigt jedoch auf die im obigen Datenkatalog "conf / base / catalog.yml" definierten "Zug" -Daten und das im Katalog beschriebene Datenformat. Basierend auf dem Pfad und dem Pfad wird die Datei gelesen und eingegeben.
Das Ausgabeobjekt erhält dann die durch "Ausgaben" angegebene Bezeichnung. Wenn Sie dieses Objekt in der nachfolgenden Verarbeitung verwenden, können Sie es mit dieser Bezeichnung angeben und aufrufen.
Die diesmal im Knoten angegebene Vorverarbeitungsfunktion lautet wie folgt. Im Gegensatz zur Pipeline muss keine spezielle Beschreibungsmethode verwendet werden.
(Die Funktion _label_encoding ()
ist eine Hilfsfunktion)
src/titanic_with_kedro/nodes/preprocess.py
import pandas as pd
from sklearn import preprocessing
def _label_encoding(df: pd.DataFrame) -> (pd.DataFrame, dict):
df_le = df.copy()
# Getting Dummies from all categorical vars
list_columns_object = df_le.columns[df_le.dtypes == 'object']
dict_encoders = {}
for column in list_columns_object:
le = preprocessing.LabelEncoder()
mask_nan = df_le[column].isnull()
df_le[column] = le.fit_transform(df_le[column].fillna('NaN'))
df_le.loc[mask_nan, column] *= -1 # transform minus for missing records
dict_encoders[column] = le
return df_le, dict_encoders
def preprocess(df: pd.DataFrame) -> pd.DataFrame:
df_prep = df.copy()
drop_cols = ['Name', 'Ticket', 'PassengerId']
df_prep = df_prep.drop(drop_cols, axis=1)
df_prep['Age'] = df_prep['Age'].fillna(df_prep['Age'].mean())
# Filling missing Embarked values with most common value
df_prep['Embarked'] = df_prep['Embarked'].fillna(df_prep['Embarked'].mode()[0])
df_prep['Pclass'] = df_prep['Pclass'].astype(str)
# Take the frist alphabet from Cabin
df_prep['Cabin'] = df_prep['Cabin'].str[0]
# Label Encoding for str columns
df_prep, _ = _label_encoding(df_prep)
return df_prep
Sie können auch mehrere erstellte Pipelines kombinieren.
Dieses Mal habe ich das Modell definiert, das in einer anderen Pipeline erstellt wurdesrc / titanic_with_kedro / pipelines / data_science / Pipeline.py
.
Gehen Sie wie folgt vor, um dies mit der vorherigen Vorverarbeitung zu kombinieren:
src/titanic_with_kedro/pipeline.py
from typing import Dict
from kedro.pipeline import Pipeline
from titanic_with_kedro.pipelines.data_engineering import pipeline as de
from titanic_with_kedro.pipelines.data_science import pipeline as ds
def create_pipelines(**kwargs) -> Dict[str, Pipeline]:
"""Create the project's pipeline.
Args:
kwargs: Ignore any additional arguments added in the future.
Returns:
A mapping from a pipeline name to a ``Pipeline`` object.
"""
de_pipeline = de.create_pipeline()
ds_pipeline = ds.create_pipeline()
return {
"de": de_pipeline,
"ds": ds_pipeline,
"__default__": de_pipeline + ds_pipeline,
}
Die Modellbildungspipeline ist wie folgt definiert.
src/titanic_with_kedro/pipelines/data_science/pipeline.py
from kedro.pipeline import node, Pipeline
from titanic_with_kedro.nodes import modeling
def create_pipeline(**kwargs):
return Pipeline(
[
node(
func=modeling.split_data,
inputs=["train_prep", "parameters"],
outputs=["X_train", "X_test", "y_train", "y_test"],
),
node(func=modeling.train_model,
inputs=["X_train", "y_train"],
outputs="clf"),
node(
func=modeling.evaluate_model,
inputs=["clf", "X_test", "y_test"],
outputs=None,
),
],
tags=["ds_tag"],
)
Auf diese Weise können Sie mehrere Knoten in einer Pipeline platzieren.
Geben Sie nach dem Definieren der Pipeline einen Ausführungsbefehl aus dem Stammverzeichnis des Projekts aus.
$ kedro run
Auf diese Weise wird "src /
Wenn Sie zu diesem Zeitpunkt die Zwischendaten nach der Vorverarbeitung und das erstellte Modell (diesmal zufällige Gesamtstruktur) speichern möchten, fügen Sie dem Datenkatalog Folgendes hinzu.
conf/base/catalog.yml
train_prep:
type: CSVLocalDataSet
filepath: data/02_intermediate/train_prep.csv
clf:
type: PickleLocalDataSet
filepath: data/06_models/classifier.pickle
versioned: true
"train_prep" und "clf" beziehen sich auf die vorverarbeiteten Daten bzw. das trainierte Modell. Bei der Definition der Pipeline wird der im Argument "output" der Funktion "node" angegebene Name jedoch so wie er ist erkannt und auf den angegebenen Formatpfad gesetzt. Es wird es speichern.
Wenn Sie "versioned" auf "true" setzen, wird es bei jeder Ausführung in einem anderen Verzeichnis gespeichert [^ 4].
[^ 4]: In diesem Fall wird zum Zeitpunkt der Ausführung unter data / 06_models / classifier.pickle /
und data / 06_models / classifier.pickle / 2020-02-22T06.26.54.486Z eine neue Zeit erstellt Es wird als / classifier.pickle
gespeichert.
Die Grundfunktionen sind wie oben, es gibt jedoch auch die folgenden Funktionen.
Ich denke, dass es beim Erstellen eines Ausführungscodes viele Leute gibt, die ihn schreiben, während sie ihn einzeln mit Jupyter-Notizbuch ausführen, ohne ihn von Anfang an in eine .py-Datei zu schreiben.
In diesem Fall ist es schwierig, den Code später in .py umzuschreiben. Wenn Sie jedoch die CLI von kedro verwenden, wird nur der angegebene Teil des Codes in .py ausgespuckt.
Starten Sie dazu zuerst Jupyter von Kedros Cli aus.
$ kedro jupyter notebook
Fügen Sie als Nächstes das node
-Tag nur zu den Zellen hinzu, die Sie in .py schreiben möchten.
Wählen Sie zum Markieren im Menü oben auf dem Bildschirm "Ansicht> Zellen-Symbolleiste> Tags" aus. Oben in jeder Zelle wird ein Tag-Eingabefenster angezeigt. Geben Sie daher "node" ein, um es hinzuzufügen.
Wenn Sie dann Folgendes über die Befehlszeile ausführen, wird nur der markierte Teil extrahiert und "src /
kedro jupyter convert notebooks/<notebook name>.ipynb
Referenz
https://kedro.readthedocs.io/en/latest/04_user_guide/11_ipython.html
Sie können auch die in der externen Datei angegebenen Parameter lesen, wenn Sie die Pipeline definieren.
Wenn Sie die obigen Modellbildungsparameter noch einmal betrachten, gibt es eine Stelle, an der "Parameter" in den Eingaben angegeben sind.
src/titanic_with_kedro/pipelines/data_science/pipeline.py
#Kürzung
def create_pipeline(**kwargs):
return Pipeline(
[
node(
func=modeling.split_data,
inputs=["train_prep", "parameters"],
outputs=["X_train", "X_test", "y_train", "y_test"],
#Kürzung
Das Obige ist der Teil, der in Trainingsdaten und Testdaten unterteilt werden soll.
"parameters" bezieht sich auf die Datei "parameters.yml" im Verzeichnis "conf / base".
conf/base/parameters.yml
test_size: 0.2
random_state: 17
Auf diese Weise können Sie es automatisch als Objekt vom Typ Wörterbuch an das Argument der Knotenfunktion übergeben und wie unten gezeigt darauf verweisen.
#Kürzung
def split_data(data: pd.DataFrame, parameters: Dict) -> List:
"""Splits data into training and test sets.
Args:
data: Source data.
parameters: Parameters defined in parameters.yml.
Returns:
A list containing split data.
"""
target_col = 'Survived'
X = data.drop(target_col, axis=1).values
y = data[target_col].values
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=parameters["test_size"], random_state=parameters["random_state"]
)
return [X_train, X_test, y_train, y_test]
#Kürzung
Wie oben erwähnt, machte ich nach der Einführung in die Verwendung von Kedro eine Titanic-Vorhersage.
Der obige Prognosefluss ist fehlerhaft.
Wenn Sie an Datenanalyse gewöhnt sind, haben Sie dies möglicherweise bemerkt.
Das kann erwähnt werden.
Insbesondere bei ersteren besteht die Gefahr von Leckagen, da die Testdateninformationen mit den Trainingsdaten gemischt werden, wenn fehlende Werte und die Etikettencodierung vervollständigt werden.
Beide Probleme können gelöst werden, indem der Vorverarbeitungsteil in eine Klasse geschrieben und die Instanz mit pickle konsolidiert wird, damit sie später gelesen und verwendet werden kann.
Die Lösung ist nicht so schwierig, und es wird erwartet, dass sie realisiert werden kann, indem der Ausgabe des Knotens ein Vorverarbeitungsobjekt hinzugefügt, catalog.yml bearbeitet und zur Laufzeit gespeichert wird.
Es gibt jedoch ein Versionsverwaltungsproblem.
Wenn sowohl der Vorverarbeitungsteil als auch das Modell mit der Versionsverwaltung gespeichert werden, wie sollten die Vorverarbeitungsobjekte der Version, die jedem Modell entsprechen, verknüpft werden?
Angenommen, Sie möchten den Vorverarbeitungsteil neu schreiben, um ein Modell zu erstellen und später Rückschlüsse auf das alte Modell zu ziehen. Wenn der neue Vorverarbeitungscode zu diesem Zeitpunkt nicht mit dem alten Modell kompatibel ist, muss das Vorverarbeitungsobjekt zu diesem Zeitpunkt auch durch das Objekt ersetzt werden, das beim Erstellen des alten Modells verwendet wurde.
Um dies mühelos zu tun, ist eine Tagging- oder Ausführungs-ID-Zuweisung erforderlich, aber es ist nicht bestätigt, ob Kedro dies kann. [^ 5]
[^ 5]: In MLflow und Metaflow können das Modell und die Zwischenobjekte durch Angabe der Ausführungs-ID gelesen werden. Wenn gut mit diesen kombiniert, kann es möglich sein ...
Darüber hinaus gab es einige Punkte, bei denen ich dachte "Ich wünschte, ich hätte diese Funktion ...", als ich Kedro berührte.
es gibt.
Ersteres kann manipuliert werden.
Letzteres liegt wahrscheinlich außerhalb des Anwendungsbereichs von Kedro, daher müssen wir es anscheinend in Kombination mit anderen Tools verwenden. Insbesondere MLflow von Databricks scheint genau richtig zu sein. In einem Artikel des Kedro-Entwicklers Quantum Black wird auch die Kombination mit MLflow erörtert. Es gibt auch eine Bibliothek namens PipelineX, die beide kombiniert.
Recommended Posts