

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Temas avanzados
<a name="model-monitor-advanced-topics"></a>

Las siguientes secciones contienen tareas más avanzadas que explican cómo personalizar la supervisión mediante scripts de preprocesamiento y posprocesamiento, cómo crear su propio contenedor y cómo utilizarlos CloudFormation para crear un programa de monitoreo.

**Topics**
+ [Programaciones de supervisión personalizadas](model-monitor-custom-monitoring-schedules.md)
+ [Cree un programa de monitoreo para un punto final en tiempo real con un recurso CloudFormation personalizado](model-monitor-cloudformation-monitoring-schedules.md)

# Programaciones de supervisión personalizadas
<a name="model-monitor-custom-monitoring-schedules"></a>

Además de utilizar los mecanismos de monitorización integrados, puede crear sus propios programas y procedimientos de monitorización personalizados mediante scripts de preprocesamiento y postprocesamiento o mediante el uso o la creación de su propio contenedor.

**Topics**
+ [Preprocesamiento y postprocesamiento](model-monitor-pre-and-post-processing.md)
+ [Support para sus propios contenedores con Amazon SageMaker Model Monitor](model-monitor-byoc-containers.md)

# Preprocesamiento y postprocesamiento
<a name="model-monitor-pre-and-post-processing"></a>

Puede usar scripts de Python personalizados de preprocesamiento y postprocesamiento para transformar la entrada en el monitor de modelos o extender el código después de una ejecución de supervisión correcta. Cargue estos scripts en Amazon S3 y haga referencia a ellos cuando cree su monitor de modelos.

En el ejemplo siguiente se muestra cómo personalizar los programas de supervisión con scripts de preprocesamiento y postprocesamiento. *user placeholder text*Sustitúyalo por tu propia información.

```
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**
+ [Archivo de comandos de preprocesamiento](#model-monitor-pre-processing-script)
+ [Muestreo personalizado](#model-monitor-pre-processing-custom-sampling)
+ [Archivo de comandos de postprocesamiento](#model-monitor-post-processing-script)

## Archivo de comandos de preprocesamiento
<a name="model-monitor-pre-processing-script"></a>

Utilice scripts de preprocesamiento cuando necesite transformar las entradas del monitor de modelos.

Por ejemplo, suponga que la salida de su modelo es una matriz `[1.0, 2.1]`. El contenedor Amazon SageMaker Model Monitor solo funciona con estructuras JSON tabulares o aplanadas, como. `{“prediction0”: 1.0, “prediction1” : 2.1}` Puede utilizar un script de preprocesamiento como el siguiente para transformar la matriz en la estructura JSON correcta.

```
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(",")) }
```

En otro ejemplo, suponga que el modelo tiene características opcionales y que utiliza `-1` para indicar que a la característica opcional le falta un valor. Si tiene un monitor de calidad de datos, es posible que desee eliminar el `-1` de la matriz de valores de entrada para que no se incluya en los cálculos de métricas del monitor. Puede utilizar un script como el siguiente para eliminar esos valores.

```
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(","))}
```

El script de preprocesamiento recibe un `inference_record` como única entrada. El siguiente fragmento de código muestra un ejemplo de `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"
}
```

El siguiente fragmento de código muestra la estructura de clases completa de un `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())
```

## Muestreo personalizado
<a name="model-monitor-pre-processing-custom-sampling"></a>

También puede aplicar una estrategia de muestreo personalizada en su script de preprocesamiento. Para ello, configure el contenedor propio y prediseñado del monitor de modelos para que haga caso omiso de un porcentaje de los registros de acuerdo con la frecuencia de muestreo especificada. En el siguiente ejemplo, el controlador muestrea el 10 % de los registros devolviendo el registro del 10 % de las llamadas al controlador y, en caso contrario, devuelve una lista vacía.

```
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(","))}
```

### Registro personalizado de script de preprocesamiento
<a name="model-monitor-pre-processing-custom-logging"></a>

 Si el script de preprocesamiento devuelve un error, compruebe los mensajes de excepción registrados para realizar la depuración. CloudWatch Puede acceder al registrador a CloudWatch través de la interfaz. `preprocess_handler` Puede registrar cualquier información que necesite de su script en. CloudWatch Esto puede resultar útil a la hora de depurar el script de preprocesamiento. El siguiente ejemplo muestra cómo puede utilizar la `preprocess_handler` interfaz para iniciar sesión en 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
```

## Archivo de comandos de postprocesamiento
<a name="model-monitor-post-processing-script"></a>

Utilice un script de postprocesamiento cuando desee extender el código después de una ejecución de supervisión correcta.

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

# Support para sus propios contenedores con Amazon SageMaker Model Monitor
<a name="model-monitor-byoc-containers"></a>

Amazon SageMaker Model Monitor proporciona un contenedor prediseñado con la capacidad de analizar los datos capturados desde puntos de enlace o trabajos de transformación por lotes para conjuntos de datos tabulares. Si desea traer su propio contenedor, el monitor de modelos proporciona puntos de extensión que puede utilizar.

Desde dentro del sistema, cuando se crea una `MonitoringSchedule`, el monitor de modelos inicia en última instancia los trabajos de procesamiento. Por lo tanto, el contenedor debe estar al tanto del contrato de trabajo de procesamiento documentado en el tema [Cómo crear su propio contenedor de procesamiento (escenario avanzado)](build-your-own-processing-container.md). Tenga en cuenta que el monitor de modelos inicia el trabajo de procesamiento en su nombre según la programación. Al invocar, el monitor de modelos configura variables de entorno adicionales para que su contenedor tenga suficiente contexto para procesar los datos para esa ejecución particular de la supervisión programada. Para obtener información adicional sobre las entradas de contenedores, consulte [Entradas de contrato de contenedor](model-monitor-byoc-contract-inputs.md).

En el contenedor, utilizando las variables de entorno/contexto anteriores, ahora puede analizar el conjunto de datos para el período actual en su código personalizado. Una vez completado este análisis, puede optar por emitir sus informes para que se carguen en buckets de S3. Los informes que genera el contenedor prediseñado se documentan en [Salidas del contrato de contenedor](model-monitor-byoc-contract-outputs.md). Si desea que la visualización de los informes funcione en SageMaker Studio, debe utilizar el mismo formato. También puede optar por emitir informes completamente personalizados.

También puede emitir CloudWatch métricas desde el contenedor siguiendo las instrucciones que se indican en[CloudWatch Métricas de Bring Your Own Containers](model-monitor-byoc-cloudwatch.md).

**Topics**
+ [Entradas de contrato de contenedor](model-monitor-byoc-contract-inputs.md)
+ [Salidas del contrato de contenedor](model-monitor-byoc-contract-outputs.md)
+ [CloudWatch Métricas de Bring Your Own Containers](model-monitor-byoc-cloudwatch.md)

# Entradas de contrato de contenedor
<a name="model-monitor-byoc-contract-inputs"></a>

La plataforma Amazon SageMaker Model Monitor invoca tu código de contenedor según un cronograma específico. Si elige escribir su propio código de contenedor, están disponibles las siguientes variables de entorno. En este contexto, puede analizar el conjunto de datos actual o evaluar las restricciones si decide emitir métricas, si procede.

Las variables de entorno disponibles son las mismas para los puntos de conexión en tiempo real y los trabajos de transformación por lotes, excepto para la variable `dataset_format`. Si utiliza un punto de conexión en tiempo real, la variable `dataset_format` admite las siguientes opciones:

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

Si utiliza un trabajo de transformación por lotes, `dataset_format` admite las siguientes opciones:

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

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

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

El siguiente ejemplo de código muestra el conjunto completo de variables de entorno disponibles para el código de contenedor (y utiliza el formato `dataset_format` para un punto de conexión en tiempo real).

```
"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 


| Nombre del parámetro | Description (Descripción) | 
| --- | --- | 
| dataset\$1format |  Para un trabajo iniciado a partir de un `MonitoringSchedule` respaldado por un `Endpoint`, esto es `sageMakerCaptureJson` con los índices de captura `endpointInput` o `endpointOutput`, o ambos. Para un trabajo de transformación por lotes, esto especifica el formato de los datos, ya sea CSV, JSON o Parquet.  | 
| dataset\$1source |  S usa un punto de conexión en tiempo real, la ruta local en la que están disponibles los datos correspondientes al período de supervisión, según lo especificado por `start_time` y `end_time`. En esta ruta, los datos están disponibles en ` /{endpoint-name}/{variant-name}/yyyy/mm/dd/hh`. A veces descargamos más de lo que especifican las horas de inicio y fin. Depende del código contenedor analizar los datos según sea necesario.  | 
| output\$1path |  La ruta local para escribir informes de salida y otros archivos. Debe especificar este parámetro en la solicitud `CreateMonitoringSchedule` como `MonitoringOutputConfig.MonitoringOutput[0].LocalPath`. Se carga en la ruta de `S3Uri` especificada en `MonitoringOutputConfig.MonitoringOutput[0].S3Uri`.  | 
| publish\$1cloudwatch\$1metrics |  Para un trabajo iniciado por `CreateMonitoringSchedule`, este parámetro se establece en `Enabled`. El contenedor puede elegir escribir el archivo de CloudWatch salida de Amazon en`[filepath]`.  | 
| sagemaker\$1endpoint\$1name |  Si utiliza un punto de conexión en tiempo real, el nombre del `Endpoint` para el que se lanzó este trabajo programado.  | 
| sagemaker\$1monitoring\$1schedule\$1name |  El nombre de la `MonitoringSchedule` que lanzó este trabajo.  | 
| \$1sagemaker\$1endpoint\$1datacapture\$1prefix\$1 |  Si utiliza un punto de conexión en tiempo real, el prefijo especificado en el parámetro `DataCaptureConfig` del `Endpoint`. El contenedor puede usarlo si necesita acceder directamente a más datos de los que ya ha descargado la SageMaker IA en la `dataset_source` ruta.  | 
| start\$1time, end\$1time |  Se ejecuta la ventana de tiempo para este análisis. Por ejemplo, para un trabajo programado para ejecutarse a las 05:00 UTC y un trabajo que se ejecuta el 20/02/2020, `start_time`: es 2020-02-19T06:00:00Z y `end_time`: es 2020-02-20T05:00:00Z  | 
| baseline\$1constraints: |  La ruta local del archivo de restricción de referencia especificado en ` BaselineConfig.ConstraintResource.S3Uri`. Esto solo está disponible si este parámetro se especificó en la solicitud `CreateMonitoringSchedule`.  | 
| baseline\$1statistics |  La ruta de acceso local al archivo de estadísticas de referencia especificado en `BaselineConfig.StatisticsResource.S3Uri`. Esto solo está disponible si este parámetro se especificó en la solicitud `CreateMonitoringSchedule`:   | 

# Salidas del contrato de contenedor
<a name="model-monitor-byoc-contract-outputs"></a>

El contenedor puede analizar los datos disponibles en la ruta `*dataset_source*` y escribir informes en la ruta en `*output_path*.` El código de contenedor puede escribir cualquier informe que se adapte a sus necesidades.

Si utiliza la estructura y el contrato siguientes, la SageMaker IA trata de forma especial algunos archivos de salida en la visualización y la API. Esto solo se aplica a los conjuntos de datos tabulares.

Archivos de salida para conjuntos de datos tabulares


| Nombre de archivo | Description (Descripción) | 
| --- | --- | 
| statistics.json |  Se espera que este archivo tenga estadísticas en columnas para cada característica en el conjunto de datos que se analiza. El esquema de este archivo está disponible en la siguiente sección.  | 
| constraints.json |  Se espera que este archivo tenga las restricciones en las características observadas. El esquema de este archivo está disponible en la siguiente sección.  | 
| constraints\$1violations.json |  Se espera que este archivo tenga la lista de infracciones encontradas en este conjunto de datos actual en comparación con el archivo de estadísticas de referencia y restricciones especificado en la ruta `baseline_constaints` y `baseline_statistics`.  | 

Además, si el `publish_cloudwatch_metrics` valor es código `"Enabled"` contenedor puede emitir CloudWatch métricas de Amazon en esta ubicación:`/opt/ml/output/metrics/cloudwatch`. El esquema de estos archivos se describe en las secciones siguientes.

**Topics**
+ [Esquema para estadísticas (archivo statistics.json)](model-monitor-byoc-statistics.md)
+ [Esquema para restricciones (archivo constraints.json)](model-monitor-byoc-constraints.md)

# Esquema para estadísticas (archivo statistics.json)
<a name="model-monitor-byoc-statistics"></a>

El esquema definido en el archivo `statistics.json` especifica los parámetros estadísticos que se van a calcular para la referencia y los datos que se capturan. También configura el bucket que debe utilizar [KLL](https://datasketches.apache.org/docs/KLL/KLLSketch.html), un boceto de cuantiles muy compacto con esquema de compactación diferido.

```
{
    "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
        }
    ]
}
```

**Notas**  
La SageMaker IA reconoce las métricas especificadas en cambios de visualización posteriores. El contenedor puede emitir más métricas en caso necesario.
El [boceto KLL](https://datasketches.apache.org/docs/KLL/KLLSketch.html) es el boceto reconocido. Los contenedores personalizados pueden escribir su propia representación, pero la SageMaker IA no los reconocerá en las visualizaciones.
Por defecto, la distribución se materializa en 10 buckets. No puede cambiar este valor.

# Esquema para restricciones (archivo constraints.json)
<a name="model-monitor-byoc-constraints"></a>

Se utiliza un archivo constraints.json para expresar las restricciones que debe cumplir un conjunto de datos. Los contenedores de Amazon SageMaker Model Monitor pueden usar el archivo constraints.json para evaluar los conjuntos de datos. Los contenedores prediseñados proporcionan la capacidad de generar automáticamente el archivo constraints.json para un conjunto de datos de referencia. Si utiliza su propio contenedor, puede proporcionarle habilidades similares o puede crear el archivo constraints.json de otra manera. Aquí está el esquema para el archivo de restricciones que utiliza el contenedor prediseñado. Al utilizar sus propios contenedores puede adoptar el mismo formato o mejorarlo según sea necesario.

```
{
    "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"
        }
    }
}
```

El objeto `monitoring_config` contiene opciones para el trabajo de supervisión de la característica. En la tabla siguiente se describe cada opción.

Supervisión de restricciones

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

# CloudWatch Métricas de Bring Your Own Containers
<a name="model-monitor-byoc-cloudwatch"></a>

Si el `publish_cloudwatch_metrics` valor está `Enabled` en el `Environment` mapa del `/opt/ml/processing/processingjobconfig.json` archivo, el código del contenedor emite CloudWatch las métricas de Amazon en esta ubicación:`/opt/ml/output/metrics/cloudwatch`. 

El esquema de este archivo se basa estrechamente en la CloudWatch `PutMetrics` API. El espacio de nombres no se especifica aquí. De forma predeterminada, es lo siguiente:
+ `For real-time endpoints: /aws/sagemaker/Endpoint/data-metrics`
+ `For batch transform jobs: /aws/sagemaker/ModelMonitoring/data-metrics`

Sin embargo, puede especificar dimensiones. Se recomienda agregar las siguientes dimensiones como mínimo:
+ `Endpoint` y `MonitoringSchedule` para puntos de conexión en tiempo real
+ `MonitoringSchedule` para trabajos de transformación por lotes 

En los siguientes fragmentos de código JSON, se muestra cómo configurar las dimensiones.

Para un punto de conexión en tiempo real, consulte el siguiente fragmento de código JSON, que incluye las dimensiones `Endpoint` y `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
}
```

Para un trabajo de transformación por lotes, consulte el siguiente fragmento de JSON, que incluye la dimensión `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
}
```

# Cree un programa de monitoreo para un punto final en tiempo real con un recurso CloudFormation personalizado
<a name="model-monitor-cloudformation-monitoring-schedules"></a>

Si utiliza un punto final en tiempo real, puede utilizar un recurso CloudFormation personalizado para crear un cronograma de monitoreo. El recurso personalizado está en Python. Para implementarlo, consulte la [implementación de Python Lambda](https://docs.aws.amazon.com/lambda/latest/dg/lambda-python-how-to-create-deployment-package.html).

## Recurso personalizado
<a name="model-monitor-cloudformation-custom-resource"></a>

Comience por añadir un recurso personalizado a su CloudFormation plantilla. Esto apunta a una función de AWS Lambda que creará en el siguiente paso. 

Este recurso le permite personalizar los parámetros de la programación de supervisión. Puede añadir o eliminar más parámetros modificando el CloudFormation recurso y la función Lambda en el siguiente recurso de ejemplo.

```
{
    "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"
            }
        }
    }
}
```

## Código de recurso personalizado de Lambda
<a name="model-monitor-cloudformation-lambda-custom-resource-code"></a>

Este recurso CloudFormation personalizado utiliza la AWS biblioteca [Custom Resource Helper](https://github.com/aws-cloudformation/custom-resource-helper), que puede instalar con pip mediante. `pip install crhelper` 

Esta función Lambda se invoca CloudFormation durante la creación y eliminación de la pila. Esta función Lambda es responsable de crear y eliminar la programación de monitorización y utilizar los parámetros definidos en el recurso personalizado descrito en la sección anterior.

```
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
```