Dela via


Konvertera ML-experiment till Python-produktionskod

GÄLLER FÖR: Python SDK azureml v1

I den här självstudien får du lära dig hur du konverterar Jupyter-notebook-filer till Python-skript för att göra det enkelt att testa och automatisera med hjälp av MLOpsPython-kodmallen och Azure Mašinsko učenje. Den här processen används vanligtvis för att experimentera/träna kod från en Jupyter-notebook-fil och konvertera den till Python-skript. Dessa skript kan sedan användas för testning och CI/CD-automatisering i produktionsmiljön.

Ett maskininlärningsprojekt kräver experimentering där hypoteser testas med agila verktyg som Jupyter Notebook med hjälp av verkliga datamängder. När modellen är klar för produktion ska modellkoden placeras i en lagringsplats för produktionskod. I vissa fall måste modellkoden konverteras till Python-skript för att placeras i lagringsplatsen för produktionskod. Den här självstudien beskriver en rekommenderad metod för hur du exporterar experimentkod till Python-skript.

I den här självstudien lär du dig att:

  • Rensa nonessential-kod
  • Omstrukturera Jupyter Notebook-kod till funktioner
  • Skapa Python-skript för relaterade uppgifter
  • Skapa enhetstester

Förutsättningar

  • Generera MALLEN MLOpsPython och använd anteckningsböckerna experimentation/Diabetes Ridge Regression Training.ipynb och experimentation/Diabetes Ridge Regression Scoring.ipynb . Dessa notebook-filer används som ett exempel på konvertering från experimentering till produktion. Du hittar dessa notebook-filer på https://github.com/microsoft/MLOpsPython/tree/master/experimentation.
  • Installera nbconvert. Följ endast installationsanvisningarna under avsnittet Installera nbconvert på installationssidan.

Ta bort all nonessential-kod

Viss kod som skrivs under experimenteringen är endast avsedd för undersökande ändamål. Därför är det första steget för att konvertera experimentell kod till produktionskod att ta bort den här nonessential-koden. Om du tar bort nonessential-kod blir koden också mer underhållsbar. I det här avsnittet tar du bort kod från notebook-filen experimentation/Diabetes Ridge Regression Training.ipynb . De instruktioner som skriver ut formen på X och y och cellanropet features.describe är bara för datautforskning och kan tas bort. När du har tagit bort nonessential-kod experimentation/Diabetes Ridge Regression Training.ipynb bör du se ut som följande kod utan markdown:

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)

Omstrukturera kod till funktioner

För det andra måste Jupyter-koden omstruktureras till funktioner. Genom att omstrukturera kod till funktioner blir enhetstestningen enklare och koden blir mer underhållsbar. I det här avsnittet omstrukturerar du:

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

Refaktor Diabetes Ridge Regression Training Notebook till funktioner

I experimentation/Diabetes Ridge Regression Training.ipynbutför du följande steg:

  1. Skapa en funktion med namnet split_data för att dela upp dataramen i test och träna data. Funktionen ska ta dataramen df som en parameter och returnera en ordlista som innehåller nycklarna train och test.

    Flytta koden under rubriken Dela upp data i utbildnings- och valideringsuppsättningar till split_data funktionen och ändra den för att returnera objektet data .

  2. Skapa en funktion med namnet train_model, som tar parametrarna data och args returnerar en tränad modell.

    Flytta koden under rubriken Träningsmodell på Träningsuppsättning till train_model funktionen och ändra den för att returnera objektet reg_model . args Ta bort ordlistan. Värdena kommer från parameternargs.

  3. Skapa en funktion med namnet get_model_metrics, som tar parametrar reg_model och data, och utvärderar modellen och returnerar sedan en ordlista med mått för den tränade modellen.

    Flytta koden under rubriken Verifiera modell på valideringsuppsättning till get_model_metrics funktionen och ändra den för att returnera objektet metrics .

De tre funktionerna bör vara följande:

# 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

Slutför följande steg fortfarande i experimentation/Diabetes Ridge Regression Training.ipynb:

  1. Skapa en ny funktion med namnet main, som inte tar några parametrar och returnerar ingenting.

  2. Flytta koden under rubriken "Läs in data" till main funktionen.

  3. Lägg till anrop för de nyligen skrivna funktionerna i main funktionen:

    # 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. Flytta koden under rubriken "Spara modell" till main funktionen.

Funktionen main bör se ut som följande kod:

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)

I det här skedet bör det inte finnas någon kod kvar i notebook-filen som inte finns i en funktion, förutom importinstruktioner i den första cellen.

Lägg till en instruktion som anropar main funktionen.

main()

Efter refaktorisering experimentation/Diabetes Ridge Regression Training.ipynb bör se ut som följande kod utan markdown:

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()

Refactor Diabetes Ridge Regression Scoring Notebook till funktioner

I experimentation/Diabetes Ridge Regression Scoring.ipynbutför du följande steg:

  1. Skapa en ny funktion med namnet init, som inte tar några parametrar och returnerar ingenting.
  2. Kopiera koden under rubriken "Läs in modell" till init funktionen.

Funktionen init bör se ut som följande kod:

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

init När funktionen har skapats ersätter du all kod under rubriken "Load Model" med ett enda anrop till init enligt följande:

init()

I experimentation/Diabetes Ridge Regression Scoring.ipynbutför du följande steg:

  1. Skapa en ny funktion med namnet run, som tar raw_data och request_headers som parametrar och returnerar en ordlista med resultat enligt följande:

    {"result": result.tolist()}
    
  2. Kopiera koden under rubrikerna "Förbered data" och "Poängsätta data" till run funktionen.

    Funktionen run bör se ut som följande kod (Kom ihåg att ta bort de instruktioner som anger variablerna raw_data och request_headers, som kommer att användas senare när run funktionen anropas):

    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 När funktionen har skapats ersätter du all kod under rubrikerna "Förbered data" och "Poängsätta data" med följande kod:

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)

Föregående kod anger variabler raw_data och request_header, anropar run funktionen med raw_data och request_headeroch skriver ut förutsägelserna.

Efter refaktorisering experimentation/Diabetes Ridge Regression Scoring.ipynb bör se ut som följande kod utan markdown:

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)

För det tredje måste relaterade funktioner slås samman i Python-filer för att bättre hjälpa till att återanvända kod. I det här avsnittet skapar du Python-filer för följande notebook-filer:

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

Skapa Python-fil för notebook-filen Diabetes Ridge Regression Training

Konvertera anteckningsboken till ett körbart skript genom att köra följande instruktion i en kommandotolk, som använder nbconvert paketet och sökvägen experimentation/Diabetes Ridge Regression Training.ipynbtill :

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

När notebook-filen har konverterats till train.pytar du bort eventuella oönskade kommentarer. Ersätt anropet till main() i slutet av filen med ett villkorligt anrop som följande kod:

if __name__ == '__main__':
    main()

Filen train.py bör se ut som följande kod:

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 kan nu anropas från en terminal genom att köra python train.py. Funktionerna från train.py kan också anropas från andra filer.

Filen train_aml.py som finns i diabetes_regression/training katalogen på MLOpsPython-lagringsplatsen anropar de funktioner som definierats i train.py kontexten för ett Azure Mašinsko učenje-experimentjobb. Funktionerna kan också anropas i enhetstester som beskrivs senare i den här guiden.

Skapa Python-fil för notebook-filen Diabetes Ridge Regression Scoring

Konvertera anteckningsboken till ett körbart skript genom att köra följande instruktion i en kommandotolk som använder nbconvert paketet och sökvägen experimentation/Diabetes Ridge Regression Scoring.ipynbtill :

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

När notebook-filen har konverterats till score.pytar du bort eventuella oönskade kommentarer. Filen score.py bör se ut som följande kod:

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)

Variabeln model måste vara global så att den visas i hela skriptet. Lägg till följande instruktion i början av init funktionen:

global model

När du har lagt till föregående instruktion init bör funktionen se ut som följande kod:

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)

Skapa enhetstester för varje Python-fil

För det fjärde skapar du enhetstester för dina Python-funktioner. Enhetstester skyddar kod mot funktionella regressioner och gör det enklare att underhålla. I det här avsnittet skapar du enhetstester för funktionerna i train.py.

train.py innehåller flera funktioner, men vi skapar bara ett enskilt enhetstest för train_model funktionen med hjälp av Pytest-ramverket i den här självstudien. Pytest är inte det enda python-enhetstestningsramverket, men det är ett av de vanligaste. Mer information finns i Pytest.

Ett enhetstest innehåller vanligtvis tre huvudsakliga åtgärder:

  • Ordna objekt – skapa och konfigurera nödvändiga objekt
  • Agera på ett objekt
  • Bekräfta vad som förväntas

Enhetstestet anropar train_model med vissa hårdkodade data och argument och verifierar att det train_model fungerade som förväntat genom att använda den resulterande tränade modellen för att göra en förutsägelse och jämföra förutsägelsen med ett förväntat värde.

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

Nästa steg

Nu när du förstår hur du konverterar från ett experiment till produktionskod kan du läsa följande länkar för mer information och nästa steg: