Praca z magazynami danych¶
W poprzednich ćwiczeniach powstało połączenie z obszarem roboczym Azure ML przy użyciu SDK v2 i uruchomienie prostego zadania na danych z lokalnego pliku CSV. Teraz czas na dane przechowywane w chmurze.
Ważne: Kod w tym notatniku zakłada, że masz wykonane dwa pierwsze kroki z Lab 4A. Jeśli jeszcze ich nie ma - zrób je teraz.
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}")
Przegląd magazynów danych w obszarze roboczym¶
Obszar roboczy zawiera kilka magazynów danych (ang. datastore), w tym magazyn aml_data utworzony we wcześniejszym kroku.
Uruchom poniższy kod, aby pobrać domyślny magazyn danych, a potem wypisać wszystkie magazyny z zaznaczeniem, który z nich jest domyślny.
# Pobierz domyślny magazyn danych
default_ds = ml_client.datastores.get_default()
# Wypisz wszystkie magazyny danych, zaznaczając, który jest domyślny
for ds in ml_client.datastores.list():
print(ds.name, "- domyślny =", ds.name == default_ds.name)
Pobranie magazynu danych do pracy¶
Dalsza część ćwiczenia korzysta z magazynu aml_data, więc trzeba pobrać go po nazwie:
aml_datastore = ml_client.datastores.get(name="aml_data")
print(f"{aml_datastore.name}: {aml_datastore.type} ({aml_datastore.account_name})")
Gdzie trafiają wysłane pliki¶
Magazyn jest wybrany, więc pora umieścić w nim dane. Tu czeka pierwsza niespodzianka.
W SDK v2 wysyłka plików z dysku dzieje się przy okazji rejestrowania zasobu danych (ang. data asset): gdy obiekt Data dostaje lokalną ścieżkę path, SDK sam wysyła pliki do chmury. Zawsze jednak do magazynu domyślnego - klasa Data nie ma parametru pozwalającego wskazać inny. Nie jest to przeoczenie, tylko świadoma decyzja: w SDK v1 istniała metoda Datastore.upload_files(), w v2 jej odpowiednika nie ma.
Co z tego wynika praktycznie: żeby wstawić pliki z dysku do konkretnego magazynu, sięga się po
azcopyalbo po stronę Data → Datastores → Browse w Azure Machine Learning studio. Z poziomu SDK da się natomiast zapisać do wybranego magazynu wynik zadania - i właśnie to zrobimy z magazynemaml_dataw dalszej części ćwiczenia.
Zarejestruj zasób danych typu uri_folder na podstawie lokalnego folderu data, w którym leżą pliki diabetes.csv i diabetes2.csv:
from azure.ai.ml.entities import Data
from azure.ai.ml.constants import AssetTypes
diabetes_data_folder = Data(
path="./data",
type=AssetTypes.URI_FOLDER,
description="Diabetes data files (folder)",
name="diabetes_data_folder",
)
diabetes_data_folder = ml_client.data.create_or_update(diabetes_data_folder)
print(f"Zarejestrowano zasób danych: {diabetes_data_folder.name} (wersja {diabetes_data_folder.version})")
Trenowanie modelu na danych z magazynu danych¶
Zarejestrowany zasób danych przekazuje się do zadania jako wejście (ang. input) - obiekt Input, który wskazuje zasób danych po nazwie i wersji. Azure ML podmontowuje wtedy dane na środowisku obliczeniowym albo je tam pobiera, dzięki czemu skrypt czyta je tak samo, niezależnie od tego, gdzie faktycznie wykonuje się zadanie.
Więcej informacji: Szczegóły pracy z danymi opisuje artykuł Read and write data in a job w dokumentacji Azure ML.
from azure.ai.ml import Input
from azure.ai.ml.constants import AssetTypes
data_input = Input(type=AssetTypes.URI_FOLDER, path=f"azureml:{diabetes_data_folder.name}:{diabetes_data_folder.version}")
print(data_input)
Aby skrypt trenujący mógł skorzystać z wejścia z danymi, musi mieć przewidziany dla niego parametr. Uruchom dwie poniższe komórki, aby utworzyć:
- Folder o nazwie diabetes_training_from_datastore
- Skrypt, który trenuje model klasyfikacji na danych ze wszystkich plików CSV w folderze wskazanym przez przekazane wejście.
import os
# Utwórz folder na pliki zadania
experiment_folder = 'diabetes_training_from_datastore'
os.makedirs(experiment_folder, exist_ok=True)
print(experiment_folder, '- folder utworzony.')
%%writefile $experiment_folder/diabetes_training.py
# Import bibliotek
import os
import argparse
import mlflow
import pandas as pd
import numpy as np
import joblib
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
from sklearn.metrics import roc_curve
# Odczytaj parametry
parser = argparse.ArgumentParser()
parser.add_argument('--regularization', type=float, dest='reg_rate', default=0.01, help='wskaźnik regularyzacji')
parser.add_argument('--data-folder', type=str, dest='data_folder', help='wejście z folderem danych')
parser.add_argument('--output-folder', type=str, dest='output_folder',
required=True, help='folder na połączone dane')
args = parser.parse_args()
reg = args.reg_rate
# Rozpocznij przebieg MLflow, aby zapisywać metryki (śledzenie MLflow jest wbudowane w zadania Azure ML)
mlflow.start_run()
# wczytaj dane o cukrzycy z folderu przekazanego na wejściu
data_folder = args.data_folder
print("Wczytywanie danych z", data_folder)
# Wczytaj wszystkie pliki i połącz ich zawartość w jedną ramkę danych
all_files = os.listdir(data_folder)
diabetes = pd.concat((pd.read_csv(os.path.join(data_folder, csv_file)) for csv_file in all_files))
# Rozdziel cechy (ang. features) i etykietę (ang. label)
X, y = diabetes[['Pregnancies','PlasmaGlucose','DiastolicBloodPressure','TricepsThickness','SerumInsulin','BMI','DiabetesPedigree','Age']].values, diabetes['Diabetic'].values
# Podziel dane na zbiór uczący 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 wskaźnikiem regularyzacji', reg)
mlflow.log_metric('Regularization Rate', float(reg))
model = LogisticRegression(C=1/reg, solver="liblinear").fit(X_train, y_train)
# policz skuteczność
y_hat = model.predict(X_test)
acc = np.average(y_hat == y_test)
print('Skuteczność:', acc)
mlflow.log_metric('Accuracy', float(acc))
# policz 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', float(auc))
os.makedirs('outputs', exist_ok=True)
# pliki zapisane w folderze outputs są automatycznie dołączane do wyników zadania
joblib.dump(value=model, filename='outputs/diabetes_model.pkl')
# Zapisz połączone dane do folderu wskazanego przez wyjście zadania.
# To wyjście wskazuje magazyn aml_data, więc plik wyląduje właśnie tam.
os.makedirs(args.output_folder, exist_ok=True)
sciezka_polaczonych = os.path.join(args.output_folder, 'diabetes_combined.csv')
diabetes.to_csv(sciezka_polaczonych, index=False)
print('Połączone dane zapisane w:', sciezka_polaczonych)
mlflow.end_run()
Skrypt wczytuje dane uczące z wejścia przekazanego mu jako parametr, więc zostaje już tylko skonfigurować zadanie tak, żeby przy zleceniu to wejście przekazało.
from azure.ai.ml import command, Input, Output
from azure.ai.ml.constants import AssetTypes
job = command(
code=experiment_folder,
command="python diabetes_training.py --regularization 0.1 --data-folder ${{inputs.data_folder}} --output-folder ${{outputs.combined}}",
inputs={
"data_folder": Input(type=AssetTypes.URI_FOLDER, path=f"azureml:{diabetes_data_folder.name}:{diabetes_data_folder.version}")
},
outputs={
# Wyjscie wskazuje konkretny magazyn - tak w SDK v2 zapisuje sie
# dane tam, gdzie chcemy, a nie tam, gdzie akurat wypadnie domyslnie.
"combined": Output(
type=AssetTypes.URI_FOLDER,
path="azureml://datastores/aml_data/paths/diabetes-combined/",
),
},
environment="azureml://registries/azureml/environments/sklearn-1.5/labels/latest",
compute="aml-cluster",
display_name="diabetes-training-datastore",
experiment_name="diabetes-training",
)
# zleć zadanie
returned_job = ml_client.jobs.create_or_update(job)
ml_client.jobs.stream(returned_job.name)
Przy pierwszym uruchomieniu zadania zbudowanie środowiska może chwilę potrwać - kolejne uruchomienia są już szybsze.
W trakcie działania zadania (albo po jego zakończeniu) szczegóły obejrzysz w Azure Machine Learning studio, łącznie z kartą Outputs + logs - zajrzyj do pliku user_logs/std_log.txt, żeby sprawdzić, że pliki z danymi zostały wczytane. Metryki zapisane przez MLflow możesz też pobrać z poziomu kodu:
Gdzie szukać wyniku: po zakończeniu zadania otwórz w Azure Machine Learning studio Data → Datastores → aml_data → Browse. W folderze
diabetes-combinedznajdziesz plikdiabetes_combined.csv- dowód, że zadanie zapisało dane do wskazanego magazynu, a nie do domyślnego.
import mlflow
mlflow.set_tracking_uri(ml_client.workspaces.get(ml_client.workspace_name).mlflow_tracking_uri)
mlflow_run = mlflow.get_run(returned_job.name)
print("Metryki:")
for key, value in mlflow_run.data.metrics.items():
print(key, value)
print(f"\nSzczegóły przebiegu w Studio: {returned_job.studio_url}")
Tak jak poprzednio, model wytrenowany przez zadanie możesz zarejestrować.
from azure.ai.ml.entities import Model
from azure.ai.ml.constants import AssetTypes
model = Model(
path=f"azureml://jobs/{returned_job.name}/outputs/artifacts/paths/outputs/diabetes_model.pkl",
name="diabetes_model",
type=AssetTypes.CUSTOM_MODEL,
description="Diabetes classification model",
tags={"Training context": "Command job (using Datastore)"},
)
registered_model = ml_client.models.create_or_update(model)
# Wypisz zarejestrowane modele
print("Zarejestrowane modele:")
for m in ml_client.models.list(name="diabetes_model"):
print(m.name, 'wersja:', m.version)
for tag_name in m.tags:
print('\t', tag_name, ':', m.tags[tag_name])
W tym ćwiczeniu poznajesz kilka sposobów pracy z danymi udostępnianymi przez magazyny danych.
Azure Machine Learning daje jeszcze jeden poziom abstrakcji nad danymi - zasoby danych. Nimi zajmiesz się w następnym ćwiczeniu.