

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Tópicos avançados
<a name="model-monitor-advanced-topics"></a>

As seções a seguir contêm tarefas mais avançadas que explicam como personalizar o monitoramento usando scripts de pré-processamento e pós-processamento, como criar seu próprio contêiner e como usá-lo CloudFormation para criar um cronograma de monitoramento.

**Topics**
+ [Programações de monitoramento personalizadas](model-monitor-custom-monitoring-schedules.md)
+ [Crie um cronograma de monitoramento para um endpoint em tempo real com um recurso CloudFormation personalizado](model-monitor-cloudformation-monitoring-schedules.md)

# Programações de monitoramento personalizadas
<a name="model-monitor-custom-monitoring-schedules"></a>

Além de usar os mecanismos de monitoramento integrados, é possível criar seus próprios agendamentos e procedimentos de monitoramento personalizados usando scripts de pré-processamento e pós-processamento ou usando ou criando seu próprio contêiner.

**Topics**
+ [Pré-processamento e pós-processamento](model-monitor-pre-and-post-processing.md)
+ [Support para seus próprios contêineres com o Amazon SageMaker Model Monitor](model-monitor-byoc-containers.md)

# Pré-processamento e pós-processamento
<a name="model-monitor-pre-and-post-processing"></a>

Você pode usar scripts Python personalizados de pré-processamento e pós-processamento para transformar a entrada do seu monitor de modelo ou estender o código após uma execução bem-sucedida do monitoramento. Faça o upload desses scripts para o Amazon S3 e faça referência a eles ao criar seu monitor de modelo.

O exemplo a seguir mostra como personalizar as programações de monitoramento com scripts de pré-processamento e pós-processamento. *user placeholder text*Substitua por suas próprias informações.

```
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 de pré-processamento](#model-monitor-pre-processing-script)
+ [Amostragem personalizada](#model-monitor-pre-processing-custom-sampling)
+ [Script de pós-processamento](#model-monitor-post-processing-script)

## Script de pré-processamento
<a name="model-monitor-pre-processing-script"></a>

Use scripts de pré-processamento quando precisar transformar as entradas do seu monitor do modelo.

Por exemplo, suponha que a saída do seu modelo seja uma matriz `[1.0, 2.1]`. O contêiner Amazon SageMaker Model Monitor só funciona com estruturas JSON tabulares ou achatadas, como. `{“prediction0”: 1.0, “prediction1” : 2.1}` Você pode usar um script de pré-processamento como o seguinte para transformar a matriz na estrutura JSON correta:

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

Em outro exemplo, suponha que seu modelo tenha atributos opcionais e você use `-1` para indicar que o atributo opcional tem um valor ausente. Se você tiver um monitor de qualidade de dados, talvez queira remover o `-1` da matriz de valores de entrada para que não seja incluído nos cálculos métricos do monitor. Você pode usar um script como o seguinte para remover esses 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(","))}
```

Seu script de pré-processamento recebe um `inference_record` como única entrada. O trecho de código a seguir mostra um exemplo de um `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"
}
```

O trecho de código a seguir mostra a estrutura de classe completa de um `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())
```

## Amostragem personalizada
<a name="model-monitor-pre-processing-custom-sampling"></a>

Você também pode aplicar uma estratégia de amostragem personalizada em seu script de pré-processamento. Para fazer isso, configure o contêiner pré-criado original do Model Monitor para ignorar uma porcentagem dos registros de acordo com a taxa de amostragem especificada. No exemplo a seguir, o manipulador coleta amostras de 10% dos registros retornando o registro em 10% das chamadas do manipulador e, caso contrário, uma lista vazia.

```
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 para script de pré-processamento
<a name="model-monitor-pre-processing-custom-logging"></a>

 Se o script de pré-processamento retornar um erro, verifique as mensagens de exceção registradas CloudWatch para depuração. Você pode acessar o logger por CloudWatch meio da `preprocess_handler` interface. Você pode registrar todas as informações necessárias do seu script em CloudWatch. Isso pode ser útil ao depurar seu script de pré-processamento. O exemplo a seguir mostra como você pode usar a `preprocess_handler` interface para fazer login em 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 de pós-processamento
<a name="model-monitor-post-processing-script"></a>

Use um script de pós-processamento quando quiser estender o código após uma execução de monitoramento bem-sucedida.

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

# Support para seus próprios contêineres com o Amazon SageMaker Model Monitor
<a name="model-monitor-byoc-containers"></a>

O Amazon SageMaker Model Monitor fornece um contêiner pré-construído com a capacidade de analisar os dados capturados de endpoints ou trabalhos de transformação em lote para conjuntos de dados tabulares. Se quiser trazer seu próprio contêiner, o Model Monitor fornecerá pontos de extensão que você pode aproveitar.

Dentro do sistema, ao criar um `MonitoringSchedule`, o Model Monitor acaba iniciando trabalhos de processamento. Por isso, o contêiner precisa estar ciente do contrato de trabalho de processamento documentado no tópico [Como criar um contêiner de processamento (cenário avançado)](build-your-own-processing-container.md). Observe que o Model Monitor inicia o trabalho de processamento em seu nome de acordo com a programação. Ao invocar, o Model Monitor configura variáveis de ambiente adicionais para você, de modo que o contêiner tenha contexto suficiente para processar os dados para essa execução específica da programação agendada. Para obter informações adicionais sobre entradas de contêiner, consulte o [Entradas do contrato de contêiner](model-monitor-byoc-contract-inputs.md).

No contêiner, usando as variáveis ou o contexto de ambiente acima, agora é possível analisar o conjunto de dados para o período atual no código personalizado. Uma vez concluída essa análise, é possível optar por emitir os relatórios que serão carregados no bucket do S3. Os relatórios gerados pelo contêiner pré-criado são documentados em [Saídas de contrato do contêiner](model-monitor-byoc-contract-outputs.md). Se você quiser que a visualização dos relatórios funcione no SageMaker Studio, siga o mesmo formato. Também é possível optar por emitir relatórios completamente personalizados.

Você também emite CloudWatch métricas do contêiner seguindo as instruções em[CloudWatch Métricas para trazer seus próprios contêineres](model-monitor-byoc-cloudwatch.md).

**Topics**
+ [Entradas do contrato de contêiner](model-monitor-byoc-contract-inputs.md)
+ [Saídas de contrato do contêiner](model-monitor-byoc-contract-outputs.md)
+ [CloudWatch Métricas para trazer seus próprios contêineres](model-monitor-byoc-cloudwatch.md)

# Entradas do contrato de contêiner
<a name="model-monitor-byoc-contract-inputs"></a>

A plataforma Amazon SageMaker Model Monitor invoca seu código de contêiner de acordo com um cronograma especificado. Se você optar por escrever seu próprio código de contêiner, as variáveis de ambiente a seguir estarão disponíveis. Nesse contexto, será possível analisar o conjunto de dados atual ou avaliar as restrições se escolher e emitir métricas, se aplicável.

As variáveis de ambiente disponíveis são as mesmas para endpoints em tempo real e trabalhos de transformação de lotes, exceto pela variável `dataset_format`. Se você estiver usando um endpoint em tempo real, a variável `dataset_format` oferece apoio às seguintes opções:

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

Se você estiver usando um trabalho de transformação de lotes, o `dataset_format` é compatível com as seguintes opções:

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

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

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

O exemplo de código a seguir mostra o conjunto completo de variáveis de ambiente disponíveis para seu código de contêiner (e usa o formato `dataset_format` para um endpoint em tempo 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"
}
```

Parâmetros 


| Nome do parâmetro | Description | 
| --- | --- | 
| dataset\$1format |  Para um trabalho iniciado a partir de um `MonitoringSchedule` com base em um `Endpoint`, isso é `sageMakerCaptureJson` com os índices de captura `endpointInput`, `endpointOutput` ou ambos. Para um trabalho de transformação de lotes, isso especifica o formato dos dados, seja CSV, JSON ou Parquet.  | 
| dataset\$1source |  Se você estiver usando um endpoint em tempo real, o caminho local no qual os dados correspondentes ao período de monitoramento, conforme especificado por `start_time` e `end_time`, estão disponíveis. Nesse caminho, os dados estão disponíveis em ` /{endpoint-name}/{variant-name}/yyyy/mm/dd/hh`. Às vezes, fazemos download mais do que o especificado pelos horários de início e de término. Cabe ao código do contêiner analisar os dados conforme necessário.  | 
| output\$1path |  O caminho local para gravar relatórios de saída e outros arquivos. Especifique esse parâmetro na solicitação `CreateMonitoringSchedule` como `MonitoringOutputConfig.MonitoringOutput[0].LocalPath`. É feito upload dele no caminho `S3Uri` especificado em `MonitoringOutputConfig.MonitoringOutput[0].S3Uri`.  | 
| publish\$1cloudwatch\$1metrics |  Para um trabalho executado por `CreateMonitoringSchedule`, esse parâmetro é definido como `Enabled`. O contêiner pode escolher gravar o arquivo CloudWatch de saída da Amazon em`[filepath]`.  | 
| sagemaker\$1endpoint\$1name |  Se você estiver usando um endpoint em tempo real, o nome do `Endpoint` para o qual esse trabalho programado foi iniciado.  | 
| sagemaker\$1monitoring\$1schedule\$1name |  O nome do `MonitoringSchedule` que executou esse trabalho.  | 
| \$1sagemaker\$1endpoint\$1datacapture\$1prefix\$1 |  Se você estiver usando um endpoint em tempo real, o prefixo especificado no parâmetro `DataCaptureConfig` do `Endpoint`. O contêiner pode usar isso se precisar acessar diretamente mais dados do que os já baixados pela SageMaker IA no `dataset_source` caminho.  | 
| start\$1time, end\$1time |  A janela de tempo para a execução dessa análise. Por exemplo, para um trabalho programado para ser executado às 05:00 UTC e um trabalho executado em 20/02/2020, `start_time` é 2020-02-19T06:00:00Z e `end_time` é 2020-02-20T05:00:00Z  | 
| baseline\$1constraints: |  O caminho local do arquivo de restrição de linha de base especificado em ` BaselineConfig.ConstraintResource.S3Uri`. Isso só estará disponível se esse parâmetro tiver sido especificado na solicitação `CreateMonitoringSchedule`.  | 
| baseline\$1statistics |  O caminho local para o arquivo de estatísticas da linha de base especificado em `BaselineConfig.StatisticsResource.S3Uri`. Isso só estará disponível se esse parâmetro tiver sido especificado na solicitação `CreateMonitoringSchedule`.   | 

# Saídas de contrato do contêiner
<a name="model-monitor-byoc-contract-outputs"></a>

O contêiner pode analisar os dados disponíveis no caminho `*dataset_source*` e gravar relatórios para o caminho em `*output_path*.`. O código do contêiner pode gravar qualquer relatório que atenda às suas necessidades.

Se você usar a estrutura e o contrato a seguir, determinados arquivos de saída serão tratados especialmente pela SageMaker IA na visualização e na API. Isso se aplica somente a conjuntos de dados tabulares.

Arquivos de saída para conjuntos de dados tabulares


| Nome do arquivo | Description | 
| --- | --- | 
| statistics.json |  Espera-se que este arquivo tenha estatísticas colunares para cada atributo no conjunto de dados que é analisado. O esquema para este arquivo está disponível na próxima seção.  | 
| constraints.json |  Espera-se que este arquivo tenha as restrições sobre os atributos observados. O esquema para este arquivo está disponível na próxima seção.  | 
| constraints\$1violations.json |  Espera-se que este arquivo tenha a lista de violações encontradas nesse conjunto atual de dados em comparação com o arquivo de estatísticas e restrições de linha de base especificado no caminho `baseline_constaints` e `baseline_statistics`.  | 

Além disso, se o `publish_cloudwatch_metrics` valor for código de `"Enabled"` contêiner pode emitir CloudWatch métricas da Amazon neste local:`/opt/ml/output/metrics/cloudwatch`. O esquema para esses arquivos está descrito nas seções a seguir.

**Topics**
+ [Esquema para estatísticas (arquivo statistics.json)](model-monitor-byoc-statistics.md)
+ [Esquema para restrições (arquivo constraints.json)](model-monitor-byoc-constraints.md)

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

O esquema definido no arquivo `statistics.json` especifica os parâmetros estatísticos a serem calculados para a linha de base e para os dados capturados. Ele também configura o bucket que deve ser usado pelo [KLL](https://datasketches.apache.org/docs/KLL/KLLSketch.html), um esboço de quantis muito compacto com esquema de compactação 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
        }
    ]
}
```

**Observações**  
As métricas especificadas são reconhecidas pela SageMaker IA em alterações posteriores na visualização. O contêiner pode emitir mais métricas, se necessário.
O [esboço KLL](https://datasketches.apache.org/docs/KLL/KLLSketch.html) é o esboço reconhecido. Os contêineres personalizados podem escrever sua própria representação, mas ela não será reconhecida pela SageMaker IA nas visualizações.
Por padrão, a distribuição é materializada em 10 buckets. Não é possível alterar esse valor.

# Esquema para restrições (arquivo constraints.json)
<a name="model-monitor-byoc-constraints"></a>

Um arquivo constraints.json é usado para expressar as restrições que um conjunto de dados deve satisfazer. Os contêineres SageMaker do Amazon Model Monitor podem usar o arquivo constraints.json para avaliar os conjuntos de dados. Os contêineres pré-criados fornecem a capacidade de gerar o arquivo constraints.json automaticamente para um conjunto de dados da linha de base. Se você trouxer seu próprio contêiner, será possível fornecê-lo com habilidades semelhantes ou você poderá criar o arquivo constraints.json de alguma outra maneira. Veja a seguir o esquema para o arquivo de restrição que o contêiner pré-criado usa. Ao trazer seus próprios contêineres, é possível adotar o mesmo formato ou melhorá-lo conforme necessário.

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

O objeto `monitoring_config` contém opções para o trabalho de monitoramento do atributo. A tabela a seguir descreve cada opção.

Monitoramento de restrições

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

# CloudWatch Métricas para trazer seus próprios contêineres
<a name="model-monitor-byoc-cloudwatch"></a>

Se o `publish_cloudwatch_metrics` valor estiver `Enabled` no `Environment` mapa do `/opt/ml/processing/processingjobconfig.json` arquivo, o código do contêiner emite CloudWatch métricas da Amazon neste local:`/opt/ml/output/metrics/cloudwatch`. 

O esquema desse arquivo é estreitamente baseado na CloudWatch `PutMetrics` API. O namespace não é especificado aqui. O padrão é o seguinte:
+ `For real-time endpoints: /aws/sagemaker/Endpoint/data-metrics`
+ `For batch transform jobs: /aws/sagemaker/ModelMonitoring/data-metrics`

No entanto, é possível especificar dimensões. Recomendamos que você adicione as dimensões a seguir no mínimo:
+ `Endpoint` e `MonitoringSchedule` para endpoints em tempo real
+ `MonitoringSchedule` para trabalhos de transformação de lotes

Os trechos JSON a seguir mostram como definir suas dimensões.

Para um endpoint em tempo real, consulte o seguinte trecho JSON, que inclui as dimensões `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
}
```

Para um trabalho de transformação de lotes, consulte o seguinte trecho JSON, que inclui a dimensão `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
}
```

# Crie um cronograma de monitoramento para um endpoint em tempo real com um recurso CloudFormation personalizado
<a name="model-monitor-cloudformation-monitoring-schedules"></a>

Se você estiver usando um endpoint em tempo real, poderá usar um recurso CloudFormation personalizado para criar um cronograma de monitoramento. O recurso personalizado está em Python. Para implantá-lo, consulte a [Implantação do 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>

Comece adicionando um recurso personalizado ao seu CloudFormation modelo. Isso apontará para uma função do AWS Lambda que você criará em seguida. 

Esse recurso permite que você personalize os parâmetros do cronograma de monitoramento. Você pode adicionar ou remover mais parâmetros modificando o CloudFormation recurso e a função Lambda no recurso de exemplo a seguir.

```
{
    "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 do Lambda
<a name="model-monitor-cloudformation-lambda-custom-resource-code"></a>

Esse recurso CloudFormation personalizado usa a AWS biblioteca [Custom Resource Helper](https://github.com/aws-cloudformation/custom-resource-helper), que você pode instalar com o pip usando. `pip install crhelper` 

Essa função Lambda é invocada CloudFormation durante a criação e exclusão da pilha. Essa função do Lambda é responsável por criar e excluir a programação de monitoramento e usar os parâmetros definidos no recurso personalizado descrito na seção 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
```