Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Wykorzystaj zmierzone wyniki, aby znaleźć lepsze współczynniki modelu. W tym przykładzie aplikacja w Pythonie dopasowuje formułę przewidywania wagi, sprawdza ją w oddzielnych rekordach walidacyjnych i zatwierdza, jeśli przewidywania będą trafniejsze.
Aplikacja (zwana supervisorem) przechowuje zatwierdzone współczynniki do późniejszych prognoz. Fitting działa w NumPy, poza grafem przepływu danych. Wbudowana transformacja mapowania następnie ocenia zatwierdzoną formułę.
Jak łączą się elementy
- Eksport dopasowań. Graf eksportu przekazuje ukończone dopasowania do aplikacji.
- Dopasowuj i zatwierdzaj zewnętrznie. Przykład w Pythonie oblicza kandydata i decyzję przeglądu. Twój przełożony odpowiada za zatwierdzanie i utrwalanie.
- Zapisz zatwierdzone współczynniki. Superwizor zapisuje pełny rekord aktywnego modelu do magazynu stanów.
Aby przetworzyć ten rekord, zobacz Odczytywanie współczynników z magazynu stanu.
W przypadku dostarczania przez MQTT zamiast wyszukiwania w magazynie stanowym, zobacz Dostarczaj zatwierdzone aktualizacje modelu przez MQTT.
Prerequisites
Ukończ wspólne przykładowe wymagania wstępne, w tym default profil i factory-mqtt punkt końcowy. Używaj YAML do debugowania oraz Azure CLI lub Bicep do zarządzania środowiskiem produkcyjnym.
Dla wdrożeń CLI ustaw AIO_INSTANCE_NAME i RESOURCE_GROUP na istniejącą instancję i grupę zasobów. W przypadku wdrożeń Bicep można również ustawić CUSTOM_LOCATION_NAME na istniejącą lokalizację niestandardową instancji. Zakładki wdrożeń odnoszą się do istniejącej instancji, profilu i punktu końcowego; nie tworzą ich. Graf eksportu nie wymaga endpointu rejestru, ponieważ nie ma transformacji.
Skrypt dopasowania wymaga także Python 3 i NumPy. Przykład zapisu stanów w magazynie wykorzystuje klientów MQTT mosquitto_pub i mosquitto_sub.
Przygotuj dopasowane rekordy
Przygotuj ukończone dopasowania z wartościami cech używanymi w każdej prognozie. Wzorzec wyrównania i korelacji pokazuje jeden ze sposobów ich wytworzenia.
Dopasuj kandydata z syntetycznych dopasowanych rekordów
Zacznij od modelu v7: weight = 2 * speed + 0.5 * temperature + 175.
Każdy dopasowany rekord musi zawierać wartości cech użyte dla danego elementu, jego zmierzoną wagę oraz wersję modelu, która wygenerowała predykcję.
Na przykład dane szkoleniowe dla nadzorcy to:
{"assetId":"line-1","pieceId":"part-1","modelVersion":7,"speed":8,"temperature":18,"predictedWeight":200,"measuredWeight":198,"residual":-2}
Użyj tych syntetycznych dopasowań: cztery do dopasowania modelu i dwa do walidacji. Zachowaj odrębne identyfikatory elementów zestawów.
| Używanie | Kawałek | Szybkość | Temperatura | Zmierzona waga | Predykcja Model v7 |
|---|---|---|---|---|---|
| Szkolenia | part-1 |
8 | 18 | 198 | 200 |
| Szkolenia | part-2 |
10 | 18 | 202 | 204 |
| Szkolenia | part-3 |
8 | 22 | 200 | 202 |
| Szkolenia | part-4 |
10 | 22 | 204 | 206 |
| Validation | part-5 |
9 | 20 | 201 | 203 |
| Validation | part-6 |
11 | 24 | 207 | 209 |
Operacja dopasowania minimalizuje sumę kwadratów błędów dla b0 + b1 * speed + b2 * temperature. Te wartości treningowe dają:
- Współczynnik prędkości:
(202 - 198) / (10 - 8) = 2. - Współczynnik temperatury:
(200 - 198) / (22 - 18) = 0.5. - Przechwycenie:
198 - 2 * 8 - 0.5 * 18 = 173.
Kandydat przewiduje 207 i 201 dla dwóch fragmentów walidacyjnych. Jego pierwiastek z błędu średniokwadratowego (RMSE) to 0; RMSE modelu v7 to 2. Wybierz odpowiednią wielkość próby walidacyjnej dla swojej aplikacji.
W przypadku danych wejściowych na żywo wdroż graf wyeksportowany za pomocą jednej z następujących metod. Aplikacja subskrybuje factory/supervisor-input; publikuje ukończone dopasowania do factory/matches.
Samodzielne demo Python poniżej korzysta bezpośrednio z tabeli i nie wymaga MQTT.
- W doświadczeniu operacyjnym otwórz swoją instancję i wybierz wykres przepływu danych>Utwórz wykres przepływu danych.
- Nadaj nazwę wykresowi
export-training-matchesi wybierz profildefault. - Dodaj źródło
sourcez endpointemfactory-mqtti tematemfactory/matches. - Dodaj element docelowy
destinationz endpointemfactory-mqtti tematemfactory/supervisor-input. - Połącz
sourcebezpośrednio dodestination, bez dodawania transformacji i wybierz Zapisz.
Graf przekazuje dalej każdy zakończony mecz bez zmian. Aplikacja zbiera dopasowania, oddziela dane szkoleniowe i walidacyjne oraz dopasowuje model dla kandydata.
Przykładowy kandydat wygenerowany przez tę aplikację na factory/model-proposals:
{
"kind": "modelProposal",
"assetId": "line-1",
"updateId": "update-42",
"expectedModelVersion": 7,
"modelVersion": 8,
"coefficients": {
"speedCoefficient": 2,
"temperatureCoefficient": 0.5,
"intercept": 173
},
"validation": {
"trainingPieceIds": ["part-1", "part-2", "part-3", "part-4"],
"validationPieceIds": ["part-5", "part-6"],
"activeRmse": 2,
"candidateRmse": 0
}
}
W tym przykładzie zatwierdzenie wymaga skonfigurowanego zasobu line-1, aktywnej wersji 7, wersji kandydackiej 8, skończonych współczynników, zbiorów próbek rozłącznych, niższej walidacji RMSE oraz zmiany wyrazu wolnego nie większej niż 3. Wyraz wolny zmienił się o -2, więc ten kandydat modelu przechodzi. Kandydat z interceptem 180 nie przechodzi ostatniej próby. Odrzuć ponowienie, gdy v8 jest aktywne.
Te kontrole są przykładowymi zasadami aplikacji.
Zapisz ten przykład jako fit-model.py i uruchom python3 fit-model.py. Wykorzystuje powyższe sześć rekordów i drukuje decyzję dotyczącą kandydata i decyzję z przeglądu. Twój przełożony zajmuje się MQTT i zapisami w stanie aktywnym; skrypt tylko dopasowuje i weryfikuje.
import json
import numpy as np
# Each row is (piece ID, speed, temperature, measured weight).
training = [
("part-1", 8, 18, 198),
("part-2", 10, 18, 202),
("part-3", 8, 22, 200),
("part-4", 10, 22, 204),
]
validation = [("part-5", 9, 20, 201), ("part-6", 11, 24, 207)]
if {r[0] for r in training} & {r[0] for r in validation}:
raise ValueError("Training and validation pieces must be distinct.")
x = np.array([[1, speed, temperature] for _, speed, temperature, _ in training], dtype=float)
y = np.array([weight for _, _, _, weight in training], dtype=float)
candidate, _, rank, _ = np.linalg.lstsq(x, y, rcond=None)
if rank != 3 or not np.isfinite(candidate).all():
raise ValueError("The fit needs three independent, finite parameters.")
vx = np.array([[1, speed, temperature] for _, speed, temperature, _ in validation], dtype=float)
vy = np.array([weight for _, _, _, weight in validation], dtype=float)
active = np.array([175, 2, 0.5]) # Intercept, speed, temperature for v7.
active_rmse = float(np.sqrt(np.mean((vx @ active - vy) ** 2)))
candidate_rmse = float(np.sqrt(np.mean((vx @ candidate - vy) ** 2)))
proposal = {
"kind": "modelProposal",
"assetId": "line-1",
"updateId": "update-42",
"expectedModelVersion": 7,
"modelVersion": 8,
"coefficients": {
"intercept": float(candidate[0]),
"speedCoefficient": float(candidate[1]),
"temperatureCoefficient": float(candidate[2]),
},
"validation": {
"trainingPieceIds": [row[0] for row in training],
"validationPieceIds": [row[0] for row in validation],
"activeRmse": active_rmse,
"candidateRmse": candidate_rmse,
},
}
def review(update, active_model, committed_update_ids):
"""Example policy for candidates produced by this trusted fitting process."""
coefficients = update["coefficients"]
metrics = update["validation"]
if update["updateId"] in committed_update_ids:
return {"approved": False, "reason": "duplicate update"}
if update["assetId"] != active_model["assetId"]:
return {"approved": False, "reason": "wrong asset"}
if (update["expectedModelVersion"] != active_model["modelVersion"]
or update["modelVersion"] != active_model["modelVersion"] + 1):
return {"approved": False, "reason": "stale or unexpected version"}
if (set(metrics["trainingPieceIds"]) & set(metrics["validationPieceIds"])
or not metrics["trainingPieceIds"] or not metrics["validationPieceIds"]):
return {"approved": False, "reason": "invalid validation split"}
numbers = [*coefficients.values(), metrics["activeRmse"], metrics["candidateRmse"]]
if not np.isfinite(numbers).all():
return {"approved": False, "reason": "non-finite coefficient or metric"}
if metrics["candidateRmse"] < 0 or metrics["activeRmse"] < 0:
return {"approved": False, "reason": "invalid RMSE"}
if metrics["candidateRmse"] >= metrics["activeRmse"]:
return {"approved": False, "reason": "no validation improvement"}
if abs(coefficients["intercept"] - active_model["intercept"]) > 3:
return {"approved": False, "reason": "intercept change exceeds policy"}
return {"approved": True, "reason": "candidate passes example policy"}
active_record = {"assetId": "line-1", "modelVersion": 7, "intercept": 175}
decision = review(proposal, active_record, set())
print(json.dumps({"candidate": proposal, "review": decision}, allow_nan=False))
Zaokrąglanie liczb zmiennoprzecinkowych może wypisać wartości bliskie 173, 2, 0.5 i 0.
Stosuj tolerancje numeryczne i zachowuj dokładne zatwierdzone współczynniki.
Review oczekuje poprawnie sformowanych kandydatów i wskaźników z zaufanego procesu dopasowania.
Przed zapisem zatwierdzonego rekordu nadzorca ponownie sprawdza aktywną wersję i zapisuje identyfikator zatwierdzenia oraz aktualizacji w swoim własnym, trwałym dzienniku. Serializuj operacje sprawdzania i zapisu dla każdego zasobu, aby konkurencyjne aktualizacje nie mogły przejść tego samego sprawdzenia wersji.
Zapisz zatwierdzone współczynniki
Po zatwierdzeniu nadzorca zapisuje jeden kompletny rekord aktywnego modelu pod kluczem factory-active-models. Początkowo zawiera:
{"assetId":"line-1","modelVersion":7,"speedCoefficient":2,"temperatureCoefficient":0.5,"intercept":175}
Po zaakceptowaniu update-42, zamień go na:
{"assetId":"line-1","modelVersion":8,"speedCoefficient":2,"temperatureCoefficient":0.5,"intercept":173}
Aby przygotować demo samodzielnego wyszukiwania, zapisz syntetyczny rekord v8 bezpośrednio. Dla modelu dopasowanego zastąp wszystkie trzy poniższe współczynniki dokładnie zatwierdzonymi wartościami.
Aby porównać v7 i v8, najpierw uruchom writera z modelVersion: 7 i intercept: 175, potem przywróć wartości v8 i uruchom go ponownie.
Użyj protokołu state-store SET. Zapisz ten skrypt Pythona jako write-model.py; tworzy plik żądania o wymaganej długości bajtów.
import json
from pathlib import Path
record = {
"assetId": "line-1",
"modelVersion": 8,
"speedCoefficient": 2,
"temperatureCoefficient": 0.5,
"intercept": 173,
}
parts = [b"SET", b"factory-active-models", json.dumps(record, separators=(",", ":")).encode("utf-8")]
request = b"*3\r\n" + b"".join(
b"$" + str(len(part)).encode("ascii") + b"\r\n" + part + b"\r\n"
for part in parts
)
Path("set-model.resp").write_bytes(request)
Do zapisu debugującego wygeneruj plik, a następnie wyślij go z wymaganymi właściwościami MQTT v5. Najpierw uruchom subskrybenta w innym terminalu; Dodaj uwierzytelnianie i opcje TLS brokera do obu poleceń MQTT.
Utrzymuj zegar modułu zapisującego w granicach jednej minuty od zegara brokera.
Właściwość __ts zawiera znacznik czasu żądania. Jeśli odpowiedź informuje, że znacznik czasu jest zbyt odległy w przyszłości, poprawij niedopasowanie zegara przed ponowną próbą.
mosquitto_sub -h <BROKER_HOST> -p <BROKER_PORT> -V mqttv5 -q 1 \
-F '%D %p' \
-t 'clients/model-writer/services/statestore/_any_/command/invoke/response'
python3 write-model.py
mosquitto_pub -h <BROKER_HOST> -p <BROKER_PORT> -V mqttv5 -q 1 \
-t 'statestore/v1/FA9AE35F-2F64-47CD-9BFF-08E2B32A0FE8/command/invoke' \
-D publish response-topic 'clients/model-writer/services/statestore/_any_/command/invoke/response' \
-D publish correlation-data 'update-42' \
-D publish user-property __ts "$(date +%s%3N):0:model-writer" \
-f set-model.resp
Pomyślny zapis wyświetla update-42 +OK: dane korelacji żądania, a następnie payload odpowiedzi. Aby uzyskać wymagania dotyczące transportu i autoryzacji, zobacz dokumentację protokołu magazynu stanu.
Ręczne SET wymienia rekord bez sprawdzania wersji oczekiwanego modelu.
Do tego demo użyj jednego autoryzowanego writera. W swojej aplikacji zachowaj zatwierdzoną historię i aktualizuj identyfikatory poza predyktorem na potrzeby odzyskiwania i wykrywania duplikatów. Aby cofnąć wzór, zatwierdź stare współczynniki jako nową wersję.
Informacje o grafie, który odczytuje przechowywany model i oblicza prognozy, można znaleźć w sekcji Odczytywanie współczynników z magazynu stanów.