O componente Transform TFX Pipeline

O componente de pipeline Transform TFX executa a engenharia de recursos em tf.Examples emitidos de um componente ExampleGen , usando um esquema de dados criado por um componente SchemaGen e emite tanto um SavedModel quanto estatísticas em dados pré-transformados e pós-transformados. Quando executado, o SavedModel aceitará tf.Examples emitidos de um componente ExampleGen e emitirá os dados de recursos transformados.

  • Consome: tf.Examples de um componente ExampleGen e um esquema de dados de um componente SchemaGen.
  • Emite: um SavedModel para um componente Trainer, estatísticas de pré-transformação e pós-transformação.

Configurando um componente de transformação

Depois que seu preprocessing_fn é gravado, ele precisa ser definido em um módulo python que é fornecido ao componente Transform como uma entrada. Este módulo será carregado por transform e a função denominada preprocessing_fn será encontrada e usada por Transform para construir o pipeline de pré-processamento.

transform = Transform(
    examples=example_gen.outputs['examples'],
    schema=schema_gen.outputs['schema'],
    module_file=os.path.abspath(_taxi_transform_module_file))

Além disso, você pode desejar fornecer opções para o cálculo de estatísticas pré-transformadas ou pós-transformadas baseadas em TFDV . Para fazer isso, defina um stats_options_updater_fn dentro do mesmo módulo.

Transformação e Transformação do TensorFlow

O Transform faz uso extensivo do TensorFlow Transform para executar a engenharia de recursos em seu conjunto de dados. O TensorFlow Transform é uma ótima ferramenta para transformar dados de feições antes de irem para o seu modelo e como parte do processo de treinamento. Transformações de recursos comuns incluem:

  • Incorporação : conversão de recursos esparsos (como os IDs inteiros produzidos por um vocabulário) em recursos densos, encontrando um mapeamento significativo do espaço de alta dimensão para o espaço de baixa dimensão. Consulte a unidade Incorporações no Curso rápido de aprendizado de máquina para obter uma introdução às incorporações.
  • Geração de vocabulário : converte strings ou outros recursos não numéricos em números inteiros, criando um vocabulário que mapeia cada valor exclusivo para um número de identificação.
  • Normalização de valores : transformação de recursos numéricos para que todos caiam em um intervalo semelhante.
  • Bucketização : conversão de recursos de valor contínuo em recursos categóricos, atribuindo valores a baldes discretos.
  • Enriquecimento de recursos de texto : produção de recursos a partir de dados brutos, como tokens, n-gramas, entidades, sentimentos, etc., para enriquecer o conjunto de recursos.

O TensorFlow Transform oferece suporte para esses e muitos outros tipos de transformações:

  • Gere automaticamente um vocabulário de seus dados mais recentes.

  • Execute transformações arbitrárias em seus dados antes de enviá-los para seu modelo. O TensorFlow Transform cria transformações no gráfico do TensorFlow para seu modelo, para que as mesmas transformações sejam realizadas no treinamento e no tempo de inferência. Você pode definir transformações que se referem a propriedades globais dos dados, como o valor máximo de um recurso em todas as instâncias de treinamento.

Você pode transformar seus dados como quiser antes de executar o TFX. Mas se você fizer isso no TensorFlow Transform, as transformações se tornarão parte do gráfico do TensorFlow. Essa abordagem ajuda a evitar desvios de treinamento/serviço.

As transformações dentro do seu código de modelagem usam FeatureColumns. Usando FeatureColumns, você pode definir bucketizations, integerizations que usam vocabulários predefinidos ou quaisquer outras transformações que podem ser definidas sem examinar os dados.

Por outro lado, o TensorFlow Transform foi projetado para transformações que exigem uma passagem completa dos dados para calcular valores que não são conhecidos antecipadamente. Por exemplo, a geração de vocabulário requer uma passagem completa dos dados.

Além de calcular valores usando o Apache Beam, o TensorFlow Transform permite que os usuários incorporem esses valores em um gráfico do TensorFlow, que pode ser carregado no gráfico de treinamento. Por exemplo, ao normalizar recursos, a função tft.scale_to_z_score calculará a média e o desvio padrão de um recurso e também uma representação, em um gráfico do TensorFlow, da função que subtrai a média e divide pelo desvio padrão. Ao emitir um gráfico do TensorFlow, não apenas estatísticas, o TensorFlow Transform simplifica o processo de criação do pipeline de pré-processamento.

