Materiały kursów
Materiały / Azure ML (polski)
Instrukcja do tego ćwiczeniaPobierz notatnik (.ipynb)

Monitorowanie modelu

Kiedy model działa już produkcyjnie jako usługa, trzeba wiedzieć, jak jest używany i czy nadal działa poprawnie. Azure Machine Learning daje na to dwa uzupełniające się sposoby dla zarządzanego punktu końcowego online (ang. managed online endpoint):

  • Integracja z Application Insights - ustawienie na poziomie wdrożenia, które wysyła wbudowaną telemetrię (liczba żądań, czasy odpowiedzi), a także wszystko, co skrypt oceniający wypisze na standardowe wyjście, do zasobu Application Insights powiązanego z obszarem roboczym.
  • Monitorowanie modelu w Azure Machine Learning - bogatsza funkcja zbudowana na zbieraniu danych (ang. data collection) z punktu końcowego. Śledzi w czasie dryf danych, dryf predykcji i jakość danych. Jest ona tematem następnego ćwiczenia (ćwiczenie 10B), ale to ćwiczenie włącza zbieranie danych, od którego tamta funkcja zależy.

W tym ćwiczeniu wytrenujesz i wdrożysz model klasyfikacji cukrzycy na punkcie końcowym diabetes-endpoint (tym samym, co w ćwiczeniu 7A) z włączoną diagnostyką Application Insights oraz zbieraniem danych. Potem wywołasz punkt końcowy i obejrzysz powstałą telemetrię.

Po co to robimy: model, który dobrze wypadł na danych testowych, nie jest modelem sprawdzonym na zawsze. Dane w produkcji zmieniają się same z siebie - zmienia się populacja pacjentów, zmieniają się procedury pomiarowe. Bez monitorowania dowiesz się o tym dopiero wtedy, gdy ktoś zauważy złe decyzje.

Połączenie z obszarem roboczym

Zacznij od połączenia z obszarem roboczym (ang. workspace).

Uwaga: jeśli od poprzedniego ćwiczenia wygasła sesja uwierzytelniania z subskrypcją Azure, zobaczysz prośbę o ponowne zalogowanie.

In [ ]:
from azure.ai.ml import MLClient
from azure.identity import DefaultAzureCredential

credential = DefaultAzureCredential()
ml_client = MLClient.from_config(credential=credential)
print(f"Gotowe do pracy z obszarem roboczym {ml_client.workspace_name}")

Przygotowanie modelu do wdrożenia

Potrzebujesz teraz modelu, który wdrożysz. Uruchom poniższą komórkę, aby wczytać dane o cukrzycy, wytrenować prosty model drzewa decyzyjnego i zarejestrować go jako zasób modelu diabetes_model (jeśli rejestrowałeś ten model we wcześniejszym ćwiczeniu, powstanie jego nowa wersja).

In [ ]:
import pandas as pd
import numpy as np
import joblib
import mlflow
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import roc_auc_score
from azure.ai.ml.entities import Model
from azure.ai.ml.constants import AssetTypes

# Wczytujemy dane o cukrzycy (zarejestrowane jako zasob diabetes_dataset - patrz cwiczenie 1A)
diabetes = pd.read_csv('data/diabetes.csv')

# Rozdzielamy cechy i etykiety
X, y = diabetes[['Pregnancies','PlasmaGlucose','DiastolicBloodPressure','TricepsThickness',
                  'SerumInsulin','BMI','DiabetesPedigree','Age']].values, diabetes['Diabetic'].values

# Dzielimy 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)

# Trenujemy model drzewa decyzyjnego, sledzac metryki przy uzyciu MLflow
mlflow.start_run()
print('Trenowanie modelu drzewa decyzyjnego')
model = DecisionTreeClassifier().fit(X_train, y_train)

y_hat = model.predict(X_test)
acc = np.average(y_hat == y_test)
mlflow.log_metric('Accuracy', acc)
print('Skutecznosc:', acc)

y_scores = model.predict_proba(X_test)
auc = roc_auc_score(y_test, y_scores[:, 1])
mlflow.log_metric('AUC', auc)
print('AUC:', auc)
mlflow.end_run()

# Zapisujemy plik wytrenowanego modelu, zeby dalo sie go zarejestrowac
# i spakowac do wdrozenia
model_file = 'diabetes_model.pkl'
joblib.dump(value=model, filename=model_file)

# Rejestrujemy model jako zasob w obszarze roboczym
registered_model = Model(
    path=model_file,
    type=AssetTypes.CUSTOM_MODEL,
    name="diabetes_model",
    description="A decision tree model that predicts diabetes",
)
model = ml_client.models.create_or_update(registered_model)

print(f"Model wytrenowany i zarejestrowany: {model.name}, wersja {model.version}")

Wdrożenie modelu jako zarządzanego punktu końcowego online

Możesz teraz wdrożyć zarejestrowany model jako zarządzany punkt końcowy online.

Najpierw utwórz folder na pliki wdrożenia.

In [ ]:
import os

folder_name = 'diabetes_service'
os.makedirs(folder_name, exist_ok=True)
print(folder_name)

Potrzebujesz jeszcze skryptu wejściowego (oceniającego, ang. scoring script), którego wdrożenie użyje do wczytania modelu i obsługi przychodzących żądań. Poniższy skrypt wypisuje dane każdego żądania wraz z predykcjami - dzięki temu zobaczysz je w Application Insights - a przy użyciu klasy Collector z pakietu azureml-ai-monitoring zapisuje wejścia i wyjścia modelu. To właśnie te zapisy posłużą jako dane produkcyjne monitorowi, który utworzysz w ćwiczeniu 10B.

Zwróć uwagę na nazwy init i run: to nie są dowolne nazwy. Azure ML wywołuje te dwie funkcje po nazwie - init() raz, przy uruchamianiu usługi, a run() przy każdym żądaniu. Zmiana nazwy zepsuje wdrożenie.

In [ ]:
%%writefile $folder_name/score_diabetes.py
import os
import json
import joblib
import numpy as np
import pandas as pd
from azureml.ai.monitoring import Collector

# Wywolywane raz, przy uruchamianiu uslugi
def init():
    global model, inputs_collector, outputs_collector
    # Ustalamy sciezke do wdrozonego pliku modelu i wczytujemy go
    model_path = os.path.join(os.getenv('AZUREML_MODEL_DIR'), 'diabetes_model.pkl')
    model = joblib.load(model_path)
    # Kolektory zapisuja wejscia i wyjscia modelu na potrzeby zbierania danych
    # i monitorowania modelu
    inputs_collector = Collector(name='model_inputs')
    outputs_collector = Collector(name='model_outputs')

# Wywolywane przy kazdym przychodzacym zadaniu
def run(raw_data):
    # Odczytujemy dane wejsciowe jako tablice numpy
    data = json.loads(raw_data)['data']
    np_data = np.array(data)
    input_df = pd.DataFrame(np_data)

    # Pobieramy predykcje z modelu
    predictions = model.predict(np_data)

    # Wypisujemy dane i predykcje - dzieki temu trafia do Application Insights
    log_text = 'Data:' + str(data) + ' - Predictions:' + str(predictions)
    print(log_text)

    # Zamieniamy kazda predykcje (0 lub 1) na nazwe klasy
    classnames = ['zdrowy', 'chory']
    predicted_classes = [classnames[prediction] for prediction in predictions]

    # Zapisujemy wejscia i wyjscia na potrzeby zbierania danych i monitorowania
    context = inputs_collector.collect(input_df)
    outputs_collector.collect(pd.DataFrame({'predicted_classes': predicted_classes}), context)

    # Zwracamy listę predykcji - serwer inferencyjny sam zamieni ją na JSON
    return predicted_classes

Potrzebne będzie też środowisko (ang. environment) określające pakiety Pythona wymagane przez wdrożenie.

In [ ]:
%%writefile $folder_name/diabetes_env.yml
name: diabetes-service-env
dependencies:
  - python=3.10
  - pip
  - pip:
      - scikit-learn
      - joblib
      - pandas
      - numpy
      - azureml-ai-monitoring

Teraz możesz wdrożyć model na zarządzanym punkcie końcowym diabetes-endpoint. Wdrożenie o nazwie blue skonfigurujesz jednocześnie pod diagnostykę Application Insights (app_insights_enabled=True) i zbieranie danych (data_collector).

Uwaga: potrwa to kilka minut - tworzenie wdrożenia czeka, aż zgłosi ono gotowość.

In [ ]:
from azure.ai.ml.entities import (
    ManagedOnlineEndpoint,
    ManagedOnlineDeployment,
    Environment,
    CodeConfiguration,
    DataCollector,
    DeploymentCollection,
)

endpoint_name = "diabetes-endpoint"
deployment_name = "blue"

# Tworzymy punkt koncowy, jesli jeszcze nie istnieje (np. z cwiczenia 7A)
endpoint = ManagedOnlineEndpoint(name=endpoint_name, auth_mode="key")
ml_client.online_endpoints.begin_create_or_update(endpoint).result()

registered_model = ml_client.models.get(name="diabetes_model", label="latest")

diabetes_env = Environment(
    name="diabetes-service-env",
    description="Environment for the diabetes scoring service",
    conda_file=f"{folder_name}/diabetes_env.yml",
    image="mcr.microsoft.com/azureml/openmpi5.0-ubuntu24.04",
)

data_collector = DataCollector(
    collections={
        "model_inputs": DeploymentCollection(enabled="true"),
        "model_outputs": DeploymentCollection(enabled="true"),
    }
)

blue_deployment = ManagedOnlineDeployment(
    name=deployment_name,
    endpoint_name=endpoint_name,
    model=registered_model,
    environment=diabetes_env,
    code_configuration=CodeConfiguration(code=folder_name, scoring_script="score_diabetes.py"),
    instance_type="Standard_DS2_v2",
    instance_count=1,
    app_insights_enabled=True,
    data_collector=data_collector,
)
ml_client.online_deployments.begin_create_or_update(blue_deployment).result()

# Kierujemy caly ruch na to wdrozenie
endpoint.traffic = {deployment_name: 100}
ml_client.online_endpoints.begin_create_or_update(endpoint).result()

print(f"Wdrozono diabetes_model na {endpoint_name} z wlaczona diagnostyka Application Insights i zbieraniem danych.")

Korzystanie z usługi

Wdrożenie jest gotowe, więc możesz wysłać dane do oceny i sprawdzić, czy wracają predykcje.

Wskazówka: jeśli pojawi się błąd, bo wdrożenie nie jest jeszcze gotowe, odczekaj kilka sekund i spróbuj ponownie.

In [ ]:
import json

# Przygotowujemy nowe dane do oceny
x_new = [[2,180,74,24,21,23.9091702,1.488172308,22],
         [0,148,58,11,179,39.19207553,0.160829008,45]]

request_data = {"data": x_new}
with open("sample-data.json", "w") as f:
    json.dump(request_data, f)

response = ml_client.online_endpoints.invoke(
    endpoint_name=endpoint_name,
    deployment_name=deployment_name,
    request_file="sample-data.json",
)

predicted_classes = json.loads(response)
for i in range(len(x_new)):
    print("Pacjent {}".format(x_new[i]), predicted_classes[i])

Przegląd telemetrii w Application Insights

Możesz teraz obejrzeć dane zapisane dla punktu końcowego:

  1. W Azure Machine Learning studio otwórz stronę punktu końcowego diabetes-endpoint i przejdź na kartę Monitoring. Zobaczysz wbudowane wykresy żądań i czasów odpowiedzi - to najszybszy sposób na potwierdzenie, że Application Insights odbiera telemetrię.

  2. W portalu Azure otwórz swój obszar roboczy Machine Learning i na stronie Overview wybierz powiązany zasób Application Insights.

  3. W zasobie Application Insights wybierz Logs.

    Uwaga: jeśli otwierasz Log Analytics po raz pierwszy, może być potrzebne kliknięcie Get Started, aby przejść do edytora zapytań.

  4. Uruchom zapytanie podobne do poniższego (dokładne nazwy pól w customDimensions zależą od obrazu bazowego użytego przez środowisko, więc jeśli nic nie wróci, obejrzyj strukturę tabeli traces):

    traces
    |where message == "STDOUT"
    |project timestamp, message, customDimensions
    
  5. Telemetria potrzebuje kilku minut, żeby dotrzeć do Application Insights - odczekaj i uruchom zapytanie ponownie, aż zobaczysz zapisane dane i predykcje.

Dlaczego to nie pojawia się od razu: telemetria jest buforowana i wysyłana partiami. Pusty wynik tuż po wywołaniu punktu końcowego nie oznacza, że coś nie działa.

Więcej informacji: o monitorowaniu zarządzanych punktów końcowych online przy użyciu Application Insights przeczytasz w artykule Monitor online endpoints w dokumentacji Azure Machine Learning. Pełniejsze monitorowanie modelu - dryf danych, dryf predykcji i jakość danych - jest tematem ćwiczenia 10B: Monitorowanie dryfu danych, które opiera się na wdrożeniu diabetes-endpoint i zbieraniu danych skonfigurowanych przed chwilą.