Sdílet prostřednictvím


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

PLATÍ PRO: Python SDK azureml v1

V tomto kurzu se dozvíte, jak převést poznámkové bloky Jupyter na skripty Pythonu, aby bylo testování a automatizace přívětivé pomocí šablony kódu MLOpsPython a Azure Machine Learning. Tento proces se obvykle používá k experimentování / trénování kódu z poznámkového bloku Jupyter a jeho převodu na skripty Pythonu. Tyto skripty se pak dají použít k testování a automatizaci CI/CD v 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 je Jupyter Notebook, pomocí skutečných datových sad. Jakmile je model připravený pro produkční 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 popisuje doporučený přístup k exportu experimentovacího kódu do skriptů Pythonu.

V tomto kurzu se naučíte:

  • Vyčištění nestředného kódu
  • Refaktoring kódu Jupyter Notebook do funkcí
  • Vytváření skriptů Pythonu pro související úlohy
  • Vytvoření testů jednotek

Požadavky

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. Prvním krokem k převodu experimentálního kódu do produkčního kódu je proto odebrání tohoto žádného nepotřebného kódu. Odebráním žádného kódu také zajistíte, aby byl kód 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 volání features.describe buněk, jsou určené jen ke zkoumání dat a je možné je odebrat. Po odebrání žádného 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 na funkce

Za druhé, kód Jupyter musí být refaktorován na funkce. Refaktoring kódu do funkcí usnadňuje testování jednotek a usnadňuje správu kódu. V této části refaktorujete:

  • The Diabetes Ridge Regression Training notebook(experimentation/Diabetes Ridge Regression Training.ipynb)
  • Poznámkový blokexperimentation/Diabetes Ridge Regression Scoring.ipynb bodování diabetes Ridge

Refaktoring diabetes Ridge Regression Training notebook into functions

Proveďte experimentation/Diabetes Ridge Regression Training.ipynbnásledující kroky:

  1. Vytvořte funkci volanou 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 pod nadpis 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í natrénovaný model.

    Přesuňte kód pod nadpisem Training Model on Training Set 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 natrénovaný model.

    Přesuňte kód pod nadpisEm Validate Model on Validation Set do get_model_metrics funkce a upravte ho metrics tak, aby vrátil objekt.

Tyto 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.ipynb, 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 pod nadpisEm Načíst data do main funkce.

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

    # 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 pod nadpisem Uložit model do main funkce.

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 být žá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 s hodnocením Diabetes Ridge do funkcí

Proveďte experimentation/Diabetes Ridge Regression Scoring.ipynbná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 Load Model jedním voláním init následujícím způsobem:

init()

Proveďte experimentation/Diabetes Ridge Regression Scoring.ipynbnásledující kroky:

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

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

    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_headerskteré budou použity 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 a request_headerraw_data 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 se lépe pomohlo znovu použít kód. 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)
  • Poznámkový blokexperimentation/Diabetes Ridge Regression Scoring.ipynb bodování diabetes Ridge

Vytvoření souboru Pythonu pro poznámkový blok pro regresi Diabetes Ridge

Převeďte poznámkový blok na spustitelný skript spuštěním následujícího příkazu v 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

Po převodu poznámkového bloku na train.pytento poznámkový blok odeberte všechny nežádoucí komentáře. Volání na main() konci souboru nahraďte podmíněným vyvolá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 python train.pypříkazu . Funkce z train.py jiných souborů lze také volat.

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

Vytvoření souboru Pythonu pro poznámkový blok pro bodování 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.ipynb:

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

Po převodu poznámkového bloku na score.pytento poznámkový blok 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í údržbu. V této části vytvoříte testy jednotek pro funkce v train.py.

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í jedinou architekturou testování částí Pythonu, ale je to jedna z nejčastěji používaných architektur. Další informace najdete v Pytestu.

Test jednotek obvykle obsahuje tři hlavní akce:

  • Uspořádání objektu – vytváření a nastavení nezbytných objektů
  • Akce na objektu
  • Assert what is expected

Test jednotek bude volat train_model s některými pevně zakódovanými daty a argumenty a pomocí výsledného natrénovaného modelu ověřit, že train_model se bude chovat podle očekávání, aby se vytvořil predikce a porovnával 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 na následujících odkazech další informace a další kroky: