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

Monitorowanie dryfu danych

Z czasem model przewiduje coraz gorzej, bo zmieniają się rozkłady danych wejściowych. To zjawisko nazywa się dryfem danych (ang. data drift). Monitorowanie dryfu pozwala wykryć moment, w którym model wymaga ponownego wytrenowania.

Jak działa monitorowanie dryfu w Azure ML: monitor modelu porównuje rzeczywisty ruch produkcyjny - przechwytywany automatycznie przez kolektor danych na wdrożonym punkcie końcowym online - z danymi odniesienia, i robi to cyklicznie według harmonogramu. Potrzebuje więc trzech rzeczy:

  1. Modelu wdrożonego na zarządzanym punkcie końcowym online z włączonym zbieraniem danych (skonfigurowałeś to dla wdrożenia diabetes-endpoint w ćwiczeniu 10A).
  2. Pewnej liczby ocenionych żądań produkcyjnych, żeby monitor miał co analizować.
  3. Harmonogramu monitorowania, który definiuje sygnał dryfu danych i częstotliwość jego obliczania.

To ćwiczenie przeprowadzi Cię przez wszystkie trzy kroki, a na końcu pokaże, gdzie obejrzeć wyniki w Studio.

Dlaczego dryf jest groźniejszy niż zwykły błąd: awaria jest widoczna od razu. Dryf nie - model nadal odpowiada, nadal zwraca sensownie wyglądające liczby, tylko coraz częściej się myli. Bez monitorowania zauważa się to po miesiącach.

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}")

Zanim zaczniesz

To ćwiczenie zakłada, że:

  • wykonałeś ćwiczenie 7A, w którym model diabetes_model został wdrożony na zarządzanym punkcie końcowym diabetes-endpoint (wdrożenie blue),
  • wykonałeś ćwiczenie 10A, w którym na tym samym wdrożeniu blue włączono diagnostykę Application Insights i zbieranie danych,
  • zarejestrowałeś zasób danych diabetes_mltable (patrz ćwiczenie 4B) - poniżej posłuży jako dane odniesienia dla sygnału dryfu.

Jeśli użyłeś innych nazw punktu końcowego, wdrożenia lub zasobu danych, podstaw je w poniższym kodzie.

Symulacja ocenionych żądań

Świeżo włączony kolektor danych nie ma jeszcze ruchu produkcyjnego. Uruchom poniższą komórkę, aby wysłać do punktu końcowego diabetes-endpoint serię żądań zbudowanych z pliku data/diabetes2.csv, z celowo przesuniętymi wartościami kilku cech. Dzięki temu monitor będzie miał dane do analizy.

Uwaga: zebrane dane pojawiają się w magazynie obszaru roboczego dopiero po kilku minutach od wysłania żądań, a monitorowanie potrzebuje sensownej ilości danych produkcyjnych - zwykle zgromadzonych przez jeden lub kilka przebiegów harmonogramu - zanim będzie co analizować. Ten krok tylko zapewnia, że w potoku zbierania danych w ogóle znajdą się jakieś wiersze.

Dlaczego przesuwamy wartości: gdyby ruch produkcyjny był identyczny z danymi treningowymi, monitor nie miałby czego wykryć. Sztuczne przesunięcie wieku, liczby ciąż i BMI symuluje sytuację, w której do modelu zaczyna trafiać inna populacja pacjentów niż ta, na której się uczył.

In [ ]:
import json
import time
import pandas as pd

# Wczytujemy dane, ktore posluza jako symulowane zadania oceny
data = pd.read_csv('data/diabetes2.csv')
feature_columns = ['Pregnancies','PlasmaGlucose','DiastolicBloodPressure','TricepsThickness',
                    'SerumInsulin','BMI','DiabetesPedigree','Age']

# Przesuwamy kilka cech, zeby symulowany ruch roznil sie od danych treningowych
drifted = data.copy()
drifted['Pregnancies'] = drifted['Pregnancies'] + 1
drifted['Age'] = round(drifted['Age'] * 1.2).astype(int)
drifted['BMI'] = drifted['BMI'] * 1.1

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

for i in range(0, 20):
    batch = drifted[feature_columns].iloc[i:i + 5].values.tolist()
    request_data = {"data": batch}
    with open("drift-sample.json", "w") as f:
        json.dump(request_data, f)

    ml_client.online_endpoints.invoke(
        endpoint_name=endpoint_name,
        deployment_name=deployment_name,
        request_file="drift-sample.json",
    )
    print(f"Wyslano partie {i + 1}")
    time.sleep(1)

print("Zakonczono wysylanie symulowanych zadan.")

Utworzenie sygnału dryfu i harmonogramu monitorowania

Możesz teraz utworzyć monitor modelu dla wdrożenia diabetes-endpoint. Monitor porównuje dane treningowe z zasobu diabetes_mltable, użyte jako dane odniesienia, z danymi produkcyjnymi zebranymi z punktu końcowego. Uruchamia się cyklicznie na bezserwerowym zasobie obliczeniowym Spark.

Adres e-mail w powiadomieniach jest poniżej wpisany jako you@example.com - zmień go na własny, jeśli chcesz otrzymywać alerty.

Co oznacza próg 0,1: odległość Jensena-Shannona mierzy, jak bardzo rozkład cechy w danych produkcyjnych różni się od rozkładu w danych odniesienia. Wartość 0 to rozkłady identyczne, 1 to rozkłady całkowicie rozłączne. Próg dobiera się do konkretnego zastosowania - zbyt niski zasypie zespół fałszywymi alarmami, zbyt wysoki przepuści realny problem.

In [ ]:
from azure.ai.ml import Input
from azure.ai.ml.constants import AssetTypes, MonitorDatasetContext
from azure.ai.ml.entities import (
    AlertNotification,
    DataDriftSignal,
    DataDriftMetricThreshold,
    NumericalDriftMetrics,
    CategoricalDriftMetrics,
    MonitorDefinition,
    MonitorSchedule,
    MonitoringTarget,
    RecurrenceTrigger,
    RecurrencePattern,
    ServerlessSparkCompute,
    ReferenceData,
)

# Wdrozony model i punkt koncowy, ktory monitorujemy
monitoring_target = MonitoringTarget(
    ml_task="classification",
    endpoint_deployment_id=f"azureml:{endpoint_name}:{deployment_name}",
)

# Jako danych odniesienia uzywamy najnowszej wersji zasobu diabetes_mltable -
# jest typu mltable, a tego formatu wymaga monitorowanie modelu.
diabetes_data_asset = ml_client.data.get(name="diabetes_mltable", label="latest")
reference_data = ReferenceData(
    input_data=Input(type=AssetTypes.MLTABLE, path=diabetes_data_asset.id),
    data_context=MonitorDatasetContext.TRAINING,
)

# Definiujemy sygnal dryfu danych i progi alertow
data_drift_signal = DataDriftSignal(
    reference_data=reference_data,
    metric_thresholds=DataDriftMetricThreshold(
        numerical=NumericalDriftMetrics(jensen_shannon_distance=0.1),
        categorical=CategoricalDriftMetrics(jensen_shannon_distance=0.1),
    ),
    alert_enabled=True,
)

monitor_definition = MonitorDefinition(
    compute=ServerlessSparkCompute(instance_type="standard_e4s_v3", runtime_version="3.4"),
    monitoring_target=monitoring_target,
    monitoring_signals={"data_drift": data_drift_signal},
    # DO ZMIANY: wpisz tutaj swoj adres e-mail (albo adres listy) przed uruchomieniem
    alert_notification=AlertNotification(emails=["you@example.com"]),
)

# Monitor uruchamia sie codziennie o 03:00
monitor_schedule = MonitorSchedule(
    name="diabetes-model-monitor",
    trigger=RecurrenceTrigger(
        frequency="day",
        interval=1,
        schedule=RecurrencePattern(hours=3, minutes=0),
    ),
    create_monitor=monitor_definition,
)

ml_client.schedules.begin_create_or_update(monitor_schedule).result()
print("Utworzono harmonogram monitorowania: diabetes-model-monitor")

Przegląd wyników monitorowania w Studio

Monitor uruchamia się zgodnie z ustawionym harmonogramem, więc wyniki nie pojawią się od razu. Aby je sprawdzić:

  1. W Azure Machine Learning studio wybierz Manage > Monitoring.
  2. Wybierz harmonogram diabetes-model-monitor.
  3. Po co najmniej jednym przebiegu obejrzyj sygnał data drift - łączny wynik dryfu oraz wkład poszczególnych cech.
  4. Jeśli któraś metryka przekroczy swój próg, wszyscy z listy powiadomień dostaną wiadomość e-mail, a przebieg zostanie oznaczony w historii monitora.

Wskazówka: nie musisz czekać na dobowy harmonogram - na stronie harmonogramu w Studio możesz uruchomić przebieg na żądanie i zobaczyć wyniki wcześniej.

Sprzątanie (opcjonalne)

Gdy skończysz, możesz wyłączyć harmonogram (a jeśli chcesz - również go usunąć), żeby przestał generować koszty zaplanowanych przebiegów Spark. Usunąć można wyłącznie harmonogram wcześniej wyłączony.

In [ ]:
# Wylaczamy harmonogram (odkomentuj linie z delete, zeby usunac go calkowicie)
ml_client.schedules.begin_disable(name="diabetes-model-monitor").result()
# ml_client.schedules.begin_delete(name="diabetes-model-monitor").result()
print("Harmonogram monitorowania wylaczony.")

Dalsza lektura

To ćwiczenie wprowadziło pojęcia i zasady monitorowania modeli. Jeśli chcesz pójść dalej:

Monitorowanie można też skonfigurować dla modeli wdrożonych poza Azure Machine Learning albo na punkcie końcowym wsadowym (ang. batch). Zamiast polegać na wbudowanym kolektorze punktu końcowego online, zbierasz wtedy własne dane produkcyjne i rejestrujesz je jako zasób danych.