Como o pré-processamento é expresso como um gráfico, ele pode acontecer no servidor e é garantido que seja consistente entre o treinamento e o serviço. Essa consistência elimina uma fonte de distorção de treinamento/serviço.

O TensorFlow Transform permite que os usuários especifiquem seu pipeline de pré-processamento usando o código do TensorFlow. Isso significa que um pipeline é construído da mesma maneira que um gráfico do TensorFlow. Se apenas as operações do TensorFlow fossem usadas neste gráfico, o pipeline seria um mapa puro que aceita lotes de entrada e retorna lotes de saída. Esse pipeline seria equivalente a colocar esse gráfico dentro de seu input_fn ao usar a API tf.Estimator . Para especificar operações de passagem completa, como calcular quantis, o TensorFlow Transform fornece funções especiais chamadas analyzers que aparecem como operações do TensorFlow, mas na verdade especificam uma computação adiada que será feita pelo Apache Beam e a saída inserida no gráfico como um constante. Enquanto uma operação comum do TensorFlow usará um único lote como entrada, realizará alguns cálculos apenas nesse lote e emitirá um lote, um analyzer executará uma redução global (implementada no Apache Beam) em todos os lotes e retornará o resultado.

Ao combinar operações comuns do TensorFlow e analisadores TensorFlow Transform, os usuários podem criar pipelines complexos para pré-processar seus dados. Por exemplo, a função tft.scale_to_z_score pega um tensor de entrada e retorna esse tensor normalizado para ter média 0 e variância 1 . Ele faz isso chamando os analisadores de mean e var sob o capô, que efetivamente gerarão constantes no gráfico iguais à média e à variância do tensor de entrada. Em seguida, ele usará as operações do TensorFlow para subtrair a média e dividir pelo desvio padrão.

O pré- preprocessing_fn da transformação do TensorFlow_fn

O componente TFX Transform simplifica o uso de Transform manipulando as chamadas de API relacionadas à leitura e gravação de dados e gravando a saída SavedModel no disco. Como usuário do TFX, você só precisa definir uma única função chamada preprocessing_fn . Em preprocessing_fn , você define uma série de funções que manipulam o dict de entrada dos tensores para produzir o dict de saída dos tensores. Você pode encontrar funções auxiliares como scale_to_0_1 e compute_and_apply_vocabulary na API TensorFlow Transform ou usar funções regulares do TensorFlow, conforme mostrado abaixo.

def preprocessing_fn(inputs):
  """tf.transform's callback function for preprocessing inputs.

  Args:
    inputs: map from feature keys to raw not-yet-transformed features.

  Returns:
    Map from string feature key to transformed feature operations.
  """
  outputs = {}
  for key in _DENSE_FLOAT_FEATURE_KEYS:
    # If sparse make it dense, setting nan's to 0 or '', and apply zscore.
    outputs[_transformed_name(key)] = transform.scale_to_z_score(
        _fill_in_missing(inputs[key]))

  for key in _VOCAB_FEATURE_KEYS:
    # Build a vocabulary for this feature.
    outputs[_transformed_name(
        key)] = transform.compute_and_apply_vocabulary(
            _fill_in_missing(inputs[key]),
            top_k=_VOCAB_SIZE,
            num_oov_buckets=_OOV_SIZE)

  for key in _BUCKET_FEATURE_KEYS:
    outputs[_transformed_name(key)] = transform.bucketize(
        _fill_in_missing(inputs[key]), _FEATURE_BUCKET_COUNT)

  for key in _CATEGORICAL_FEATURE_KEYS:
    outputs[_transformed_name(key)] = _fill_in_missing(inputs[key])

  # Was this passenger a big tipper?
  taxi_fare = _fill_in_missing(inputs[_FARE_KEY])
  tips = _fill_in_missing(inputs[_LABEL_KEY])
  outputs[_transformed_name(_LABEL_KEY)] = tf.where(
      tf.is_nan(taxi_fare),
      tf.cast(tf.zeros_like(taxi_fare), tf.int64),
      # Test if the tip was > 20% of the fare.
      tf.cast(
          tf.greater(tips, tf.multiply(taxi_fare, tf.constant(0.2))), tf.int64))

  return outputs

Entendendo as entradas para o preprocessing_fn

