Převod experimentů ML na produkční kód Pythonu

PLATÍ PRO:Sada Python SDK azureml v1

V tomto kurzu se naučíte, jak převést poznámkové bloky Jupyter na skripty Pythonu, aby byly přívětivé k testování a automatizaci pomocí šablony kódu MLOpsPython a služby Azure Machine Learning. Tento proces se obvykle používá k získání experimentování nebo trénování kódu z poznámkového bloku Jupyter a jeho převodu na skripty Pythonu. Tyto skripty pak můžete použít k testování a automatizaci CI/CD ve vašem produkčním prostředí.

Projekt strojového učení vyžaduje experimentování, kdy se hypotézy testují pomocí agilních nástrojů, jako jsou Jupyter Notebook pomocí skutečných datových sad. Jakmile je model připravený do produkčního prostředí, měl by se kód modelu umístit do úložiště produkčního kódu. V některých případech musí být kód modelu převeden na skripty Pythonu, které se umístí do úložiště produkčního kódu. Tento kurz se zabývá doporučeným přístupem k exportu experimentálního kódu do skriptů Pythonu.

V tomto kurzu se naučíte:

  • Vyčištění nepotřebného kódu
  • Refaktoring Jupyter Notebook kódu do funkcí
  • Vytváření skriptů Pythonu pro související úlohy
  • Create unit tests (Vytvořit testy jednotek)

Požadavky

  • Vygenerujte šablonu MLOpsPython a použijte experimentation/Diabetes Ridge Regression Training.ipynb poznámkové bloky a experimentation/Diabetes Ridge Regression Scoring.ipynb . Tyto poznámkové bloky slouží jako příklad převodu z experimentování do produkčního prostředí. Tyto poznámkové bloky najdete na adrese https://github.com/microsoft/MLOpsPython/tree/master/experimentation.
  • Nainstalujte nbconvert. Postupujte pouze podle pokynů k instalaci v části Instalace nástroje nbconvert na stránce Instalace .

Odebrání veškerého nepotřebného kódu

Kód napsaný během experimentování je určen pouze pro průzkumné účely. Proto prvním krokem k převodu experimentálního kódu na produkční kód je odebrání tohoto nepotřebného kódu. Odebráním nepotřebného kódu bude kód také lépe udržovatelný. V této části odeberete kód z poznámkového experimentation/Diabetes Ridge Regression Training.ipynb bloku. Příkazy, které tisknou tvar X a y a volání features.describe buňky, jsou jen pro zkoumání dat a je možné je odebrat. Po odebrání nepotřebného kódu experimentation/Diabetes Ridge Regression Training.ipynb by měl vypadat jako následující kód bez markdownu:

from sklearn.datasets import load_diabetes
from sklearn.linear_model import Ridge
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
import joblib
import pandas as pd

sample_data = load_diabetes()

df = pd.DataFrame(
    data=sample_data.data,
    columns=sample_data.feature_names)
df['Y'] = sample_data.target

X = df.drop('Y', axis=1).values
y = df['Y'].values

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=0)
data = {"train": {"X": X_train, "y": y_train},
        "test": {"X": X_test, "y": y_test}}

args = {
    "alpha": 0.5
}

reg_model = Ridge(**args)
reg_model.fit(data["train"]["X"], data["train"]["y"])

preds = reg_model.predict(data["test"]["X"])
mse = mean_squared_error(preds, y_test)
metrics = {"mse": mse}
print(metrics)

model_name = "sklearn_regression_model.pkl"
joblib.dump(value=reg, filename=model_name)

Refaktoring kódu do funkcí

Za druhé je potřeba refaktorovat kód Jupyter do funkcí. Refaktoring kódu do funkcí usnadňuje testování jednotek a usnadňuje údržbu kódu. V této části refaktorujete:

  • The Diabetes Ridge Regression Training Notebook(experimentation/Diabetes Ridge Regression Training.ipynb)
  • The Diabetes Ridge Regression Scoring Notebook(experimentation/Diabetes Ridge Regression Scoring.ipynb)

Refaktoring poznámkového bloku Diabetes Ridge Regression Training do funkcí

