Trenowanie modeli¶
Celem uczenia maszynowego jest wytrenowanie modeli predykcyjnych, z których korzystają potem aplikacje. W Azure Machine Learning modele trenujesz skryptami, używając popularnych bibliotek - Scikit-Learn, TensorFlow, PyTorch i innych. Takie skrypty treningowe uruchamiasz jako zadania (job), dzięki czemu metryki i pliki wyjściowe - a przede wszystkim sam wytrenowany model - są śledzone. Powstały model możesz następnie zarejestrować w obszarze roboczym.
Połączenie z obszarem roboczym¶
Na początek połącz się z obszarem roboczym przy użyciu Azure ML SDK v2.
Uwaga: Jeśli od poprzedniego ćwiczenia wygasła uwierzytelniona sesja z subskrypcją Azure, pojawi się prośba o ponowne zalogowanie.
from azure.ai.ml import MLClient
from azure.identity import DefaultAzureCredential
credential = DefaultAzureCredential()
ml_client = MLClient.from_config(credential=credential)
print(f"Azure ML gotowe do pracy z obszarem roboczym {ml_client.workspace_name}")
Tworzenie skryptu treningowego¶
Model na danych o cukrzycy wytrenuje skrypt Pythona, więc zacznij od utworzenia folderu na skrypt i pliki z danymi.
import os, shutil
# Utwórz folder na pliki eksperymentu
training_folder = 'diabetes-training'
os.makedirs(training_folder, exist_ok=True)
# Skopiuj plik z danymi do podfolderu data, aby skrypt wczytywał go
# tą samą ścieżką względną, której używa w tym repozytorium
os.makedirs(os.path.join(training_folder, 'data'), exist_ok=True)
shutil.copy('data/diabetes.csv', os.path.join(training_folder, 'data', 'diabetes.csv'))
Teraz utwórz skrypt treningowy i zapisz go w tym folderze.
Skrypt wywołuje mlflow.sklearn.autolog(), dzięki czemu parametry i metryki zapisują się same - nie trzeba wypisywać każdej z osobna. Model zapisujemy już jawnie, do nazwanego wyjścia zadania: autolog potrafi to zrobić za nas, ale ta droga wymaga zgodności wersji MLflow z wtyczką Azure ML, a jawny zapis działa zawsze.
%%writefile $training_folder/diabetes_training.py
# Import bibliotek
import argparse
import pandas as pd
import numpy as np
import mlflow
import mlflow.sklearn
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
# Azure ML podaje tu katalog, w ktorym ma wyladowac gotowy model
parser = argparse.ArgumentParser()
parser.add_argument('--model_output', type=str, dest='model_output',
required=True,
help='katalog nazwanego wyjscia zadania na gotowy model')
args = parser.parse_args()
# Automatyczny zapis parametrow i metryk. Modelem zajmujemy sie sami - patrz
# komentarz na koncu skryptu.
mlflow.sklearn.autolog(log_models=False, log_datasets=False)
# Ustaw wspolczynnik regularyzacji
reg = 0.01
mlflow.log_param('regularization_rate', reg)
# wczytaj zbior danych o cukrzycy
print("Wczytywanie danych...")
diabetes = pd.read_csv('data/diabetes.csv')
# Rozdziel cechy (ang. features) i etykiety (ang. labels)
X, y = diabetes[['Pregnancies','PlasmaGlucose','DiastolicBloodPressure','TricepsThickness','SerumInsulin','BMI','DiabetesPedigree','Age']].values, diabetes['Diabetic'].values
# Podziel dane na zbior treningowy i testowy
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.30, random_state=0)
# Wytrenuj model regresji logistycznej
print('Trenowanie modelu regresji logistycznej ze wspolczynnikiem regularyzacji', reg)
model = LogisticRegression(C=1/reg, solver="liblinear").fit(X_train, y_train)
# oblicz skutecznosc (accuracy)
y_hat = model.predict(X_test)
acc = np.average(y_hat == y_test)
print('Accuracy:', acc)
mlflow.log_metric('Accuracy', acc)
# oblicz AUC
y_scores = model.predict_proba(X_test)
auc = roc_auc_score(y_test,y_scores[:,1])
print('AUC: ' + str(auc))
mlflow.log_metric('AUC', auc)
# Zapisujemy model do nazwanego wyjscia zadania. Przez log_model() sie nie
# da: azureml-mlflow obsluguje MLflow najwyzej w wersji 2.16.
mlflow.sklearn.save_model(sk_model=model, path=args.model_output)
print('Model zapisany w:', args.model_output)
Uruchomienie skryptu jako zadania¶
Do tej pory skrypty wykonywały się bezpośrednio w notatniku. Teraz uruchomisz skrypt treningowy jako zadanie command na środowisku obliczeniowym. Dzięki temu Azure Machine Learning śledzi przebieg, a jego metryki, pliki wyjściowe i zarejestrowany model zobaczysz w Azure Machine Learning studio.
Skorzystasz z utworzonego wcześniej klastra aml-cluster oraz z gotowego środowiska, w którym scikit-learn i MLflow są już zainstalowane.
from azure.ai.ml import command, Output
from azure.ai.ml.constants import AssetTypes
# skonfiguruj zadanie
job = command(
code=training_folder,
command="python diabetes_training.py --model_output ${{outputs.model_output}}",
outputs={
# Nazwane wyjscie: Azure ML przygotuje katalog i zapamieta, ze lezy
# w nim model w formacie MLflow.
"model_output": Output(type=AssetTypes.MLFLOW_MODEL),
},
environment="azureml://registries/azureml/environments/sklearn-1.5/labels/latest",
compute="aml-cluster",
display_name="diabetes-training",
experiment_name="diabetes-training",
)
# zlec zadanie
returned_job = ml_client.jobs.create_or_update(job)
# wyswietlaj na biezaco logi zadania w trakcie jego dzialania
ml_client.jobs.stream(returned_job.name)
W trakcie działania zadania możesz otworzyć je w Azure Machine Learning studio pod linkiem wypisanym poniżej.
print(returned_job.services["Studio"].endpoint)
Po zakończeniu zadania metryki i parametry zapisane w jego trakcie pobierzesz również klientem MLflow.
from mlflow.tracking import MlflowClient
client = MlflowClient()
job_run = client.get_run(returned_job.name)
print("Metryki:")
for key, value in job_run.data.metrics.items():
print(key, value)
print("\nParametry:")
for key, value in job_run.data.params.items():
print(key, value)
Rejestrowanie wytrenowanego modelu¶
Skrypt zapisał model do wyjścia zadania o nazwie model_output. Azure ML wie, że leży tam model w formacie MLflow, bo tak zadeklarowaliśmy to wyjście - wystarczy więc wskazać je przy rejestracji.
Rejestracja nadaje modelowi nazwę i kolejny numer wersji. Dzięki temu da się go później odtworzyć, a przy wdrożeniu w jednym z następnych ćwiczeń nie będzie potrzebny osobny skrypt oceniający.
from azure.ai.ml.entities import Model
from azure.ai.ml.constants import AssetTypes
# Rejestrujemy model z nazwanego wyjscia zadania (a nie z artefaktow MLflow)
model = Model(
path=f"azureml://jobs/{returned_job.name}/outputs/model_output",
name="diabetes_model",
type=AssetTypes.MLFLOW_MODEL,
description="Diabetes classification model trained with scikit-learn.",
tags={"training_context": "command job"},
)
registered_model = ml_client.models.create_or_update(model)
print(f"Zarejestrowany model: {registered_model.name}, wersja: {registered_model.version}")
# Wypisz wszystkie wersje zarejestrowanego modelu
for m in ml_client.models.list(name="diabetes_model"):
print(m.name, 'wersja:', m.version)
Skrypt treningowy z parametrami¶
Zadanie treningowe staje się dużo elastyczniejsze, gdy skrypt przyjmuje parametry - można wtedy powtarzać to samo trenowanie z różnymi ustawieniami bez modyfikowania kodu. Tutaj dodasz parametr sterujący współczynnikiem regularyzacji regresji logistycznej.
Znowu zacznij od utworzenia folderu na sparametryzowany skrypt i dane treningowe.
import os, shutil
# Utwórz folder na pliki eksperymentu
training_folder = 'diabetes-training-params'
os.makedirs(training_folder, exist_ok=True)
# Skopiuj plik z danymi do podfolderu data, aby skrypt wczytywał go
# tą samą ścieżką względną, której używa w tym repozytorium
os.makedirs(os.path.join(training_folder, 'data'), exist_ok=True)
shutil.copy('data/diabetes.csv', os.path.join(training_folder, 'data', 'diabetes.csv'))
Utwórz teraz skrypt, w którym współczynnik regularyzacji jest hiperparametrem przyjmowanym z wiersza poleceń.
%%writefile $training_folder/diabetes_training.py
# Import bibliotek
import argparse
import pandas as pd
import numpy as np
import mlflow
import mlflow.sklearn
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
# Azure ML podaje tu katalog, w ktorym ma wyladowac gotowy model
parser = argparse.ArgumentParser()
parser.add_argument('--model_output', type=str, dest='model_output',
required=True,
help='katalog nazwanego wyjscia zadania na gotowy model')
parser.add_argument('--reg_rate', type=float, dest='reg', default=0.01)
args = parser.parse_args()
# Automatyczny zapis parametrow i metryk. Modelem zajmujemy sie sami - patrz
# komentarz na koncu skryptu.
mlflow.sklearn.autolog(log_models=False, log_datasets=False)
reg = args.reg
mlflow.log_param('regularization_rate', reg)
# wczytaj zbior danych o cukrzycy
print("Wczytywanie danych...")
diabetes = pd.read_csv('data/diabetes.csv')
# Rozdziel cechy (ang. features) i etykiety (ang. labels)
X, y = diabetes[['Pregnancies','PlasmaGlucose','DiastolicBloodPressure','TricepsThickness','SerumInsulin','BMI','DiabetesPedigree','Age']].values, diabetes['Diabetic'].values
# Podziel dane na zbior treningowy i testowy
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.30, random_state=0)
# Wytrenuj model regresji logistycznej
print('Trenowanie modelu regresji logistycznej ze wspolczynnikiem regularyzacji', reg)
model = LogisticRegression(C=1/reg, solver="liblinear").fit(X_train, y_train)
# oblicz skutecznosc (accuracy)
y_hat = model.predict(X_test)
acc = np.average(y_hat == y_test)
print('Accuracy:', acc)
mlflow.log_metric('Accuracy', acc)
# oblicz AUC
y_scores = model.predict_proba(X_test)
auc = roc_auc_score(y_test,y_scores[:,1])
print('AUC: ' + str(auc))
mlflow.log_metric('AUC', auc)
# Zapisujemy model do nazwanego wyjscia zadania. Przez log_model() sie nie
# da: azureml-mlflow obsluguje MLflow najwyzej w wersji 2.16.
mlflow.sklearn.save_model(sk_model=model, path=args.model_output)
print('Model zapisany w:', args.model_output)
Przekazanie parametrów do zadania¶
Poprzednio skrypt treningowy działał z domyślnym współczynnikiem regularyzacji. Teraz uruchomisz wersję sparametryzowaną i przekażesz argument --reg_rate w poleceniu zadania (command). Dzięki temu to samo trenowanie powtórzysz z różnymi wartościami regularyzacji bez edytowania skryptu.
from azure.ai.ml import command, Output
from azure.ai.ml.constants import AssetTypes
# skonfiguruj zadanie, przekazujac wspolczynnik regularyzacji jako argument
job = command(
code=training_folder,
command="python diabetes_training.py --reg_rate 0.1 --model_output ${{outputs.model_output}}",
outputs={
# Nazwane wyjscie: Azure ML przygotuje katalog i zapamieta, ze lezy
# w nim model w formacie MLflow.
"model_output": Output(type=AssetTypes.MLFLOW_MODEL),
},
environment="azureml://registries/azureml/environments/sklearn-1.5/labels/latest",
compute="aml-cluster",
display_name="diabetes-training",
experiment_name="diabetes-training",
)
# zlec zadanie
returned_job = ml_client.jobs.create_or_update(job)
# wyswietlaj na biezaco logi zadania w trakcie jego dzialania
ml_client.jobs.stream(returned_job.name)
Tak jak poprzednio, możesz pobrać metryki i parametry zapisane przez zadanie.
from mlflow.tracking import MlflowClient
client = MlflowClient()
job_run = client.get_run(returned_job.name)
print("Metryki:")
for key, value in job_run.data.metrics.items():
print(key, value)
print("\nParametry:")
for key, value in job_run.data.params.items():
print(key, value)
Rejestrowanie nowej wersji modelu¶
Powstał nowy wytrenowany model, więc możesz zarejestrować go jako kolejną wersję diabetes_model w obszarze roboczym.
from azure.ai.ml.entities import Model
from azure.ai.ml.constants import AssetTypes
# Rejestrujemy model z nazwanego wyjscia zadania (a nie z artefaktow MLflow)
model = Model(
path=f"azureml://jobs/{returned_job.name}/outputs/model_output",
name="diabetes_model",
type=AssetTypes.MLFLOW_MODEL,
description="Diabetes classification model trained with scikit-learn.",
tags={"training_context": "command job"},
)
registered_model = ml_client.models.create_or_update(model)
print(f"Zarejestrowany model: {registered_model.name}, wersja: {registered_model.version}")
# Wypisz wszystkie wersje zarejestrowanego modelu
for m in ml_client.models.list(name="diabetes_model"):
print(m.name, 'wersja:', m.version)
W menu File wybierz Close and Halt, aby zamknąć ten notatnik. Następnie wróć do instrukcji ćwiczenia.