Skip to content

Commit bdf84f9

Browse files
committed
changes to how to docs
1 parent d2add31 commit bdf84f9

File tree

2 files changed

+158
-65
lines changed

2 files changed

+158
-65
lines changed

articles/machine-learning/how-to-collect-production-data.md

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ To begin, add custom logging code to your scoring script (`score.py`). For custo
8989
> [!NOTE]
9090
> Currently, the `collect()` API logs only pandas DataFrames. If the data is not in a DataFrame when passed to `collect()`, it won't get logged to storage and an error will be reported.
9191

92-
The following code is an example of a full scoring script (`score.py`) that uses the custom logging Python SDK. In this example, a third `Collector` called `inputs_outputs_collector` logs a joined DataFrame of the `model_inputs` and the `model_outputs`. This joined DataFrame enables more monitoring signals such as feature attribution drift. If you're not interested in these monitoring signals, you can remove this `Collector`.
92+
The following code is an example of a full scoring script (`score.py`) that uses the custom logging Python SDK.
9393

9494
```python
9595
import pandas as pd
@@ -132,6 +132,86 @@ def predict(input_df):
132132
return output_df
133133
```
134134

135+
#### Update your scoring script to log custom unique IDs
136+
137+
In addition to logging pandas DataFrames directly within your scoring script, you can log data with unique IDs of your choice. These IDs can come from your application, an external system, or can be generated by you. If you do not provide a custom ID, as detailed in this section, the Data collector will autogenerate a unique `correlationid` to help you correlate your model's inputs and outputs later. If you supply a custom ID, the `correlationid` field in the logged data will contain the value of your supplied custom ID.
138+
139+
1. In addition to the steps above, import the `azureml.ai.monitoring.context` package by adding the following line to your scoring script:
140+
141+
```python
142+
from azureml.ai.monitoring.context import BasicCorrelationContext
143+
```
144+
145+
1. In your scoring script, instantiate a `BasicCorrelationContext` object and pass in the `id` you wish to log for that row. We recommend that this `id` be a unique ID from your system, so you can uniquely identify each logged row from your Blob storage. Pass this object into your `collect()` API call as a parameter:
146+
147+
```python
148+
# create a context with a custom unique id
149+
artificial_context = BasicCorrelationContext(id='test')
150+
151+
# collect inputs data, store correlation_context
152+
context = inputs_collector.collect(input_df, artificial_context)
153+
```
154+
155+
1. Ensure that you pass into the context into your `outputs_collector` so that your model inputs and outputs have the same unique ID logged with them, and they can be easily correlated later:
156+
157+
```python
158+
# collect outputs data, pass in context so inputs and outputs data can be correlated later
159+
outputs_collector.collect(output_df, context)
160+
```
161+
162+
A comprehensive example is detailed below:
163+
164+
```python
165+
import pandas as pd
166+
import json
167+
from azureml.ai.monitoring import Collector
168+
from azureml.ai.monitoring.context import BasicCorrelationContext
169+
170+
def init():
171+
global inputs_collector, outputs_collector, inputs_outputs_collector
172+
173+
# instantiate collectors with appropriate names, make sure align with deployment spec
174+
inputs_collector = Collector(name='model_inputs')
175+
outputs_collector = Collector(name='model_outputs')
176+
177+
def run(data):
178+
# json data: { "data" : { "col1": [1,2,3], "col2": [2,3,4] } }
179+
pdf_data = preprocess(json.loads(data))
180+
181+
# tabular data: { "col1": [1,2,3], "col2": [2,3,4] }
182+
input_df = pd.DataFrame(pdf_data)
183+
184+
# create a context with a custom unique id
185+
artificial_context = BasicCorrelationContext(id='test')
186+
187+
# collect inputs data, store correlation_context
188+
context = inputs_collector.collect(input_df, artificial_context)
189+
190+
# perform scoring with pandas Dataframe, return value is also pandas Dataframe
191+
output_df = predict(input_df)
192+
193+
# collect outputs data, pass in context so inputs and outputs data can be correlated later
194+
outputs_collector.collect(output_df, context)
195+
196+
return output_df.to_dict()
197+
198+
def preprocess(json_data):
199+
# preprocess the payload to ensure it can be converted to pandas DataFrame
200+
return json_data["data"]
201+
202+
def predict(input_df):
203+
# process input and return with outputs
204+
...
205+
206+
return output_df
207+
```
208+
209+
#### Collect data for model performance monitoring
210+
211+
If you are interested in using your collected data for model performance monitoring, it is important that each logged row has a unique `correlationid` which can be used to correlate the data with ground truth data, when it becomes available. The data collector will autogenerate a unique `correlationid` for each logged row, and include it in the `correlationid` field in the JSON object. Please see [store collected data in a blob](#store-collected-data-in-a-blob) for comprehensive details on the JSON schema.
212+
213+
If you are interested in using your own unique ID to log with your production data, it is recommended that you log it as a separate column in your `pandas DataFrame`. The reason for this is because [the data collector will batch requests](#data-collector-batching) which fall within close proximity of one another. If you need the `correlationid` to be readily available downstream for integration with ground truth data, having it logged as a separate column is recommended.
214+
135215
### Update your dependencies
136216

137217
Before you can create your deployment with the updated scoring script, you need to create your environment with the base image `mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04` and the appropriate conda dependencies. Thereafter, you can build the environment using the specification in the following YAML.
@@ -301,6 +381,28 @@ With collected binary data, we show the raw file directly, with `instance_id` as
301381
}
302382
```
303383

384+
#### Data collector batching
385+
386+
The data collector will batch requests together into the same JSON object if they are sent within a short duration of each other. For example, if you run a script to send sample data to your endpoint, and the deployment has data collection enabled, some of the requests may get batched together, depending on the interval of time between them. If you are using data collection to use with [Azure Machine Learning model monitoring](#concept-model-monitoring.md) this behavior is handled appropriately and each request is handled as independent by the model monitoring service. However, if you expect each logged row of data have its own unique `correlationid`, you can include the `correlationid` as a column in the `pandas DataFrame` you are logging with the data collector. Information on how to do this can be found in [data collection for model performance monitoring][#collect-data-for-model-performance-monitoring].
387+
388+
Here is an example of two logged requests being batched together:
389+
390+
```json
391+
{"specversion":"1.0",
392+
"id":"720b8867-54a2-4876-80eb-1fd6a8975770",
393+
"source":"/subscriptions/79a1ba0c-35bb-436b-bff2-3074d5ff1f89/resourceGroups/rg-bozhlinmomoignite/providers/Microsoft.MachineLearningServices/workspaces/momo-demo-ws/onlineEndpoints/credit-default-mdc-testing-4/deployments/main2",
394+
"type":"azureml.inference.model_inputs",
395+
"datacontenttype":"application/json",
396+
"time":"2024-03-05T18:16:25Z",
397+
"data":[{"LIMIT_BAL":502970,"AGE":54,"BILL_AMT1":308068,"BILL_AMT2":381402,"BILL_AMT3":442625,"BILL_AMT4":320399,"BILL_AMT5":322616,"BILL_AMT6":397534,"PAY_AMT1":17987,"PAY_AMT2":78764,"PAY_AMT3":26067,"PAY_AMT4":24102,"PAY_AMT5":-1155,"PAY_AMT6":2154,"SEX":2,"EDUCATION":2,"MARRIAGE":2,"PAY_0":0,"PAY_2":0,"PAY_3":0,"PAY_4":0,"PAY_5":0,"PAY_6":0},{"LIMIT_BAL":293458,"AGE":35,"BILL_AMT1":74131,"BILL_AMT2":-71014,"BILL_AMT3":59284,"BILL_AMT4":98926,"BILL_AMT5":110,"BILL_AMT6":1033,"PAY_AMT1":-3926,"PAY_AMT2":-12729,"PAY_AMT3":17405,"PAY_AMT4":25110,"PAY_AMT5":7051,"PAY_AMT6":1623,"SEX":1,"EDUCATION":3,"MARRIAGE":2,"PAY_0":-2,"PAY_2":-2,"PAY_3":-2,"PAY_4":-2,"PAY_5":-1,"PAY_6":-1}],
398+
"contentrange":"bytes 0-6794/6795",
399+
"correlationid":"test",
400+
"xrequestid":"test",
401+
"modelversion":"default",
402+
"collectdatatype":"pandas.core.frame.DataFrame",
403+
"agent":"azureml-ai-monitoring/0.1.0b4"}
404+
```
405+
304406
#### View the data in the studio UI
305407

306408
To view the collected data in Blob Storage from the studio UI:

articles/machine-learning/how-to-monitor-model-performance.md

Lines changed: 55 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -451,14 +451,22 @@ You must satisfy the following requirements for you to configure your model perf
451451

452452
> [!NOTE]
453453
>
454-
> For Azure Machine Learning model performance monitoring, we recommend that you log your unique ID in its own column, using the [Azure Machine Learning data collector](how-to-collect-production-data.md). This practice will ensure that each collected row is guaranteed to have a unique ID.
454+
> For Azure Machine Learning model performance monitoring, we recommend that you log your unique ID in its own column, using the [Azure Machine Learning data collector](how-to-collect-production-data.md).
455455
456456
* Have ground truth data (actuals) with a unique ID for each row. The unique ID for a given row should match the unique ID for the model outputs for that particular inference request. This unique ID is used to join your ground truth dataset with the model outputs.
457457

458458
Without having ground truth data, you can't perform model performance monitoring. Since ground truth data is encountered at the application level, it's your responsibility to collect it as it becomes available. You should also maintain a data asset in Azure Machine Learning that contains this ground truth data.
459459

460460
* (Optional) Have a pre-joined tabular dataset with model outputs and ground truth data already joined together.
461461

462+
### Monitoring model performance requirements when using data collector
463+
464+
If you use the [Azure Machine Learning data collector](concept-data-collection.md) to collect production inference data and do not supply your own unique ID for each row as a separate column, a `correlationid` will be autogenerated for you and included in the logged JSON object. However, the data collector will [batch rows](how-to-collect-production-data.md#data-collector-batching) which are sent within close proximity to each other. Batched rows will fall within the same JSON object and will thus have the same `correlationid`.
465+
466+
In order to differentiate between the rows in the same JSON object, Azure Machine Learning model performance monitoring uses indexing to determine the first, second, third, and so on, row in the JSON object. For example, if three rows are batched together, and the `correlationid` is `test`, row 1 will have an id of `test_0`, row 2 will have an id of `test_1`, and row 3 will have an id `test_2`. To ensure that your ground truth dataset contains unique IDs which match to the collected production inference model outputs, ensure that you index each `correlationid` appropriately. If your logged JSON object only has one row, then the `correlationid` would be `correlationid_0`.
467+
468+
To avoid using this indexing, we recommend that you log your unique ID in its own column within the `pandas DataFrame`, using the [Azure Machine Learning data collector](how-to-collect-production-data.md). Then, in your model monitoring configuration, you specify the name of this column to join your model output data with your ground data. As long as the IDs for each row in both datasets are the same, Azure Machine Learning model monitoring can perform model performance monitoring.
469+
462470
### Example workflow for monitoring model performance
463471

464472
To understand the concepts associated with model performance monitoring, consider this example workflow. Suppose you're deploying a model to predict whether credit card transactions are fraudulent or not, you can follow these steps to monitor the model's performance:
@@ -532,25 +540,17 @@ create_monitor:
532540
Once you've satisfied the [prerequisites for model performance monitoring](#more-prerequisites-for-model-performance-monitoring), you can set up model monitoring with the following Python code:
533541
534542
```python
535-
from azure.identity import InteractiveBrowserCredential
543+
from azure.identity import DefaultAzureCredential
536544
from azure.ai.ml import Input, MLClient
537545
from azure.ai.ml.constants import (
538-
MonitorFeatureType,
539-
MonitorMetricName,
540-
MonitorDatasetContext
546+
MonitorDatasetContext,
541547
)
542548
from azure.ai.ml.entities import (
543549
AlertNotification,
544-
DataDriftSignal,
545-
DataQualitySignal,
546-
DataDriftMetricThreshold,
547-
DataQualityMetricThreshold,
548-
NumericalDriftMetrics,
549-
CategoricalDriftMetrics,
550-
DataQualityMetricsNumerical,
551-
DataQualityMetricsCategorical,
552-
MonitorFeatureFilter,
553-
MonitorInputData,
550+
BaselineDataRange,
551+
ModelPerformanceMetricThreshold,
552+
ModelPerformanceSignal,
553+
ModelPerformanceClassificationThresholds,
554554
MonitoringTarget,
555555
MonitorDefinition,
556556
MonitorSchedule,
@@ -563,79 +563,70 @@ from azure.ai.ml.entities import (
563563

564564
# get a handle to the workspace
565565
ml_client = MLClient(
566-
InteractiveBrowserCredential(),
567-
subscription_id,
568-
resource_group,
569-
workspace
566+
DefaultAzureCredential(),
567+
subscription_id="79a1ba0c-35bb-436b-bff2-3074d5ff1f89",
568+
resource_group_name="rg-bozhlinmomoignite",
569+
workspace_name="momo-demo-ws",
570570
)
571571

572+
# create your compute
572573
spark_compute = ServerlessSparkCompute(
573574
instance_type="standard_e4s_v3",
574-
runtime_version="3.2"
575+
runtime_version="3.3"
575576
)
576577

577-
#define target dataset (production dataset)
578+
# reference your azureml endpoint and deployment
579+
monitoring_target = MonitoringTarget(
580+
ml_task="classification",
581+
)
582+
583+
# MDC-generated production data with data column names
578584
production_data = ProductionData(
579585
input_data=Input(
580586
type="uri_folder",
581-
path="azureml:my_model_production_data:1"
587+
path="azureml:credit-default-main-model_outputs:1"
582588
),
583-
data_context=MonitorDatasetContext.MODEL_INPUTS,
584-
pre_processing_component="azureml:production_data_preprocessing:1"
589+
data_column_names={
590+
"target_column": "DEFAULT_NEXT_MONTH",
591+
"join_column": "correlationid"
592+
},
593+
data_window=BaselineDataRange(
594+
lookback_window_offset="P0D",
595+
lookback_window_size="P10D",
596+
)
585597
)
586598

587-
588-
# training data to be used as baseline dataset
589-
reference_data_training = ReferenceData(
599+
# ground truth reference data
600+
reference_data_ground_truth = ReferenceData(
590601
input_data=Input(
591602
type="mltable",
592-
path="azureml:my_model_training_data:1"
603+
path="azureml:credit-ground-truth:1"
593604
),
594-
data_context=MonitorDatasetContext.TRAINING
605+
data_column_names={
606+
"target_column": "ground_truth",
607+
"join_column": "correlationid"
608+
},
609+
data_context=MonitorDatasetContext.GROUND_TRUTH_DATA,
595610
)
596611

597-
# create an advanced data drift signal
598-
features = MonitorFeatureFilter(top_n_feature_importance=20)
599-
metric_thresholds = DataDriftMetricThreshold(
600-
numerical=NumericalDriftMetrics(
601-
jensen_shannon_distance=0.01
612+
# create the model performance signal
613+
metric_thresholds = ModelPerformanceMetricThreshold(
614+
classification=ModelPerformanceClassificationThresholds(
615+
accuracy=0.50,
616+
precision=0.50,
617+
recall=0.50
602618
),
603-
categorical=CategoricalDriftMetrics(
604-
pearsons_chi_squared_test=0.02
605-
)
606619
)
607620

608-
advanced_data_drift = DataDriftSignal(
621+
model_performance = ModelPerformanceSignal(
609622
production_data=production_data,
610-
reference_data=reference_data_training,
611-
features=features,
623+
reference_data=reference_data_ground_truth,
612624
metric_thresholds=metric_thresholds
613625
)
614626

615-
616-
# create an advanced data quality signal
617-
features = ['feature_A', 'feature_B', 'feature_C']
618-
metric_thresholds = DataQualityMetricThreshold(
619-
numerical=DataQualityMetricsNumerical(
620-
null_value_rate=0.01
621-
),
622-
categorical=DataQualityMetricsCategorical(
623-
out_of_bounds_rate=0.02
624-
)
625-
)
626-
627-
advanced_data_quality = DataQualitySignal(
628-
production_data=production_data,
629-
reference_data=reference_data_training,
630-
features=features,
631-
metric_thresholds=metric_thresholds,
632-
alert_enabled="False"
633-
)
634-
635627
# put all monitoring signals in a dictionary
636628
monitoring_signals = {
637-
'data_drift_advanced': advanced_data_drift,
638-
'data_quality_advanced': advanced_data_quality
629+
'model_performance':model_performance,
639630
}
640631

641632
# create alert notification object
@@ -646,6 +637,7 @@ alert_notification = AlertNotification(
646637
# Finally monitor definition
647638
monitor_definition = MonitorDefinition(
648639
compute=spark_compute,
640+
monitoring_target=monitoring_target,
649641
monitoring_signals=monitoring_signals,
650642
alert_notification=alert_notification
651643
)
@@ -657,14 +649,13 @@ recurrence_trigger = RecurrenceTrigger(
657649
)
658650

659651
model_monitor = MonitorSchedule(
660-
name="fraud_detection_model_monitoring_advanced",
652+
name="credit_default_model_performance",
661653
trigger=recurrence_trigger,
662654
create_monitor=monitor_definition
663655
)
664656

665657
poller = ml_client.schedules.begin_create_or_update(model_monitor)
666658
created_monitor = poller.result()
667-
668659
```
669660

670661
# [Studio](#tab/azure-studio)

0 commit comments

Comments
 (0)