V experimentation/Diabetes Ridge Regression Training.ipynbnástroji proveďte následující kroky:

  1. Vytvořte funkci s názvem split_data pro rozdělení datového rámce na testovací a trénovací data. Funkce by měla datový rámec df převzít jako parametr a vrátit slovník obsahující klíče train a test.

    Přesuňte kód do nadpisu Rozdělit data do trénovacích a ověřovacích sad do split_data funkce a upravte ho data tak, aby vrátil objekt.

  2. Vytvořte funkci s názvem train_model, která přebírá parametry data a args vrací trénovaný model.

    Přesuňte kód pod nadpisEm trénovací model v trénovací sadě do train_model funkce a upravte ho reg_model tak, aby vrátil objekt. args Odeberte slovník, hodnoty budou pocházet z parametruargs.

  3. Vytvořte funkci s názvem get_model_metrics, která přebírá parametry reg_model a dataa vyhodnocuje model a pak vrátí slovník metrik pro trénovaný model.

    Přesuňte kód do funkce pod nadpisem Validate Model on Validation Set (Ověřit model vget_model_metrics ověřovací sadě) a upravte ho metrics tak, aby vrátil objekt.

Tři funkce by měly být následující:

# Split the dataframe into test and train data
def split_data(df):
    X = df.drop('Y', axis=1).values
    y = df['Y'].values

    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=0)
    data = {"train": {"X": X_train, "y": y_train},
            "test": {"X": X_test, "y": y_test}}
    return data


# Train the model, return the model
def train_model(data, args):
    reg_model = Ridge(**args)
    reg_model.fit(data["train"]["X"], data["train"]["y"])
    return reg_model


# Evaluate the metrics for the model
def get_model_metrics(reg_model, data):
    preds = reg_model.predict(data["test"]["X"])
    mse = mean_squared_error(preds, data["test"]["y"])
    metrics = {"mse": mse}
    return metrics

Stále v experimentation/Diabetes Ridge Regression Training.ipynbnástroji proveďte následující kroky:

  1. Vytvořte novou funkci s názvem main, která nepřijímá žádné parametry a nevrací nic.

  2. Přesuňte kód do main funkce pod nadpisem Načíst data.

  3. Přidejte do main funkce vyvolání nově zapsaných funkcí:

    # Split Data into Training and Validation Sets
    data = split_data(df)
    
    # Train Model on Training Set
    args = {
        "alpha": 0.5
    }
    reg = train_model(data, args)
    
    # Validate Model on Validation Set
    metrics = get_model_metrics(reg, data)
    
  4. Přesuňte kód do funkce pod nadpisem main Uložit model.

Funkce main by měla vypadat jako následující kód:

def main():
    # Load Data
    sample_data = load_diabetes()

    df = pd.DataFrame(
        data=sample_data.data,
        columns=sample_data.feature_names)
    df['Y'] = sample_data.target

    # Split Data into Training and Validation Sets
    data = split_data(df)

    # Train Model on Training Set
    args = {
        "alpha": 0.5
    }
    reg = train_model(data, args)

    # Validate Model on Validation Set
    metrics = get_model_metrics(reg, data)

    # Save Model
    model_name = "sklearn_regression_model.pkl"

    joblib.dump(value=reg, filename=model_name)

V této fázi by v poznámkovém bloku neměl zůstat žádný kód, který není ve funkci, kromě příkazů importu v první buňce.

Přidejte příkaz, který volá main funkci.

main()

Po refaktoringu experimentation/Diabetes Ridge Regression Training.ipynb by měl vypadat jako následující kód bez markdownu:

from sklearn.datasets import load_diabetes
from sklearn.linear_model import Ridge
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
import pandas as pd
import joblib


# Split the dataframe into test and train data
def split_data(df):
    X = df.drop('Y', axis=1).values
    y = df['Y'].values

    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=0)
    data = {"train": {"X": X_train, "y": y_train},
            "test": {"X": X_test, "y": y_test}}
    return data


# Train the model, return the model
def train_model(data, args):
    reg_model = Ridge(**args)
    reg_model.fit(data["train"]["X"], data["train"]["y"])
    return reg_model


# Evaluate the metrics for the model
def get_model_metrics(reg_model, data):
    preds = reg_model.predict(data["test"]["X"])
    mse = mean_squared_error(preds, data["test"]["y"])
    metrics = {"mse": mse}
    return metrics


def main():
    # Load Data
    sample_data = load_diabetes()

    df = pd.DataFrame(
        data=sample_data.data,
        columns=sample_data.feature_names)
    df['Y'] = sample_data.target

    # Split Data into Training and Validation Sets
    data = split_data(df)

    # Train Model on Training Set
    args = {
        "alpha": 0.5
    }
    reg = train_model(data, args)

    # Validate Model on Validation Set
    metrics = get_model_metrics(reg, data)

    # Save Model
    model_name = "sklearn_regression_model.pkl"

    joblib.dump(value=reg, filename=model_name)