O preprocessing_fn descreve uma série de operações em tensores (ou seja, Tensor s, SparseTensor s ou RaggedTensor s). Para definir o preprocessing_fn corretamente é necessário entender como os dados são representados como tensores. A entrada para preprocessing_fn é determinada pelo esquema. Um Schema é eventualmente convertido em uma "especificação de recurso" (às vezes chamada de "especificação de análise") que é usada para análise de dados, veja mais detalhes sobre a lógica de conversão aqui .

Usando o TensorFlow Transform para lidar com rótulos de string

Normalmente, alguém deseja usar o TensorFlow Transform para gerar um vocabulário e aplicar esse vocabulário para converter strings em números inteiros. Ao seguir este fluxo de trabalho, o input_fn construído no modelo produzirá a string inteirada. No entanto, os rótulos são uma exceção, porque para que o modelo seja capaz de mapear os rótulos de saída (inteiro) de volta para strings, o modelo precisa do input_fn para gerar um rótulo de string, junto com uma lista de possíveis valores do rótulo. Por exemplo, se os rótulos são cat e dog , a saída de input_fn deve ser essas strings brutas e as chaves ["cat", "dog"] precisam ser passadas para o estimador como um parâmetro (consulte os detalhes abaixo).

Para lidar com o mapeamento de rótulos de string para números inteiros, você deve usar o TensorFlow Transform para gerar um vocabulário. Demonstramos isso no trecho de código abaixo:

def _preprocessing_fn(inputs):
  """Preprocess input features into transformed features."""

  ...


  education = inputs[features.RAW_LABEL_KEY]
  _ = tft.vocabulary(education, vocab_filename=features.RAW_LABEL_KEY)

  ...

A função de pré-processamento acima pega o recurso de entrada bruta (que também será retornado como parte da saída da função de pré-processamento) e chama tft.vocabulary nele. Isso resulta na geração de um vocabulário para education que pode ser acessado no modelo.

O exemplo também mostra como transformar um rótulo e gerar um vocabulário para o rótulo transformado. Em particular, ele pega a education do rótulo bruto e converte todos, exceto os 5 principais rótulos (por frequência) em UNKNOWN , sem converter o rótulo em um número inteiro.

No código do modelo, o classificador deve receber o vocabulário gerado por tft.vocabulary como o argumento label_vocabulary . Isso é feito lendo primeiro este vocabulário como uma lista com uma função auxiliar. Isso é mostrado no trecho abaixo. Observe que o código de exemplo usa o rótulo transformado discutido acima, mas aqui mostramos o código para usar o rótulo bruto.

def create_estimator(pipeline_inputs, hparams):

  ...

  tf_transform_output = trainer_util.TFTransformOutput(
      pipeline_inputs.transform_dir)

  # vocabulary_by_name() returns a Python list.
  label_vocabulary = tf_transform_output.vocabulary_by_name(
      features.RAW_LABEL_KEY)

  return tf.contrib.learn.DNNLinearCombinedClassifier(
      ...
      n_classes=len(label_vocab),
      label_vocabulary=label_vocab,
      ...)

Como configurar estatísticas de pré-transformação e pós-transformação

Conforme mencionado acima, o componente Transform invoca o TFDV para calcular as estatísticas de pré-transformação e pós-transformação. O TFDV recebe como entrada um objeto StatsOptions opcional. Os usuários podem querer configurar este objeto para habilitar certas estatísticas adicionais (por exemplo, estatísticas NLP) ou para definir limites que são validados (por exemplo, frequência mínima/máxima de token). Para fazer isso, defina um stats_options_updater_fn no arquivo do módulo.

def stats_options_updater_fn(stats_type, stats_options):
  ...
  if stats_type == stats_options_util.StatsType.PRE_TRANSFORM:
    # Update stats_options to modify pre-transform statistics computation.
    # Most constraints are specified in the schema which can be accessed
    # via stats_options.schema.
  if stats_type == stats_options_util.StatsType.POST_TRANSFORM
    # Update stats_options to modify post-transform statistics computation.
    # Most constraints are specified in the schema which can be accessed
    # via stats_options.schema.
  return stats_options

As estatísticas pós-transformação geralmente se beneficiam do conhecimento do vocabulário usado para pré-processar um recurso. O nome do vocabulário para o mapeamento do caminho é fornecido para StatsOptions (e, portanto, TFDV) para cada vocabulário gerado pelo TFT. Além disso, os mapeamentos para vocabulários criados externamente podem ser adicionados (i) modificando diretamente o dicionário vocab_paths em StatsOptions ou (ii) usando tft.annotate_asset .

,

O componente de pipeline Transform TFX executa a engenharia de recursos em tf.Examples emitidos de um componente ExampleGen , usando um esquema de dados criado por um componente SchemaGen e emite tanto um SavedModel quanto estatísticas em dados pré-transformados e pós-transformados. Quando executado, o SavedModel aceitará tf.Examples emitidos de um componente ExampleGen e emitirá os dados de recursos transformados.

  • Consome: tf.Examples de um componente ExampleGen e um esquema de dados de um componente SchemaGen.
  • Emite: um SavedModel para um componente Trainer, estatísticas de pré-transformação e pós-transformação.

Configurando um componente de transformação

Depois que seu preprocessing_fn é gravado, ele precisa ser definido em um módulo python que é fornecido ao componente Transform como uma entrada. Este módulo será carregado por transform e a função denominada preprocessing_fn será encontrada e usada por Transform para construir o pipeline de pré-processamento.

transform = Transform(
    examples=example_gen.outputs['examples'],
    schema=schema_gen.outputs['schema'],
    module_file=os.path.abspath(_taxi_transform_module_file))

Além disso, você pode desejar fornecer opções para o cálculo de estatísticas pré-transformadas ou pós-transformadas baseadas em TFDV . Para fazer isso, defina um stats_options_updater_fn dentro do mesmo módulo.

Transformação e Transformação do TensorFlow

O Transform faz uso extensivo do TensorFlow Transform para executar a engenharia de recursos em seu conjunto de dados. O TensorFlow Transform é uma ótima ferramenta para transformar dados de feições antes de irem para o seu modelo e como parte do processo de treinamento. Transformações de recursos comuns incluem:

  • Incorporação : conversão de recursos esparsos (como os IDs inteiros produzidos por um vocabulário) em recursos densos, encontrando um mapeamento significativo do espaço de alta dimensão para o espaço de baixa dimensão. Consulte a unidade Incorporações no Curso rápido de aprendizado de máquina para obter uma introdução às incorporações.
  • Geração de vocabulário : converte strings ou outros recursos não numéricos em números inteiros, criando um vocabulário que mapeia cada valor exclusivo para um número de identificação.
  • Normalização de valores : transformação de recursos numéricos para que todos caiam em um intervalo semelhante.
  • Bucketização : conversão de recursos de valor contínuo em recursos categóricos, atribuindo valores a baldes discretos.
  • Enriquecimento de recursos de texto : produção de recursos a partir de dados brutos, como tokens, n-gramas, entidades, sentimentos, etc., para enriquecer o conjunto de recursos.

O TensorFlow Transform oferece suporte para esses e muitos outros tipos de transformações:

  • Gere automaticamente um vocabulário de seus dados mais recentes.

  • Execute transformações arbitrárias em seus dados antes de enviá-los para seu modelo. O TensorFlow Transform cria transformações no gráfico do TensorFlow para seu modelo, para que as mesmas transformações sejam realizadas no treinamento e no tempo de inferência. Você pode definir transformações que se referem a propriedades globais dos dados, como o valor máximo de um recurso em todas as instâncias de treinamento.

Você pode transformar seus dados como quiser antes de executar o TFX. Mas se você fizer isso no TensorFlow Transform, as transformações se tornarão parte do gráfico do TensorFlow. Essa abordagem ajuda a evitar desvios de treinamento/serviço.

As transformações dentro do seu código de modelagem usam FeatureColumns. Usando FeatureColumns, você pode definir bucketizations, integerizations que usam vocabulários predefinidos ou quaisquer outras transformações que podem ser definidas sem examinar os dados.

Por outro lado, o TensorFlow Transform foi projetado para transformações que exigem uma passagem completa dos dados para calcular valores que não são conhecidos antecipadamente. Por exemplo, a geração de vocabulário requer uma passagem completa dos dados.

Além de calcular valores usando o Apache Beam, o TensorFlow Transform permite que os usuários incorporem esses valores em um gráfico do TensorFlow, que pode ser carregado no gráfico de treinamento. Por exemplo, ao normalizar recursos, a função tft.scale_to_z_score calculará a média e o desvio padrão de um recurso e também uma representação, em um gráfico do TensorFlow, da função que subtrai a média e divide pelo desvio padrão. Ao emitir um gráfico do TensorFlow, não apenas estatísticas, o TensorFlow Transform simplifica o processo de criação do pipeline de pré-processamento.

Como o pré-processamento é expresso como um gráfico, ele pode acontecer no servidor e é garantido que seja consistente entre o treinamento e o serviço. Essa consistência elimina uma fonte de distorção de treinamento/serviço.

O TensorFlow Transform permite que os usuários especifiquem seu pipeline de pré-processamento usando o código do TensorFlow. Isso significa que um pipeline é construído da mesma maneira que um gráfico do TensorFlow. Se apenas as operações do TensorFlow fossem usadas neste gráfico, o pipeline seria um mapa puro que aceita lotes de entrada e retorna lotes de saída. Esse pipeline seria equivalente a colocar esse gráfico dentro de seu input_fn ao usar a API tf.Estimator . Para especificar operações de passagem completa, como calcular quantis, o TensorFlow Transform fornece funções especiais chamadas analyzers que aparecem como operações do TensorFlow, mas na verdade especificam uma computação adiada que será feita pelo Apache Beam e a saída inserida no gráfico como um constante. Enquanto uma operação comum do TensorFlow usará um único lote como entrada, realizará alguns cálculos apenas nesse lote e emitirá um lote, um analyzer executará uma redução global (implementada no Apache Beam) em todos os lotes e retornará o resultado.

Ao combinar operações comuns do TensorFlow e analisadores TensorFlow Transform, os usuários podem criar pipelines complexos para pré-processar seus dados. Por exemplo, a função tft.scale_to_z_score pega um tensor de entrada e retorna esse tensor normalizado para ter média 0 e variância 1 . Ele faz isso chamando os analisadores de mean e var sob o capô, que efetivamente gerarão constantes no gráfico iguais à média e à variância do tensor de entrada. Em seguida, ele usará as operações do TensorFlow para subtrair a média e dividir pelo desvio padrão.

O pré- preprocessing_fn da transformação do TensorFlow_fn

O componente TFX Transform simplifica o uso de Transform manipulando as chamadas de API relacionadas à leitura e gravação de dados e gravando a saída SavedModel no disco. Como usuário do TFX, você só precisa definir uma única função chamada preprocessing_fn . Em preprocessing_fn , você define uma série de funções que manipulam o dict de entrada dos tensores para produzir o dict de saída dos tensores. Você pode encontrar funções auxiliares como scale_to_0_1 e compute_and_apply_vocabulary na API TensorFlow Transform ou usar funções regulares do TensorFlow, conforme mostrado abaixo.

def preprocessing_fn(inputs):
  """tf.transform's callback function for preprocessing inputs.

  Args:
    inputs: map from feature keys to raw not-yet-transformed features.

  Returns:
    Map from string feature key to transformed feature operations.
  """
  outputs = {}
  for key in _DENSE_FLOAT_FEATURE_KEYS:
    # If sparse make it dense, setting nan's to 0 or '', and apply zscore.
    outputs[_transformed_name(key)] = transform.scale_to_z_score(
        _fill_in_missing(inputs[key]))

  for key in _VOCAB_FEATURE_KEYS:
    # Build a vocabulary for this feature.
    outputs[_transformed_name(
        key)] = transform.compute_and_apply_vocabulary(
            _fill_in_missing(inputs[key]),
            top_k=_VOCAB_SIZE,
            num_oov_buckets=_OOV_SIZE)

  for key in _BUCKET_FEATURE_KEYS:
    outputs[_transformed_name(key)] = transform.bucketize(
        _fill_in_missing(inputs[key]), _FEATURE_BUCKET_COUNT)

  for key in _CATEGORICAL_FEATURE_KEYS:
    outputs[_transformed_name(key)] = _fill_in_missing(inputs[key])

  # Was this passenger a big tipper?
  taxi_fare = _fill_in_missing(inputs[_FARE_KEY])
  tips = _fill_in_missing(inputs[_LABEL_KEY])
  outputs[_transformed_name(_LABEL_KEY)] = tf.where(
      tf.is_nan(taxi_fare),
      tf.cast(tf.zeros_like(taxi_fare), tf.int64),
      # Test if the tip was > 20% of the fare.
      tf.cast(
          tf.greater(tips, tf.multiply(taxi_fare, tf.constant(0.2))), tf.int64))

  return outputs

Entendendo as entradas para o preprocessing_fn

