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 Machine Learning. 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
ochexperimentation/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.ipynb
utför du följande steg:
Skapa en funktion med namnet
split_data
för att dela upp dataramen i test och träna data. Funktionen ska ta dataramendf
som en parameter och returnera en ordlista som innehåller nycklarnatrain
ochtest
.Flytta koden under rubriken Dela upp data i utbildnings- och valideringsuppsättningar till
split_data
funktionen och ändra den för att returnera objektetdata
.Skapa en funktion med namnet
train_model
, som tar parametrarnadata
ochargs
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 objektetreg_model
.args
Ta bort ordlistan. Värdena kommer från parameternargs
.Skapa en funktion med namnet
get_model_metrics
, som tar parametrarreg_model
ochdata
, 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 objektetmetrics
.
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
:
Skapa en ny funktion med namnet
main
, som inte tar några parametrar och returnerar ingenting.Flytta koden under rubriken "Läs in data" till
main
funktionen.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)
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.ipynb
utför du följande steg:
- Skapa en ny funktion med namnet
init
, som inte tar några parametrar och returnerar ingenting. - 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.ipynb
utför du följande steg:
Skapa en ny funktion med namnet
run
, som tarraw_data
ochrequest_headers
som parametrar och returnerar en ordlista med resultat enligt följande:{"result": result.tolist()}
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 variablernaraw_data
ochrequest_headers
, som kommer att användas senare närrun
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_header
och 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)
Kombinera relaterade funktioner i Python-filer
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.ipynb
till :
jupyter nbconvert "Diabetes Ridge Regression Training.ipynb" --to script --output train
När notebook-filen har konverterats till train.py
tar 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 Machine Learning-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.ipynb
till :
jupyter nbconvert "Diabetes Ridge Regression Scoring.ipynb" --to script --output score
När notebook-filen har konverterats till score.py
tar 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:
- MLOpsPython: Skapa en CI/CD-pipeline för att träna, utvärdera och distribuera din egen modell med hjälp av Azure Pipelines och Azure Machine Learning
- Övervaka Azure Machine Learning-experimentjobb och -mått
- Se Övervaka och samla in data från webbtjänstslutpunkter i ML