main()

Refaktoring poznámkového bloku Diabetes Ridge Regression Scoring do funkcí

V experimentation/Diabetes Ridge Regression Scoring.ipynbnástroji proveďte následující kroky:

  1. Vytvořte novou funkci s názvem init, která nepřijímá žádné parametry a nevrací nic.
  2. Zkopírujte kód pod nadpisem Načíst model do init funkce.

Funkce init by měla vypadat jako následující kód:

def init():
    model_path = Model.get_model_path(
        model_name="sklearn_regression_model.pkl")
    model = joblib.load(model_path)

init Po vytvoření funkce nahraďte veškerý kód pod nadpisem Načíst model jedním voláním init následujícím způsobem:

init()

V experimentation/Diabetes Ridge Regression Scoring.ipynbnástroji proveďte následující kroky:

  1. Vytvořte novou funkci s názvem run, která přebírá raw_data parametry a request_headers a vrátí slovník výsledků následujícím způsobem:

    {"result": result.tolist()}
    
  2. Zkopírujte kód do run funkce pod nadpisy Připravit data a Skóre dat.

    Funkce run by měla vypadat jako následující kód (Nezapomeňte odebrat příkazy, které nastavují proměnné raw_data a request_headers, které se použijí později při run zavolání funkce):

    def run(raw_data, request_headers):
        data = json.loads(raw_data)["data"]
        data = numpy.array(data)
        result = model.predict(data)
    
        return {"result": result.tolist()}
    

run Po vytvoření funkce nahraďte veškerý kód v nadpisech "Připravit data" a "Skóre dat" následujícím kódem:

raw_data = '{"data":[[1,2,3,4,5,6,7,8,9,10],[10,9,8,7,6,5,4,3,2,1]]}'
request_header = {}
prediction = run(raw_data, request_header)
print("Test result: ", prediction)

Předchozí kód nastaví proměnné raw_data a request_headerzavolá run funkci pomocí raw_data a request_headera vytiskne předpovědi.

Po refaktoringu experimentation/Diabetes Ridge Regression Scoring.ipynb by měl vypadat jako následující kód bez markdownu:

import json
import numpy
from azureml.core.model import Model
import joblib

def init():
    model_path = Model.get_model_path(
        model_name="sklearn_regression_model.pkl")
    model = joblib.load(model_path)

def run(raw_data, request_headers):
    data = json.loads(raw_data)["data"]
    data = numpy.array(data)
    result = model.predict(data)

    return {"result": result.tolist()}

init()
test_row = '{"data":[[1,2,3,4,5,6,7,8,9,10],[10,9,8,7,6,5,4,3,2,1]]}'
request_header = {}
prediction = run(test_row, {})
print("Test result: ", prediction)

Za třetí, související funkce je potřeba sloučit do souborů Pythonu, aby bylo možné lépe používat kód znovu. V této části budete vytvářet soubory Pythonu pro následující poznámkové bloky:

  • The Diabetes Ridge Regression Training Notebook(experimentation/Diabetes Ridge Regression Training.ipynb)
  • The Diabetes Ridge Regression Scoring Notebook(experimentation/Diabetes Ridge Regression Scoring.ipynb)

Vytvoření souboru Pythonu pro poznámkový blok trénování regrese Diabetes Ridge

Převeďte poznámkový blok na spustitelný skript spuštěním následujícího příkazu na příkazovém řádku, který používá nbconvert balíček a cestu :experimentation/Diabetes Ridge Regression Training.ipynb

jupyter nbconvert "Diabetes Ridge Regression Training.ipynb" --to script --output train

Jakmile se poznámkový blok převede na train.py, odeberte všechny nežádoucí komentáře. Nahraďte volání na main() konci souboru podmíněným voláním, jako je následující kód:

if __name__ == '__main__':
    main()

Soubor train.py by měl vypadat jako následující kód:

from sklearn.datasets import load_diabetes
from sklearn.linear_model import Ridge
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
import pandas as pd
import joblib


# Split the dataframe into test and train data
def split_data(df):
    X = df.drop('Y', axis=1).values
    y = df['Y'].values

    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=0.2, random_state=0)
    data = {"train": {"X": X_train, "y": y_train},
            "test": {"X": X_test, "y": y_test}}
    return data


# Train the model, return the model
def train_model(data, args):
    reg_model = Ridge(**args)
    reg_model.fit(data["train"]["X"], data["train"]["y"])
    return reg_model


# Evaluate the metrics for the model
def get_model_metrics(reg_model, data):
    preds = reg_model.predict(data["test"]["X"])
    mse = mean_squared_error(preds, data["test"]["y"])
    metrics = {"mse": mse}
    return metrics


def main():
    # Load Data
    sample_data = load_diabetes()

    df = pd.DataFrame(
        data=sample_data.data,
        columns=sample_data.feature_names)
    df['Y'] = sample_data.target

    # Split Data into Training and Validation Sets
    data = split_data(df)

    # Train Model on Training Set
    args = {
        "alpha": 0.5
    }
    reg = train_model(data, args)

    # Validate Model on Validation Set
    metrics = get_model_metrics(reg, data)

    # Save Model
    model_name = "sklearn_regression_model.pkl"

    joblib.dump(value=reg, filename=model_name)

if __name__ == '__main__':
    main()

train.py nyní lze vyvolat z terminálu spuštěním příkazu python train.py. Funkce z train.py lze také volat z jiných souborů.

Soubor train_aml.py v adresáři diabetes_regression/training v úložišti MLOpsPython volá funkce definované v train.py kontextu úlohy experimentu Azure Machine Learning. Funkce lze také volat v testech jednotek, probírané dále v této příručce.

Vytvoření souboru Pythonu pro poznámkový blok s hodnocením regrese Diabetes Ridge

Převeďte poznámkový blok na spustitelný skript spuštěním následujícího příkazu na příkazovém řádku, který používá nbconvert balíček a cestu experimentation/Diabetes Ridge Regression Scoring.ipynbk :

jupyter nbconvert "Diabetes Ridge Regression Scoring.ipynb" --to script --output score

Jakmile se poznámkový blok převede na score.py, odeberte všechny nežádoucí komentáře. Soubor score.py by měl vypadat jako následující kód:

import json
import numpy
from azureml.core.model import Model
import joblib

def init():
    model_path = Model.get_model_path(
        model_name="sklearn_regression_model.pkl")
    model = joblib.load(model_path)

def run(raw_data, request_headers):
    data = json.loads(raw_data)["data"]
    data = numpy.array(data)
    result = model.predict(data)

    return {"result": result.tolist()}

init()
test_row = '{"data":[[1,2,3,4,5,6,7,8,9,10],[10,9,8,7,6,5,4,3,2,1]]}'
request_header = {}
prediction = run(test_row, request_header)
print("Test result: ", prediction)

Proměnná model musí být globální, aby byla viditelná v celém skriptu. Na začátek init funkce přidejte následující příkaz:

global model

Po přidání předchozího příkazu init by funkce měla vypadat jako následující kód:

def init():
    global model

    # load the model from file into a global object
    model_path = Model.get_model_path(
        model_name="sklearn_regression_model.pkl")
    model = joblib.load(model_path)

Vytvoření testů jednotek pro každý soubor Pythonu

Za čtvrté vytvořte testy jednotek pro funkce Pythonu. Testy jednotek chrání kód před funkčními regresemi a usnadňují jeho údržbu. V této části vytvoříte testy jednotek pro funkce v train.pynástroji .

train.py obsahuje více funkcí, ale v tomto kurzu vytvoříme pouze jeden test jednotek pro train_model funkci pomocí architektury Pytest. Pytest není jediná architektura pro testování jednotek v Pythonu, ale je to jedna z nejčastěji používaných architektur. Další informace najdete na stránce Pytest.

Test jednotek obvykle obsahuje tři hlavní akce:

  • Uspořádat objekt – vytváření a nastavení potřebných objektů
  • Akce s objektem
  • Potvrdit, co se očekává

Test jednotek zavolá train_model s některými pevně zakódovanými daty a argumenty a ověří, že train_model se chovaly podle očekávání, a to pomocí výsledného natrénovaného modelu, který vytvoří předpověď a porovná ji s očekávanou hodnotou.

import numpy as np
from code.training.train import train_model


def test_train_model():
    # Arrange
    X_train = np.array([1, 2, 3, 4, 5, 6]).reshape(-1, 1)
    y_train = np.array([10, 9, 8, 8, 6, 5])
    data = {"train": {"X": X_train, "y": y_train}}

    # Act
    reg_model = train_model(data, {"alpha": 1.2})

    # Assert
    preds = reg_model.predict([[1], [2]])
    np.testing.assert_almost_equal(preds, [9.93939393939394, 9.03030303030303])

Další kroky

Teď, když rozumíte tomu, jak převést z experimentu na produkční kód, najdete další informace a další kroky na následujících odkazech: