O Dia da Comunidade de ML é dia 9 de novembro! Junte-nos para atualização de TensorFlow, JAX, e mais Saiba mais

Dê os primeiros passos com a validação de dados do Tensorflow

A validação de dados do Tensorflow (TFDV) pode analisar dados de treinamento e veiculação para:

A API principal oferece suporte a cada parte da funcionalidade, com métodos de conveniência que se baseiam e podem ser chamados no contexto de notebooks.

Computando estatísticas descritivas de dados

O TFDV pode calcular estatísticas descritivas que fornecem uma visão geral rápida dos dados em termos dos recursos que estão presentes e as formas de suas distribuições de valor. Ferramentas como Visão geral de facetas podem fornecer uma visualização sucinta dessas estatísticas para facilitar a navegação.

Por exemplo, suponha que o path aponte para um arquivo no formato TFRecord (que contém registros do tipo tensorflow.Example ). O seguinte snippet ilustra o cálculo de estatísticas usando TFDV:

    stats = tfdv.generate_statistics_from_tfrecord(data_location=path)

O valor retornado é um buffer de protocolo DatasetFeatureStatisticsList . O bloco de notas de exemplo contém uma visualização das estatísticas usando Visão geral das facetas :

    tfdv.visualize_statistics(stats)

Captura de tela da visualização de estatísticas

O exemplo anterior assume que os dados estão armazenados em um arquivo TFRecord . TFDV também oferece suporte ao formato de entrada CSV, com extensibilidade para outros formatos comuns. Você pode encontrar os decodificadores de dados disponíveis aqui . Além disso, o TFDV fornece a função de utilitário tfdv.generate_statistics_from_dataframe para usuários com dados na memória representados como um DataFrame do pandas.

Além de calcular um conjunto padrão de estatísticas de dados, o TFDV também pode calcular estatísticas para domínios semânticos (por exemplo, imagens, texto). Para habilitar a computação de estatísticas domínio semântico, passar um tfdv.StatsOptions objeto com enable_semantic_domain_stats Defina como true para tfdv.generate_statistics_from_tfrecord .

Executando no Google Cloud

Internamente, o TFDV usa a estrutura de processamento paralelo de dados do Apache Beam para dimensionar a computação de estatísticas em grandes conjuntos de dados. Para aplicativos que desejam se integrar mais profundamente com TFDV (por exemplo, anexar geração de estatísticas no final de um pipeline de geração de dados, gerar estatísticas para dados em formato personalizado ), a API também expõe um Beam PTransform para geração de estatísticas.

Para executar o TFDV no Google Cloud, o arquivo TFDV wheel deve ser baixado e fornecido aos workers do Dataflow. Baixe o arquivo wheel para o diretório atual da seguinte forma:

pip download tensorflow_data_validation \
  --no-deps \
  --platform manylinux2010_x86_64 \
  --only-binary=:all:

O snippet a seguir mostra um exemplo de uso de TFDV no Google Cloud:


import tensorflow_data_validation as tfdv
from apache_beam.options.pipeline_options import PipelineOptions, GoogleCloudOptions, StandardOptions, SetupOptions

PROJECT_ID = ''
JOB_NAME = ''
GCS_STAGING_LOCATION = ''
GCS_TMP_LOCATION = ''
GCS_DATA_LOCATION = ''
# GCS_STATS_OUTPUT_PATH is the file path to which to output the data statistics
# result.
GCS_STATS_OUTPUT_PATH = ''

PATH_TO_WHL_FILE = ''


# Create and set your PipelineOptions.
options = PipelineOptions()

# For Cloud execution, set the Cloud Platform project, job_name,
# staging location, temp_location and specify DataflowRunner.
google_cloud_options = options.view_as(GoogleCloudOptions)
google_cloud_options.project = PROJECT_ID
google_cloud_options.job_name = JOB_NAME
google_cloud_options.staging_location = GCS_STAGING_LOCATION
google_cloud_options.temp_location = GCS_TMP_LOCATION
options.view_as(StandardOptions).runner = 'DataflowRunner'

setup_options = options.view_as(SetupOptions)
# PATH_TO_WHL_FILE should point to the downloaded tfdv wheel file.
setup_options.extra_packages = [PATH_TO_WHL_FILE]

tfdv.generate_statistics_from_tfrecord(GCS_DATA_LOCATION,
                                       output_path=GCS_STATS_OUTPUT_PATH,
                                       pipeline_options=options)

Nesse caso, o protocolo de estatísticas gerado é armazenado em um arquivo TFRecord gravado em GCS_STATS_OUTPUT_PATH .

NOTA Ao chamar qualquer uma das funções tfdv.generate_statistics_... (por exemplo, tfdv.generate_statistics_from_tfrecord ) no Google Cloud, você deve fornecer um output_path . Especificar Nenhum pode causar um erro.

Inferir um esquema sobre os dados

O esquema descreve as propriedades esperadas dos dados. Algumas dessas propriedades são:

  • quais recursos devem estar presentes
  • o tipo deles
  • o número de valores para um recurso em cada exemplo
  • a presença de cada recurso em todos os exemplos
  • os domínios esperados de recursos.

Em suma, o esquema descreve as expectativas de dados "corretos" e pode, portanto, ser usado para detectar erros nos dados (descritos abaixo). Além disso, o mesmo esquema pode ser usado para configurar o Tensorflow Transform para transformações de dados. Observe que se espera que o esquema seja bastante estático, por exemplo, vários conjuntos de dados podem estar em conformidade com o mesmo esquema, enquanto as estatísticas (descritas acima) podem variar por conjunto de dados.

Como escrever um esquema pode ser uma tarefa tediosa, especialmente para conjuntos de dados com muitos recursos, o TFDV fornece um método para gerar uma versão inicial do esquema com base nas estatísticas descritivas:

    schema = tfdv.infer_schema(stats)

Em geral, o TFDV usa heurísticas conservadoras para inferir propriedades de dados estáveis ​​a partir das estatísticas, a fim de evitar o sobreajuste do esquema para o conjunto de dados específico. É altamente recomendável revisar o esquema inferido e refiná-lo conforme necessário , para capturar qualquer conhecimento de domínio sobre os dados que as heurísticas do TFDV possam ter perdido.

Por padrão, tfdv.infer_schema infere a forma de cada recurso necessário, se value_count.min for igual a value_count.max para o recurso. Defina o argumento infer_feature_shape como False para desativar a inferência de formas.

O esquema em si é armazenado como um buffer de protocolo do Schema e pode, portanto, ser atualizado / editado usando a API de buffer de protocolo padrão. O TFDV também fornece alguns métodos utilitários para tornar essas atualizações mais fáceis. Por exemplo, suponha que o esquema contenha a seguinte estrofe para descrever um recurso de string obrigatório payment_type que assume um único valor:

feature {
  name: "payment_type"
  value_count {
    min: 1
    max: 1
  }
  type: BYTES
  domain: "payment_type"
  presence {
    min_fraction: 1.0
    min_count: 1
  }
}

Para marcar que o recurso deve ser preenchido em pelo menos 50% dos exemplos:

    tfdv.get_feature(schema, 'payment_type').presence.min_fraction = 0.5

O bloco de notas de exemplo contém uma visualização simples do esquema como uma tabela, listando cada recurso e suas características principais conforme codificadas no esquema.

Captura de tela da visualização do esquema

Verificando os dados em busca de erros

Dado um esquema, é possível verificar se um conjunto de dados está em conformidade com as expectativas definidas no esquema ou se existem quaisquer anomalias de dados . Você pode verificar se há erros em seus dados (a) no agregado em todo um conjunto de dados, comparando as estatísticas do conjunto de dados com o esquema, ou (b) verificando erros por exemplo.

Comparando as estatísticas do conjunto de dados com um esquema

Para verificar se há erros no agregado, o TFDV compara as estatísticas do conjunto de dados com o esquema e marca quaisquer discrepâncias. Por exemplo:

    # Assume that other_path points to another TFRecord file
    other_stats = tfdv.generate_statistics_from_tfrecord(data_location=other_path)
    anomalies = tfdv.validate_statistics(statistics=other_stats, schema=schema)

O resultado é uma instância do buffer de protocolo de Anomalies e descreve quaisquer erros em que as estatísticas não concordem com o esquema. Por exemplo, suponha que os dados em other_path contenham exemplos com valores para o recurso payment_type fora do domínio especificado no esquema.

Isso produz uma anomalia

   payment_type  Unexpected string values  Examples contain values missing from the schema: Prcard (<1%).

indicando que um valor fora do domínio foi encontrado nas estatísticas em <1% dos valores do recurso.

Se isso era esperado, o esquema pode ser atualizado da seguinte maneira:

   tfdv.get_domain(schema, 'payment_type').value.append('Prcard')

Se a anomalia realmente indicar um erro de dados, os dados subjacentes devem ser corrigidos antes de usá-los para treinamento.

Os vários tipos de anomalias que podem ser detectados por este módulo estão listados aqui .

O bloco de notas de exemplo contém uma visualização simples das anomalias como uma tabela, listando os recursos onde os erros são detectados e uma breve descrição de cada erro.

Captura de tela de anomalias

Verificação de erros por exemplo

O TFDV também oferece a opção de validar os dados por exemplo, em vez de comparar as estatísticas de todo o conjunto de dados com o esquema. TFDV fornece funções para validar dados por exemplo e, em seguida, gerar estatísticas de resumo para os exemplos anômalos encontrados. Por exemplo:

   options = tfdv.StatsOptions(schema=schema)
   anomalous_example_stats = tfdv.validate_examples_in_tfrecord(
       data_location=input, stats_options=options)

O anomalous_example_stats que validate_examples_in_tfrecord retorna é um buffer de protocolo DatasetFeatureStatisticsList no qual cada conjunto de dados consiste no conjunto de exemplos que exibem uma anomalia específica. Você pode usar isso para determinar o número de exemplos em seu conjunto de dados que exibem uma determinada anomalia e as características desses exemplos.

Ambientes de esquema

Por padrão, as validações assumem que todos os conjuntos de dados em um pipeline aderem a um único esquema. Em alguns casos, a introdução de pequenas variações de esquema é necessária, por exemplo, recursos usados ​​como rótulos são necessários durante o treinamento (e devem ser validados), mas estão ausentes durante o serviço.

Os ambientes podem ser usados ​​para expressar esses requisitos. Em particular, os recursos no esquema podem ser associados a um conjunto de ambientes usando default_environment, in_environment e not_in_environment.

Por exemplo, se o recurso de dicas está sendo usado como rótulo no treinamento, mas ausente nos dados de veiculação. Sem o ambiente especificado, ele aparecerá como uma anomalia.

    serving_stats = tfdv.generate_statistics_from_tfrecord(data_location=serving_data_path)
    serving_anomalies = tfdv.validate_statistics(serving_stats, schema)

Captura de tela de anomalias de veiculação

Para corrigir isso, precisamos definir o ambiente padrão para todos os recursos como 'TREINAMENTO' e 'SERVIR', e excluir o recurso 'dicas' do ambiente SERVIR.

    # All features are by default in both TRAINING and SERVING environments.
    schema.default_environment.append('TRAINING')
    schema.default_environment.append('SERVING')

    # Specify that 'tips' feature is not in SERVING environment.
    tfdv.get_feature(schema, 'tips').not_in_environment.append('SERVING')

    serving_anomalies_with_env = tfdv.validate_statistics(
        serving_stats, schema, environment='SERVING')

Verificando distorção e desvio de dados

Além de verificar se um conjunto de dados está em conformidade com as expectativas definidas no esquema, o TFDV também fornece funcionalidades para detectar:

  • distorção entre o treinamento e os dados de veiculação
  • deriva entre diferentes dias de dados de treinamento

O TFDV executa essa verificação comparando as estatísticas de diferentes conjuntos de dados com base nos comparadores de desvio / inclinação especificados no esquema. Por exemplo, para verificar se há alguma distorção entre o recurso 'payment_type' no treinamento e no conjunto de dados de veiculação:

    # Assume we have already generated the statistics of training dataset, and
    # inferred a schema from it.
    serving_stats = tfdv.generate_statistics_from_tfrecord(data_location=serving_data_path)
    # Add a skew comparator to schema for 'payment_type' and set the threshold
    # of L-infinity norm for triggering skew anomaly to be 0.01.
    tfdv.get_feature(schema, 'payment_type').skew_comparator.infinity_norm.threshold = 0.01
    skew_anomalies = tfdv.validate_statistics(
        statistics=train_stats, schema=schema, serving_statistics=serving_stats)

NOTA Para detectar inclinação para recursos numéricos, especifique um limite jensen_shannon_divergence vez de um limite infinity_norm no skew_comparator .

O mesmo ocorre com a verificação de que um conjunto de dados está em conformidade com as expectativas definidas no esquema. O resultado também é uma instância do buffer de protocolo do Anomalies e descreve qualquer distorção entre os conjuntos de dados de treinamento e serviço. Por exemplo, suponha que os dados de serviço contenham significativamente mais exemplos com o recurso payement_type tendo o valor Cash , isso produz uma anomalia de inclinação

   payment_type  High L-infinity distance between serving and training  The L-infinity distance between serving and training is 0.0435984 (up to six significant digits), above the threshold 0.01. The feature value with maximum difference is: Cash

Se a anomalia realmente indicar uma distorção entre os dados de treinamento e serviço, uma investigação mais aprofundada é necessária, pois isso pode ter um impacto direto no desempenho do modelo.

O bloco de notas de exemplo contém um exemplo simples de verificação de anomalias baseadas em distorção.

A detecção de desvios entre diferentes dias de dados de treinamento pode ser feita de maneira semelhante

    # Assume we have already generated the statistics of training dataset for
    # day 2, and inferred a schema from it.
    train_day1_stats = tfdv.generate_statistics_from_tfrecord(data_location=train_day1_data_path)
    # Add a drift comparator to schema for 'payment_type' and set the threshold
    # of L-infinity norm for triggering drift anomaly to be 0.01.
    tfdv.get_feature(schema, 'payment_type').drift_comparator.infinity_norm.threshold = 0.01
    drift_anomalies = tfdv.validate_statistics(
        statistics=train_day2_stats, schema=schema, previous_statistics=train_day1_stats)

NOTA Para detectar inclinação para recursos numéricos, especifique um limite jensen_shannon_divergence vez de um limite infinity_norm no drift_comparator .

Gravando conector de dados personalizado

Para calcular estatísticas de dados, TFDV fornece vários métodos convenientes para lidar com dados de entrada em vários formatos (por exemplo, TFRecord de tf.train.Example , CSV, etc). Se o seu formato de dados não estiver nesta lista, você precisa escrever um conector de dados customizado para ler dados de entrada e conectá-lo com a API do núcleo TFDV para estatísticas de dados de computação.

A API principal do TFDV para estatísticas de dados de computação é um Beam PTransform que obtém uma PCollection de lotes de exemplos de entrada (um lote de exemplos de entrada é representado como um Arrow RecordBatch) e produz uma PCollection contendo um único buffer de protocolo DatasetFeatureStatisticsList .

Depois de implementar o conector de dados customizado que agrupa seus exemplos de entrada em um Arrow RecordBatch, você precisa conectá-lo à API tfdv.GenerateStatistics para calcular as estatísticas de dados. Tome TFRecord de tf.train.Example , por exemplo. tfx_bsl fornece o conector de dados TFExampleRecord e abaixo está um exemplo de como conectá-lo à API tfdv.GenerateStatistics .

import tensorflow_data_validation as tfdv
from tfx_bsl.public import tfxio
import apache_beam as beam
from tensorflow_metadata.proto.v0 import statistics_pb2

DATA_LOCATION = ''
OUTPUT_LOCATION = ''

with beam.Pipeline() as p:
    _ = (
    p
    # 1. Read and decode the data with tfx_bsl.
    | 'TFXIORead' >> (
          tfxio.TFExampleRecord(
              file_pattern=[DATA_LOCATION],
              telemetry_descriptors=['my', 'tfdv']).BeamSource())
    # 2. Invoke TFDV `GenerateStatistics` API to compute the data statistics.
    | 'GenerateStatistics' >> tfdv.GenerateStatistics()
    # 3. Materialize the generated data statistics.
    | 'WriteStatsOutput' >> WriteStatisticsToTFRecord(OUTPUT_LOCATION))

Computando estatísticas sobre fatias de dados

O TFDV pode ser configurado para calcular estatísticas sobre fatias de dados. O fatiamento pode ser ativado fornecendo funções de fatiamento que pegam um RecordBatch Seta e RecordBatch uma sequência de tuplas de forma (slice key, record batch) . TFDV fornece uma maneira fácil de gerar funções de fatiamento baseadas em valor de recurso que podem ser fornecidas como parte de tfdv.StatsOptions ao calcular estatísticas.

Quando o fatiamento está ativado, o protótipo de saída DatasetFeatureStatisticsList contém vários protos DatasetFeatureStatistics , um para cada fatia. Cada fatia é identificada por um nome exclusivo que é definido como o nome do conjunto de dados no protocolo DatasetFeatureStatistics . Por padrão, o TFDV calcula estatísticas para o conjunto de dados geral, além das fatias configuradas.

import tensorflow_data_validation as tfdv
from tensorflow_data_validation.utils import slicing_util

# Slice on country feature (i.e., every unique value of the feature).
slice_fn1 = slicing_util.get_feature_value_slicer(features={'country': None})

# Slice on the cross of country and state feature (i.e., every unique pair of
# values of the cross).
slice_fn2 = slicing_util.get_feature_value_slicer(
    features={'country': None, 'state': None})

# Slice on specific values of a feature.
slice_fn3 = slicing_util.get_feature_value_slicer(
    features={'age': [10, 50, 70]})

stats_options = tfdv.StatsOptions(
    slice_functions=[slice_fn1, slice_fn2, slice_fn3])