

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

# Argomenti avanzati
<a name="model-monitor-advanced-topics"></a>

Le sezioni seguenti contengono attività più avanzate che spiegano come personalizzare il monitoraggio utilizzando script di preelaborazione e post-elaborazione, come creare un contenitore personalizzato e come utilizzarlo per CloudFormation creare una pianificazione di monitoraggio.

**Topics**
+ [Pianificazioni di monitoraggio personalizzate](model-monitor-custom-monitoring-schedules.md)
+ [Crea una pianificazione di monitoraggio per un endpoint in tempo reale con una risorsa CloudFormation personalizzata](model-monitor-cloudformation-monitoring-schedules.md)

# Pianificazioni di monitoraggio personalizzate
<a name="model-monitor-custom-monitoring-schedules"></a>

Oltre a utilizzare i meccanismi di monitoraggio integrati, è possibile creare pianificazioni e procedure personalizzate di monitoraggio utilizzando script di pre-elaborazione e post-elaborazione, o utilizzando o costruendo il proprio container.

**Topics**
+ [Pre-elaborazione e post-elaborazione](model-monitor-pre-and-post-processing.md)
+ [Support per i tuoi contenitori con Amazon SageMaker Model Monitor](model-monitor-byoc-containers.md)

# Pre-elaborazione e post-elaborazione
<a name="model-monitor-pre-and-post-processing"></a>

È possibile utilizzare script Python personalizzati di pre-elaborazione e post-elaborazione per trasformare l'input al monitoraggio del modello o estendere il codice dopo un'esecuzione di monitoraggio riuscita. Carica questi script su Amazon S3 e utilizzali come riferimento durante la creazione del monitoraggio di modello.

L'esempio seguente mostra come personalizzare le pianificazioni di monitoraggio con script di pre-elaborazione e post-elaborazione. Sostituiscilo *user placeholder text* con le tue informazioni.

```
import boto3, os
from sagemaker import get_execution_role, Session
from sagemaker.model_monitor import CronExpressionGenerator, DefaultModelMonitor

# Upload pre and postprocessor scripts
session = Session()
bucket = boto3.Session().resource("s3").Bucket(session.default_bucket())
prefix = "demo-sagemaker-model-monitor"
pre_processor_script = bucket.Object(os.path.join(prefix, "preprocessor.py")).upload_file("preprocessor.py")
post_processor_script = bucket.Object(os.path.join(prefix, "postprocessor.py")).upload_file("postprocessor.py")

# Get execution role
role = get_execution_role() # can be an empty string

# Instance type
instance_type = "instance-type"
# instance_type = "ml.m5.xlarge" # Example

# Create a monitoring schedule with pre and postprocessing
my_default_monitor = DefaultModelMonitor(
    role=role,
    instance_count=1,
    instance_type=instance_type,
    volume_size_in_gb=20,
    max_runtime_in_seconds=3600,
)

s3_report_path = "s3://{}/{}".format(bucket, "reports")
monitor_schedule_name = "monitor-schedule-name"
endpoint_name = "endpoint-name"
my_default_monitor.create_monitoring_schedule(
    post_analytics_processor_script=post_processor_script,
    record_preprocessor_script=pre_processor_script,
    monitor_schedule_name=monitor_schedule_name,
    # use endpoint_input for real-time endpoint
    endpoint_input=endpoint_name,
    # or use batch_transform_input for batch transform jobs
    # batch_transform_input=batch_transform_name,
    output_s3_uri=s3_report_path,
    statistics=my_default_monitor.baseline_statistics(),
    constraints=my_default_monitor.suggested_constraints(),
    schedule_cron_expression=CronExpressionGenerator.hourly(),
    enable_cloudwatch_metrics=True,
)
```

**Topics**
+ [Script di pre-elaborazione](#model-monitor-pre-processing-script)
+ [Campionamento personalizzato](#model-monitor-pre-processing-custom-sampling)
+ [Script di post-elaborazione](#model-monitor-post-processing-script)

## Script di pre-elaborazione
<a name="model-monitor-pre-processing-script"></a>

Utilizza gli script di pre-elaborazione quando devi trasformare gli input che arrivano al monitoraggio del modello.

Per esempio, supponiamo che l'output del tuo modello sia una matrice `[1.0, 2.1]`. Il contenitore Amazon SageMaker Model Monitor funziona solo con strutture JSON tabulari o appiattite, come. `{“prediction0”: 1.0, “prediction1” : 2.1}` È possibile utilizzare uno script di pre-elaborazione come riportato di seguito per trasformare la matrice nella struttura JSON corretta.

```
def preprocess_handler(inference_record):
    input_data = inference_record.endpoint_input.data
    output_data = inference_record.endpoint_output.data.rstrip("\n")
    data = output_data + "," + input_data
    return { str(i).zfill(20) : d for i, d in enumerate(data.split(",")) }
```

In un altro caso, supponiamo che il modello abbia funzionalità opzionali e che si utilizzi `-1` per indicare che la funzionalità opzionale ha un valore mancante. Se disponi di un sistema di monitoraggio per la qualità dei dati, è consigliabile rimuovere `-1` dalla matrice dei valori di input in modo che non venga incluso nei calcoli dei parametri di monitoraggio. Per rimuovere tali valori puoi utilizzare uno script come quello riportato di seguito.

```
def preprocess_handler(inference_record):
    input_data = inference_record.endpoint_input.data
    return {i : None if x == -1 else x for i, x in enumerate(input_data.split(","))}
```

Lo script di pre-elaborazione riceve `inference_record` come unico input. Il seguente frammento di codice mostra un esempio di `inference_record`.

```
{
  "captureData": {
    "endpointInput": {
      "observedContentType": "text/csv",
      "mode": "INPUT",
      "data": "132,25,113.2,96,269.9,107,,0,0,0,0,0,0,1,0,1,0,0,1",
      "encoding": "CSV"
    },
    "endpointOutput": {
      "observedContentType": "text/csv; charset=utf-8",
      "mode": "OUTPUT",
      "data": "0.01076381653547287",
      "encoding": "CSV"
    }
  },
  "eventMetadata": {
    "eventId": "feca1ab1-8025-47e3-8f6a-99e3fdd7b8d9",
    "inferenceTime": "2019-11-20T23:33:12Z"
  },
  "eventVersion": "0"
}
```

Il seguente frammento di codice mostra l'intera struttura di classe di `inference_record`.

```
KEY_EVENT_METADATA = "eventMetadata"
KEY_EVENT_METADATA_EVENT_ID = "eventId"
KEY_EVENT_METADATA_EVENT_TIME = "inferenceTime"
KEY_EVENT_METADATA_CUSTOM_ATTR = "customAttributes"

KEY_EVENTDATA_ENCODING = "encoding"
KEY_EVENTDATA_DATA = "data"

KEY_GROUND_TRUTH_DATA = "groundTruthData"

KEY_EVENTDATA = "captureData"
KEY_EVENTDATA_ENDPOINT_INPUT = "endpointInput"
KEY_EVENTDATA_ENDPOINT_OUTPUT = "endpointOutput"

KEY_EVENTDATA_BATCH_OUTPUT = "batchTransformOutput"
KEY_EVENTDATA_OBSERVED_CONTENT_TYPE = "observedContentType"
KEY_EVENTDATA_MODE = "mode"

KEY_EVENT_VERSION = "eventVersion"

class EventConfig:
    def __init__(self, endpoint, variant, start_time, end_time):
        self.endpoint = endpoint
        self.variant = variant
        self.start_time = start_time
        self.end_time = end_time


class EventMetadata:
    def __init__(self, event_metadata_dict):
        self.event_id = event_metadata_dict.get(KEY_EVENT_METADATA_EVENT_ID, None)
        self.event_time = event_metadata_dict.get(KEY_EVENT_METADATA_EVENT_TIME, None)
        self.custom_attribute = event_metadata_dict.get(KEY_EVENT_METADATA_CUSTOM_ATTR, None)


class EventData:
    def __init__(self, data_dict):
        self.encoding = data_dict.get(KEY_EVENTDATA_ENCODING, None)
        self.data = data_dict.get(KEY_EVENTDATA_DATA, None)
        self.observedContentType = data_dict.get(KEY_EVENTDATA_OBSERVED_CONTENT_TYPE, None)
        self.mode = data_dict.get(KEY_EVENTDATA_MODE, None)

    def as_dict(self):
        ret = {
            KEY_EVENTDATA_ENCODING: self.encoding,
            KEY_EVENTDATA_DATA: self.data,
            KEY_EVENTDATA_OBSERVED_CONTENT_TYPE: self.observedContentType,
        }
        return ret


class CapturedData:
    def __init__(self, event_dict):
        self.event_metadata = None
        self.endpoint_input = None
        self.endpoint_output = None
        self.batch_transform_output = None
        self.ground_truth = None
        self.event_version = None
        self.event_dict = event_dict
        self._event_dict_postprocessed = False
        
        if KEY_EVENT_METADATA in event_dict:
            self.event_metadata = EventMetadata(event_dict[KEY_EVENT_METADATA])
        if KEY_EVENTDATA in event_dict:
            if KEY_EVENTDATA_ENDPOINT_INPUT in event_dict[KEY_EVENTDATA]:
                self.endpoint_input = EventData(event_dict[KEY_EVENTDATA][KEY_EVENTDATA_ENDPOINT_INPUT])
            if KEY_EVENTDATA_ENDPOINT_OUTPUT in event_dict[KEY_EVENTDATA]:
                self.endpoint_output = EventData(event_dict[KEY_EVENTDATA][KEY_EVENTDATA_ENDPOINT_OUTPUT])
            if KEY_EVENTDATA_BATCH_OUTPUT in event_dict[KEY_EVENTDATA]:
                self.batch_transform_output = EventData(event_dict[KEY_EVENTDATA][KEY_EVENTDATA_BATCH_OUTPUT])

        if KEY_GROUND_TRUTH_DATA in event_dict:
            self.ground_truth = EventData(event_dict[KEY_GROUND_TRUTH_DATA])
        if KEY_EVENT_VERSION in event_dict:
            self.event_version = event_dict[KEY_EVENT_VERSION]

    def as_dict(self):
        if self._event_dict_postprocessed is True:
            return self.event_dict
        if KEY_EVENTDATA in self.event_dict:
            if KEY_EVENTDATA_ENDPOINT_INPUT in self.event_dict[KEY_EVENTDATA]:
                self.event_dict[KEY_EVENTDATA][KEY_EVENTDATA_ENDPOINT_INPUT] = self.endpoint_input.as_dict()
            if KEY_EVENTDATA_ENDPOINT_OUTPUT in self.event_dict[KEY_EVENTDATA]:
                self.event_dict[KEY_EVENTDATA][
                    KEY_EVENTDATA_ENDPOINT_OUTPUT
                ] = self.endpoint_output.as_dict()
            if KEY_EVENTDATA_BATCH_OUTPUT in self.event_dict[KEY_EVENTDATA]:
                self.event_dict[KEY_EVENTDATA][KEY_EVENTDATA_BATCH_OUTPUT] = self.batch_transform_output.as_dict()
        
        self._event_dict_postprocessed = True
        return self.event_dict

    def __str__(self):
        return str(self.as_dict())
```

## Campionamento personalizzato
<a name="model-monitor-pre-processing-custom-sampling"></a>

Puoi anche applicare una strategia di campionamento personalizzata nello script di pre-elaborazione. A tale scopo, configura il container proprietario e predefinito di Model Monitor in modo che ignori una percentuale dei record in base alla frequenza di campionamento specificata. Nell'esempio seguente, il gestore campiona il 10% dei record restituendo il record nel 10% delle chiamate al gestore e in caso contrario un elenco vuoto.

```
import random

def preprocess_handler(inference_record):
    # we set up a sampling rate of 0.1
    if random.random() > 0.1:
        # return an empty list
        return []
    input_data = inference_record.endpoint_input.data
    return {i : None if x == -1 else x for i, x in enumerate(input_data.split(","))}
```

### Registrazione personalizzata per lo script di pre-elaborazione
<a name="model-monitor-pre-processing-custom-logging"></a>

 Se lo script di preelaborazione restituisce un errore, controlla i messaggi di eccezione registrati in debug. CloudWatch È possibile accedere al logger tramite l'interfaccia. CloudWatch `preprocess_handler` Puoi registrare tutte le informazioni di cui hai bisogno dal tuo script a CloudWatch. Potrebbe essere utile per eseguire il debug dello script di pre-elaborazione. L'esempio seguente mostra come utilizzare l'`preprocess_handler`interfaccia per accedere a CloudWatch 

```
def preprocess_handler(inference_record, logger):
    logger.info(f"I'm a processing record: {inference_record}")
    logger.debug(f"I'm debugging a processing record: {inference_record}")
    logger.warning(f"I'm processing record with missing value: {inference_record}")
    logger.error(f"I'm a processing record with bad value: {inference_record}")
    return inference_record
```

## Script di post-elaborazione
<a name="model-monitor-post-processing-script"></a>

Utilizza uno script di post-elaborazione quando desideri estendere il codice dopo un'esecuzione di monitoraggio riuscita.

```
def postprocess_handler():
    print("Hello from post-proc script!")
```

# Support per i tuoi contenitori con Amazon SageMaker Model Monitor
<a name="model-monitor-byoc-containers"></a>

Amazon SageMaker Model Monitor offre un contenitore predefinito in grado di analizzare i dati acquisiti dagli endpoint o dai processi di trasformazione in batch per set di dati tabulari. Se si desidera utilizzare il proprio container, Model Monitor fornisce punti di estensione che è possibile sfruttare.

Dietro le quinte, quando crei un `MonitoringSchedule`, Model Monitor avvia il processo di elaborazione. Quindi il container deve essere a conoscenza del contratto del processo di elaborazione documentato nell'argomento [Come creare un container di elaborazione personalizzato (scenario avanzato)](build-your-own-processing-container.md). Tieni presente che Model Monitor avvia il processo di elaborazione per tuo conto in base alla pianificazione. Durante il richiamo, Model Monitor imposta ulteriori variabili di ambiente per l'utente in modo che il container abbia un contesto sufficiente per elaborare i dati per quella particolare esecuzione del monitoraggio pianificato. Per ulteriori informazioni sugli input del container, consulta [Input contratto container](model-monitor-byoc-contract-inputs.md).

Nel container, utilizzando le variabili/contesto di ambiente di cui sopra, è ora possibile analizzare il set di dati per il periodo corrente nel codice personalizzato. Una volta completata questa analisi, puoi scegliere di emettere i tuoi report e caricarli in un bucket S3. I report generati dal container predefinito sono documentati in [Output contratto container](model-monitor-byoc-contract-outputs.md). Se desideri che la visualizzazione dei report funzioni in SageMaker Studio, devi seguire lo stesso formato. È inoltre possibile scegliere di emettere report completamente personalizzati.

Puoi anche emettere CloudWatch metriche dal contenitore seguendo le istruzioni in. [CloudWatch Metriche per Bring Your Own Containers](model-monitor-byoc-cloudwatch.md)

**Topics**
+ [Input contratto container](model-monitor-byoc-contract-inputs.md)
+ [Output contratto container](model-monitor-byoc-contract-outputs.md)
+ [CloudWatch Metriche per Bring Your Own Containers](model-monitor-byoc-cloudwatch.md)

# Input contratto container
<a name="model-monitor-byoc-contract-inputs"></a>

La piattaforma Amazon SageMaker Model Monitor richiama il codice del contenitore in base a una pianificazione specificata. Se scegli di scrivere il tuo codice container, sono disponibili le seguenti variabili di ambiente. In questo contesto, è possibile analizzare il set di dati corrente o valutare i vincoli se si sceglie di emettere parametri, se applicabili.

Le variabili di ambiente disponibili sono le stesse per gli endpoint in tempo reale e i processi di trasformazione di batch, ad eccezione della variabile `dataset_format`. Se si utilizza un endpoint in tempo reale, la variabile `dataset_format` supporta le seguenti opzioni:

```
{\"sagemakerCaptureJson\": {\"captureIndexNames\": [\"endpointInput\",\"endpointOutput\"]}}
```

Se si utilizza un processo di trasformazione di batch, `dataset_format` supporta le seguenti opzioni:

```
{\"csv\": {\"header\": [\"true\",\"false\"]}}
```

```
{\"json\": {\"line\": [\"true\",\"false\"]}}
```

```
{\"parquet\": {}}
```

Il seguente esempio di codice mostra il set completo di variabili di ambiente disponibili per il codice del container (e utilizza il formato `dataset_format` per endpoint in tempo reale).

```
"Environment": {
 "dataset_format": "{\"sagemakerCaptureJson\": {\"captureIndexNames\": [\"endpointInput\",\"endpointOutput\"]}}",
 "dataset_source": "/opt/ml/processing/endpointdata",
 "end_time": "2019-12-01T16: 20: 00Z",
 "output_path": "/opt/ml/processing/resultdata",
 "publish_cloudwatch_metrics": "Disabled",
 "sagemaker_endpoint_name": "endpoint-name",
 "sagemaker_monitoring_schedule_name": "schedule-name",
 "start_time": "2019-12-01T15: 20: 00Z"
}
```

Parameters 


| Nome parametro | Description | 
| --- | --- | 
| dataset\$1format |  Per un processo avviato da un `MonitoringSchedule` sostenuto da un `Endpoint`, è `sageMakerCaptureJson` con gli indici di acquisizione `endpointInput` oppure `endpointOutput`, o entrambi. Per un processo di trasformazione di batch, specifica il formato dei dati, che sia CSV, JSON o Parquet.  | 
| dataset\$1source |  Se stai utilizzando un endpoint in tempo reale, il percorso locale in cui sono disponibili i dati corrispondenti al periodo di monitoraggio, come specificato da `start_time` e `end_time`. In questo percorso, i dati sono disponibili in ` /{endpoint-name}/{variant-name}/yyyy/mm/dd/hh`. A volte scarichiamo più di quanto specificato dagli orari di inizio e fine. Il codice container ha il compito di analizzare i dati come richiesto.  | 
| output\$1path |  Il percorso locale per scrivere report di output e altri file. È necessario specificare questo parametro nella richiesta `CreateMonitoringSchedule` come `MonitoringOutputConfig.MonitoringOutput[0].LocalPath`. Viene caricato nel percorso `S3Uri` specificato in `MonitoringOutputConfig.MonitoringOutput[0].S3Uri`.  | 
| publish\$1cloudwatch\$1metrics |  Per un processo avviato da `CreateMonitoringSchedule`, questo parametro è impostato su `Enabled`. Il contenitore può scegliere di scrivere il file CloudWatch di output di Amazon in`[filepath]`.  | 
| sagemaker\$1endpoint\$1name |  Se si utilizza un endpoint in tempo reale, il nome del `Endpoint` per cui è stato avviato il processo pianificato.  | 
| sagemaker\$1monitoring\$1schedule\$1name |  Il nome del `MonitoringSchedule` che ha avviato questo processo.  | 
| \$1sagemaker\$1endpoint\$1datacapture\$1prefix\$1 |  Se si utilizza un endpoint in tempo reale, il prefisso specificato nel parametro `DataCaptureConfig` del `Endpoint`. Il contenitore può utilizzarlo se ha bisogno di accedere direttamente a più dati di quelli già scaricati dall' SageMaker IA nel `dataset_source` percorso.  | 
| start\$1time, end\$1time |  La finestra temporale per l'esecuzione di questa analisi. Ad esempio, per un'attività la cui esecuzione è pianificata alle 05:00 UTC e per un'attività eseguita il 20/02/2020, `start_time` è 2020-02-19T 06:00:00 Z e `end_time` è 2020-02-20T 05:00:00 Z  | 
| baseline\$1constraints: |  Il percorso locale del file di vincolo della linea di base specificato in ` BaselineConfig.ConstraintResource.S3Uri`. Questo parametro è disponibile solo se è stato specificato nella richiesta `CreateMonitoringSchedule`.  | 
| baseline\$1statistics |  Il percorso locale del file di statistiche della linea di base specificato in `BaselineConfig.StatisticsResource.S3Uri`. Questo parametro è disponibile solo se è stato specificato nella richiesta `CreateMonitoringSchedule`.   | 

# Output contratto container
<a name="model-monitor-byoc-contract-outputs"></a>

Il container può analizzare i dati disponibili nel percorso `*dataset_source*` e scrivere report sul percorso in `*output_path*.`. Il codice container può scrivere tutti i report che soddisfano le tue esigenze.

Se utilizzi la struttura e il contratto seguenti, alcuni file di output vengono trattati in modo speciale dall' SageMaker intelligenza artificiale nella visualizzazione e nell'API. È valido solo per set di dati tabulari.

File di output per set di dati tabulari


| Nome del file | Description | 
| --- | --- | 
| statistics.json |  Si prevede che questo file abbia statistiche a colonne per ogni funzionalità del set di dati che viene analizzato. Lo schema di questo file è disponibile nella sezione successiva.  | 
| constraints.json |  Si prevede che questo file abbia vincoli sulle funzionalità osservate. Lo schema di questo file è disponibile nella sezione successiva.  | 
| constraints\$1violations.json |  Questo file deve contenere un elenco di violazioni rilevate in questo set di dati corrente rispetto al file di statistiche e vincoli della linea di base specificato nei percorsi `baseline_constaints` e `baseline_statistics`.  | 

Inoltre, se il `publish_cloudwatch_metrics` valore è il codice del `"Enabled"` contenitore, può emettere i CloudWatch parametri Amazon in questa posizione:. `/opt/ml/output/metrics/cloudwatch` Lo schema per questi file è descritto nelle sezioni seguenti.

**Topics**
+ [Schema per le statistiche (file statistics.json)](model-monitor-byoc-statistics.md)
+ [Schema per vincoli (file constraints.json)](model-monitor-byoc-constraints.md)

# Schema per le statistiche (file statistics.json)
<a name="model-monitor-byoc-statistics"></a>

Lo schema definito nel file `statistics.json` specifica i parametri statistici da calcolare per la linea di base e i dati acquisiti. Configura anche il bucket che deve essere utilizzato da [KLL](https://datasketches.apache.org/docs/KLL/KLLSketch.html), uno sketch di quantili molto compatto con schema di compattazione lento.

```
{
    "version": 0,
    # dataset level stats
    "dataset": {
        "item_count": number
    },
    # feature level stats
    "features": [
        {
            "name": "feature-name",
            "inferred_type": "Fractional" | "Integral",
            "numerical_statistics": {
                "common": {
                    "num_present": number,
                    "num_missing": number
                },
                "mean": number,
                "sum": number,
                "std_dev": number,
                "min": number,
                "max": number,
                "distribution": {
                    "kll": {
                        "buckets": [
                            {
                                "lower_bound": number,
                                "upper_bound": number,
                                "count": number
                            }
                        ],
                        "sketch": {
                            "parameters": {
                                "c": number,
                                "k": number
                            },
                            "data": [
                                [
                                    num,
                                    num,
                                    num,
                                    num
                                ],
                                [
                                    num,
                                    num
                                ][
                                    num,
                                    num
                                ]
                            ]
                        }#sketch
                    }#KLL
                }#distribution
            }#num_stats
        },
        {
            "name": "feature-name",
            "inferred_type": "String",
            "string_statistics": {
                "common": {
                    "num_present": number,
                    "num_missing": number
                },
                "distinct_count": number,
                "distribution": {
                    "categorical": {
                         "buckets": [
                                {
                                    "value": "string",
                                    "count": number
                                }
                          ]
                     }
                }
            },
            #provision for custom stats
        }
    ]
}
```

**Note**  
Le metriche specificate vengono riconosciute dall' SageMaker IA nelle successive modifiche di visualizzazione. Il container può emettere più parametri se necessario.
Lo [sketch KLL](https://datasketches.apache.org/docs/KLL/KLLSketch.html) è lo sketch riconosciuto. I contenitori personalizzati possono scrivere la propria rappresentazione, ma questa non verrà riconosciuta dall' SageMaker IA nelle visualizzazioni.
Per impostazione predefinita, la distribuzione è materializzata in 10 bucket. Non puoi modificare questo valore.

# Schema per vincoli (file constraints.json)
<a name="model-monitor-byoc-constraints"></a>

Il file constraints.json viene usato per esprimere i vincoli che un set di dati deve soddisfare. I contenitori Amazon SageMaker Model Monitor possono utilizzare il file constraints.json per valutare i set di dati. I container esistenti offrono la possibilità di generare automaticamente il file constraints.json per un set di dati della baseline. Se porti il tuo container, puoi dotarlo di abilità simili o puoi creare il file constraints.json in altro modo. Ecco lo schema per il file di vincolo utilizzato dal container esistente. Portare i propri container consente di adottare lo stesso formato o migliorarlo in base alle necessità.

```
{
    "version": 0,
    "features":
    [
        {
            "name": "string",
            "inferred_type": "Integral" | "Fractional" | 
                    | "String" | "Unknown",
            "completeness": number,
            "num_constraints":
            {
                "is_non_negative": boolean
            },
            "string_constraints":
            {
                "domains":
                [
                    "list of",
                    "observed values",
                    "for small cardinality"
                ]
            },
            "monitoringConfigOverrides":
            {}
        }
    ],
    "monitoring_config":
    {
        "evaluate_constraints": "Enabled",
        "emit_metrics": "Enabled",
        "datatype_check_threshold": 0.1,
        "domain_content_threshold": 0.1,
        "distribution_constraints":
        {
            "perform_comparison": "Enabled",
            "comparison_threshold": 0.1,
            "comparison_method": "Simple"||"Robust",
            "categorical_comparison_threshold": 0.1,
            "categorical_drift_method": "LInfinity"||"ChiSquared"
        }
    }
}
```

L'oggetto `monitoring_config` contiene opzioni per il monitoraggio del processo relativo alla funzionalità. Nella tabella seguente è descritta ciascuna opzione.

Vincoli di monitoraggio

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/it_it/sagemaker/latest/dg/model-monitor-byoc-constraints.html)

# CloudWatch Metriche per Bring Your Own Containers
<a name="model-monitor-byoc-cloudwatch"></a>

Se il `publish_cloudwatch_metrics` valore è `Enabled` nella `Environment` mappa del `/opt/ml/processing/processingjobconfig.json` file, il codice del contenitore emette i CloudWatch parametri Amazon in questa posizione:. `/opt/ml/output/metrics/cloudwatch` 

Lo schema di questo file è strettamente basato sull' CloudWatch`PutMetrics`API. Lo spazio dei nomi non è specificato qui. Il valore predefinito è riportato di seguito:
+ `For real-time endpoints: /aws/sagemaker/Endpoint/data-metrics`
+ `For batch transform jobs: /aws/sagemaker/ModelMonitoring/data-metrics`

Tuttavia, è possibile specificare le dimensioni. Si consiglia di aggiungere almeno le seguenti dimensioni:
+ `Endpoint` e `MonitoringSchedule` per gli endpoint in tempo reale
+ `MonitoringSchedule` per processi di trasformazione di batch

I seguenti snippet di codice JSON mostrano come impostare le dimensioni.

Per un endpoint in tempo reale, consulta il seguente snippet di codice JSON che include le dimensioni `Endpoint` e `MonitoringSchedule`:

```
{ 
    "MetricName": "", # Required
    "Timestamp": "2019-11-26T03:00:00Z", # Required
    "Dimensions" : [{"Name":"Endpoint","Value":"endpoint_0"},{"Name":"MonitoringSchedule","Value":"schedule_0"}]
    "Value": Float,
    # Either the Value or the StatisticValues field can be populated and not both.
    "StatisticValues": {
        "SampleCount": Float,
        "Sum": Float,
        "Minimum": Float,
        "Maximum": Float
    },
    "Unit": "Count", # Optional
}
```

Per un processo di trasformazione di batch, consulta il seguente snippet di codice JSON che include la dimensione `MonitoringSchedule`:

```
{ 
    "MetricName": "", # Required
    "Timestamp": "2019-11-26T03:00:00Z", # Required
    "Dimensions" : [{"Name":"MonitoringSchedule","Value":"schedule_0"}]
    "Value": Float,
    # Either the Value or the StatisticValues field can be populated and not both.
    "StatisticValues": {
        "SampleCount": Float,
        "Sum": Float,
        "Minimum": Float,
        "Maximum": Float
    },
    "Unit": "Count", # Optional
}
```

# Crea una pianificazione di monitoraggio per un endpoint in tempo reale con una risorsa CloudFormation personalizzata
<a name="model-monitor-cloudformation-monitoring-schedules"></a>

Se utilizzi un endpoint in tempo reale, puoi utilizzare una risorsa CloudFormation personalizzata per creare una pianificazione di monitoraggio. La risorsa personalizzata è in Python. Per distribuirla, consulta vedere la sezione relativa alla [distribuzione di Python Lambda](https://docs.aws.amazon.com/lambda/latest/dg/lambda-python-how-to-create-deployment-package.html).

## Risorsa personalizzata
<a name="model-monitor-cloudformation-custom-resource"></a>

Inizia aggiungendo una risorsa personalizzata al tuo CloudFormation modello. Questo punterà a una funzione AWS Lambda che sarà creata nella fase successiva. 

Questa risorsa consente di personalizzare i parametri per la pianificazione del monitoraggio. È possibile aggiungere o rimuovere altri parametri modificando la CloudFormation risorsa e la funzione Lambda nella risorsa di esempio seguente.

```
{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Resources": {
        "MonitoringSchedule": {
            "Type": "Custom::MonitoringSchedule",
            "Version": "1.0",
            "Properties": {
                "ServiceToken": "arn:aws:lambda:us-west-2:111111111111:function:lambda-name",
                "ScheduleName": "YourScheduleName",
                "EndpointName": "YourEndpointName",
                "BaselineConstraintsUri": "s3://your-baseline-constraints/constraints.json",
                "BaselineStatisticsUri": "s3://your-baseline-stats/statistics.json",
                "PostAnalyticsProcessorSourceUri": "s3://your-post-processor/postprocessor.py",
                "RecordPreprocessorSourceUri": "s3://your-preprocessor/preprocessor.py",
                "InputLocalPath": "/opt/ml/processing/endpointdata",
                "OutputLocalPath": "/opt/ml/processing/localpath",
                "OutputS3URI": "s3://your-output-uri",
                "ImageURI": "111111111111.dkr.ecr.us-west-2.amazonaws.com/your-image",
                "ScheduleExpression": "cron(0 * ? * * *)",
                "PassRoleArn": "arn:aws:iam::111111111111:role/AmazonSageMaker-ExecutionRole"
            }
        }
    }
}
```

## Codice risorsa personalizzato Lambda
<a name="model-monitor-cloudformation-lambda-custom-resource-code"></a>

Questa risorsa CloudFormation personalizzata utilizza la AWS libreria [Custom Resource Helper](https://github.com/aws-cloudformation/custom-resource-helper), che puoi installare con pip utilizzando. `pip install crhelper` 

Questa funzione Lambda viene richiamata da CloudFormation durante la creazione e l'eliminazione dello stack. Questa funzione Lambda è responsabile della creazione e dell'eliminazione della pianificazione del monitoraggio, nonché dell'utilizzo dei parametri definiti nella risorsa personalizzata descritta nella sezione precedente.

```
import boto3
import botocore
import logging

from crhelper import CfnResource
from botocore.exceptions import ClientError


logger = logging.getLogger(__name__)
sm = boto3.client('sagemaker')

# cfnhelper makes it easier to implement a CloudFormation custom resource
helper = CfnResource()

# CFN Handlers

def handler(event, context):
    helper(event, context)


@helper.create
def create_handler(event, context):
    """
    Called when CloudFormation custom resource sends the create event
    """
    create_monitoring_schedule(event)


@helper.delete
def delete_handler(event, context):
    """
    Called when CloudFormation custom resource sends the delete event
    """
    schedule_name = get_schedule_name(event)
    delete_monitoring_schedule(schedule_name)


@helper.poll_create
def poll_create(event, context):
    """
    Return true if the resource has been created and false otherwise so
    CloudFormation polls again.
    """
    schedule_name = get_schedule_name(event)
    logger.info('Polling for creation of schedule: %s', schedule_name)
    return is_schedule_ready(schedule_name)

@helper.update
def noop():
    """
    Not currently implemented but crhelper will throw an error if it isn't added
    """
    pass

# Helper Functions

def get_schedule_name(event):
    return event['ResourceProperties']['ScheduleName']

def create_monitoring_schedule(event):
    schedule_name = get_schedule_name(event)
    monitoring_schedule_config = create_monitoring_schedule_config(event)

    logger.info('Creating monitoring schedule with name: %s', schedule_name)

    sm.create_monitoring_schedule(
        MonitoringScheduleName=schedule_name,
        MonitoringScheduleConfig=monitoring_schedule_config)

def is_schedule_ready(schedule_name):
    is_ready = False

    schedule = sm.describe_monitoring_schedule(MonitoringScheduleName=schedule_name)
    status = schedule['MonitoringScheduleStatus']

    if status == 'Scheduled':
        logger.info('Monitoring schedule (%s) is ready', schedule_name)
        is_ready = True
    elif status == 'Pending':
        logger.info('Monitoring schedule (%s) still creating, waiting and polling again...', schedule_name)
    else:
        raise Exception('Monitoring schedule ({}) has unexpected status: {}'.format(schedule_name, status))

    return is_ready

def create_monitoring_schedule_config(event):
    props = event['ResourceProperties']

    return {
        "ScheduleConfig": {
            "ScheduleExpression": props["ScheduleExpression"],
        },
        "MonitoringJobDefinition": {
            "BaselineConfig": {
                "ConstraintsResource": {
                    "S3Uri": props['BaselineConstraintsUri'],
                },
                "StatisticsResource": {
                    "S3Uri": props['BaselineStatisticsUri'],
                }
            },
            "MonitoringInputs": [
                {
                    "EndpointInput": {
                        "EndpointName": props["EndpointName"],
                        "LocalPath": props["InputLocalPath"],
                    }
                }
            ],
            "MonitoringOutputConfig": {
                "MonitoringOutputs": [
                    {
                        "S3Output": {
                            "S3Uri": props["OutputS3URI"],
                            "LocalPath": props["OutputLocalPath"],
                        }
                    }
                ],
            },
            "MonitoringResources": {
                "ClusterConfig": {
                    "InstanceCount": 1,
                    "InstanceType": "ml.t3.medium",
                    "VolumeSizeInGB": 50,
                }
            },
            "MonitoringAppSpecification": {
                "ImageUri": props["ImageURI"],
                "RecordPreprocessorSourceUri": props['PostAnalyticsProcessorSourceUri'],
                "PostAnalyticsProcessorSourceUri": props['PostAnalyticsProcessorSourceUri'],
            },
            "StoppingCondition": {
                "MaxRuntimeInSeconds": 300
            },
            "RoleArn": props["PassRoleArn"],
        }
    }


def delete_monitoring_schedule(schedule_name):
    logger.info('Deleting schedule: %s', schedule_name)
    try:
        sm.delete_monitoring_schedule(MonitoringScheduleName=schedule_name)
    except ClientError as e:
        if e.response['Error']['Code'] == 'ResourceNotFound':
            logger.info('Resource not found, nothing to delete')
        else:
            logger.error('Unexpected error while trying to delete monitoring schedule')
            raise e
```