O preprocessing_fn descreve uma série de operações em tensores (ou seja, Tensor s, SparseTensor s ou RaggedTensor s). Para definir o preprocessing_fn corretamente é necessário entender como os dados são representados como tensores. A entrada para preprocessing_fn é determinada pelo esquema. Um Schema é eventualmente convertido em uma "especificação de recurso" (às vezes chamada de "especificação de análise") que é usada para análise de dados, veja mais detalhes sobre a lógica de conversão aqui .

Usando o TensorFlow Transform para lidar com rótulos de string

Normalmente, alguém deseja usar o TensorFlow Transform para gerar um vocabulário e aplicar esse vocabulário para converter strings em números inteiros. Ao seguir este fluxo de trabalho, o input_fn construído no modelo produzirá a string inteirada. No entanto, os rótulos são uma exceção, porque para que o modelo seja capaz de mapear os rótulos de saída (inteiro) de volta para strings, o modelo precisa do input_fn para gerar um rótulo de string, junto com uma lista de possíveis valores do rótulo. Por exemplo, se os rótulos são cat e dog , a saída de input_fn deve ser essas strings brutas e as chaves ["cat", "dog"] precisam ser passadas para o estimador como um parâmetro (consulte os detalhes abaixo).

Para lidar com o mapeamento de rótulos de string para números inteiros, você deve usar o TensorFlow Transform para gerar um vocabulário. Demonstramos isso no trecho de código abaixo:

def _preprocessing_fn(inputs):
  """Preprocess input features into transformed features."""

  ...


  education = inputs[features.RAW_LABEL_KEY]
  _ = tft.vocabulary(education, vocab_filename=features.RAW_LABEL_KEY)

  ...

A função de pré-processamento acima pega o recurso de entrada bruta (que também será retornado como parte da saída da função de pré-processamento) e chama tft.vocabulary nele. Isso resulta na geração de um vocabulário para education que pode ser acessado no modelo.

O exemplo também mostra como transformar um rótulo e gerar um vocabulário para o rótulo transformado. Em particular, ele pega a education do rótulo bruto e converte todos, exceto os 5 principais rótulos (por frequência) em UNKNOWN , sem converter o rótulo em um número inteiro.

No código do modelo, o classificador deve receber o vocabulário gerado por tft.vocabulary como o argumento label_vocabulary . Isso é feito lendo primeiro este vocabulário como uma lista com uma função auxiliar. Isso é mostrado no trecho abaixo. Observe que o código de exemplo usa o rótulo transformado discutido acima, mas aqui mostramos o código para usar o rótulo bruto.

def create_estimator(pipeline_inputs, hparams):

  ...

  tf_transform_output = trainer_util.TFTransformOutput(
      pipeline_inputs.transform_dir)

  # vocabulary_by_name() returns a Python list.
  label_vocabulary = tf_transform_output.vocabulary_by_name(
      features.RAW_LABEL_KEY)

  return tf.contrib.learn.DNNLinearCombinedClassifier(
      ...
      n_classes=len(label_vocab),
      label_vocabulary=label_vocab,
      ...)

Como configurar estatísticas de pré-transformação e pós-transformação

Conforme mencionado acima, o componente Transform invoca o TFDV para calcular as estatísticas de pré-transformação e pós-transformação. O TFDV recebe como entrada um objeto StatsOptions opcional. Os usuários podem querer configurar este objeto para habilitar certas estatísticas adicionais (por exemplo, estatísticas NLP) ou para definir limites que são validados (por exemplo, frequência mínima/máxima de token). Para fazer isso, defina um stats_options_updater_fn no arquivo do módulo.

def stats_options_updater_fn(stats_type, stats_options):
  ...
  if stats_type == stats_options_util.StatsType.PRE_TRANSFORM:
    # Update stats_options to modify pre-transform statistics computation.
    # Most constraints are specified in the schema which can be accessed
    # via stats_options.schema.
  if stats_type == stats_options_util.StatsType.POST_TRANSFORM
    # Update stats_options to modify post-transform statistics computation.
    # Most constraints are specified in the schema which can be accessed
    # via stats_options.schema.
  return stats_options

As estatísticas pós-transformação geralmente se beneficiam do conhecimento do vocabulário usado para pré-processar um recurso. O nome do vocabulário para o mapeamento do caminho é fornecido para StatsOptions (e, portanto, TFDV) para cada vocabulário gerado pelo TFT. Além disso, os mapeamentos para vocabulários criados externamente podem ser adicionados (i) modificando diretamente o dicionário vocab_paths em StatsOptions ou (ii) usando tft.annotate_asset .