Pré-processar dados com o TensorFlow Transform

O componente de engenharia de recursos do TensorFlow Extended (TFX)

Este exemplo de notebook colab fornece um exemplo muito simples de como o TensorFlow Transform ( tf.Transform ) pode ser usado para pré-processar dados usando exatamente o mesmo código para treinar um modelo e fornecer inferências na produção.

O TensorFlow Transform é uma biblioteca para pré-processamento de dados de entrada para o TensorFlow, incluindo a criação de recursos que exigem uma passagem completa pelo conjunto de dados de treinamento. Por exemplo, usando o TensorFlow Transform, você pode:

  • Normalize um valor de entrada usando a média e o desvio padrão
  • Converta strings em inteiros gerando um vocabulário sobre todos os valores de entrada
  • Converta floats em inteiros atribuindo-os a buckets, com base na distribuição de dados observada

O TensorFlow tem suporte integrado para manipulações em um único exemplo ou em um lote de exemplos. tf.Transform estende esses recursos para oferecer suporte a passagens completas em todo o conjunto de dados de treinamento.

A saída de tf.Transform é exportada como um gráfico do TensorFlow que você pode usar para treinamento e veiculação. Usar o mesmo gráfico para treinamento e veiculação pode evitar distorções, pois as mesmas transformações são aplicadas em ambos os estágios.

Pip de atualização

Para evitar atualizar o Pip em um sistema ao executar localmente, verifique se estamos executando no Colab. É claro que os sistemas locais podem ser atualizados separadamente.

try:
  import colab
  !pip install --upgrade pip
except:
  pass

Instalar o TensorFlow Transform

pip install -q -U tensorflow_transform

Você reiniciou o tempo de execução?

Se você estiver usando o Google Colab, na primeira vez que executar a célula acima, deverá reiniciar o runtime (Runtime > Restart runtime...). Isso ocorre devido à maneira como o Colab carrega os pacotes.

Importações

import pprint
import tempfile

import tensorflow as tf
import tensorflow_transform as tft

import tensorflow_transform.beam as tft_beam
from tensorflow_transform.tf_metadata import dataset_metadata
from tensorflow_transform.tf_metadata import schema_utils

Dados: crie alguns dados fictícios

Vamos criar alguns dados fictícios simples para nosso exemplo simples:

  • raw_data são os dados brutos iniciais que vamos pré-processar
  • raw_data_metadata contém o esquema que nos informa os tipos de cada uma das colunas em raw_data . Neste caso, é muito simples.
raw_data = [
      {'x': 1, 'y': 1, 's': 'hello'},
      {'x': 2, 'y': 2, 's': 'world'},
      {'x': 3, 'y': 3, 's': 'hello'}
  ]

raw_data_metadata = dataset_metadata.DatasetMetadata(
    schema_utils.schema_from_feature_spec({
        'y': tf.io.FixedLenFeature([], tf.float32),
        'x': tf.io.FixedLenFeature([], tf.float32),
        's': tf.io.FixedLenFeature([], tf.string),
    }))

Transformar: criar uma função de pré-processamento

A função de pré -processamento é o conceito mais importante de tf.Transform. Uma função de pré-processamento é onde a transformação do conjunto de dados realmente acontece. Ele aceita e retorna um dicionário de tensores, onde um tensor significa um Tensor ouSparseTensor . Existem dois grupos principais de chamadas de API que normalmente formam o coração de uma função de pré-processamento:

  1. TensorFlow Ops: qualquer função que aceita e retorna tensores, o que geralmente significa operações do TensorFlow. Eles adicionam operações do TensorFlow ao gráfico que transforma dados brutos em dados transformados, um vetor de recurso por vez. Eles serão executados para todos os exemplos, durante o treinamento e o serviço.
  2. Analisadores/Mapeadores de Transformação do Tensorflow: Qualquer um dos analisadores/mapeadores fornecidos pelo tf.Transform. Eles também aceitam e retornam tensores e normalmente contêm uma combinação de operações do Tensorflow e computação do Beam, mas, ao contrário das operações do TensorFlow, eles são executados apenas no pipeline do Beam durante a análise, exigindo uma passagem completa por todo o conjunto de dados de treinamento. A computação do Beam é executada apenas uma vez, durante o treinamento, e normalmente faz uma passagem completa por todo o conjunto de dados de treinamento. Eles criam constantes de tensor, que são adicionadas ao seu gráfico. Por exemplo, tft.min calcula o mínimo de um tensor sobre o conjunto de dados de treinamento, enquanto tft.scale_by_min_max primeiro calcula o mínimo e o máximo de um tensor sobre o conjunto de dados de treinamento e, em seguida, dimensiona o tensor para estar dentro de um intervalo especificado pelo usuário, [output_min, output_max]. tf.Transform fornece um conjunto fixo de tais analisadores/mapeadores, mas isso será estendido em versões futuras.
def preprocessing_fn(inputs):
    """Preprocess input columns into transformed columns."""
    x = inputs['x']
    y = inputs['y']
    s = inputs['s']
    x_centered = x - tft.mean(x)
    y_normalized = tft.scale_to_0_1(y)
    s_integerized = tft.compute_and_apply_vocabulary(s)
    x_centered_times_y_normalized = (x_centered * y_normalized)
    return {
        'x_centered': x_centered,
        'y_normalized': y_normalized,
        's_integerized': s_integerized,
        'x_centered_times_y_normalized': x_centered_times_y_normalized,
    }

Juntando tudo

Agora estamos prontos para transformar nossos dados. Usaremos o Apache Beam com um executor direto e forneceremos três entradas:

  1. raw_data - Os dados brutos de entrada que criamos acima
  2. raw_data_metadata - O esquema para os dados brutos
  3. preprocessing_fn - A função que criamos para fazer nossa transformação
def main():
  # Ignore the warnings
  with tft_beam.Context(temp_dir=tempfile.mkdtemp()):
    transformed_dataset, transform_fn = (  # pylint: disable=unused-variable
        (raw_data, raw_data_metadata) | tft_beam.AnalyzeAndTransformDataset(
            preprocessing_fn))

  transformed_data, transformed_metadata = transformed_dataset  # pylint: disable=unused-variable

  print('\nRaw data:\n{}\n'.format(pprint.pformat(raw_data)))
  print('Transformed data:\n{}'.format(pprint.pformat(transformed_data)))

if __name__ == '__main__':
  main()
WARNING:apache_beam.runners.interactive.interactive_environment:Dependencies required for Interactive Beam PCollection visualization are not available, please use: `pip install apache-beam[interactive]` to install necessary dependencies to enable all data visualization features.
WARNING:tensorflow:You are passing instance dicts and DatasetMetadata to TFT which will not provide optimal performance. Consider following the TFT guide to upgrade to the TFXIO format (Apache Arrow RecordBatch).
WARNING:tensorflow:You are passing instance dicts and DatasetMetadata to TFT which will not provide optimal performance. Consider following the TFT guide to upgrade to the TFXIO format (Apache Arrow RecordBatch).
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_transform/tf_utils.py:289: Tensor.experimental_ref (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use ref() instead.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow_transform/tf_utils.py:289: Tensor.experimental_ref (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use ref() instead.
WARNING:tensorflow:You are passing instance dicts and DatasetMetadata to TFT which will not provide optimal performance. Consider following the TFT guide to upgrade to the TFXIO format (Apache Arrow RecordBatch).
WARNING:tensorflow:You are passing instance dicts and DatasetMetadata to TFT which will not provide optimal performance. Consider following the TFT guide to upgrade to the TFXIO format (Apache Arrow RecordBatch).
WARNING:apache_beam.options.pipeline_options:Discarding unparseable args: ['/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py', '-f', '/tmp/tmp8aif_7w8.json', '--HistoryManager.hist_file=:memory:']
WARNING:root:Make sure that locally built Python SDK docker image has Python 3.7 interpreter.
INFO:tensorflow:Assets written to: /tmp/tmpfvgb9_2h/tftransform_tmp/319450c9d7da4ab08741bc79e129ac38/assets
2022-02-03 10:18:41.378629: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
INFO:tensorflow:Assets written to: /tmp/tmpfvgb9_2h/tftransform_tmp/319450c9d7da4ab08741bc79e129ac38/assets
INFO:tensorflow:tensorflow_text is not available.
INFO:tensorflow:tensorflow_text is not available.
INFO:tensorflow:tensorflow_decision_forests is not available.
INFO:tensorflow:tensorflow_decision_forests is not available.
INFO:tensorflow:struct2tensor is not available.
INFO:tensorflow:struct2tensor is not available.
INFO:tensorflow:Assets written to: /tmp/tmpfvgb9_2h/tftransform_tmp/1f79865adbdd4ede9a3768fcac29949c/assets
INFO:tensorflow:Assets written to: /tmp/tmpfvgb9_2h/tftransform_tmp/1f79865adbdd4ede9a3768fcac29949c/assets
INFO:tensorflow:tensorflow_text is not available.
INFO:tensorflow:tensorflow_text is not available.
INFO:tensorflow:tensorflow_decision_forests is not available.
INFO:tensorflow:tensorflow_decision_forests is not available.
INFO:tensorflow:struct2tensor is not available.
INFO:tensorflow:struct2tensor is not available.
Raw data:
[{'s': 'hello', 'x': 1, 'y': 1},
 {'s': 'world', 'x': 2, 'y': 2},
 {'s': 'hello', 'x': 3, 'y': 3}]

Transformed data:
[{'s_integerized': 0,
  'x_centered': -1.0,
  'x_centered_times_y_normalized': -0.0,
  'y_normalized': 0.0},
 {'s_integerized': 1,
  'x_centered': 0.0,
  'x_centered_times_y_normalized': 0.0,
  'y_normalized': 0.5},
 {'s_integerized': 0,
  'x_centered': 1.0,
  'x_centered_times_y_normalized': 1.0,
  'y_normalized': 1.0}]

Esta é a resposta certa?

Anteriormente, tf.Transform para fazer isso:

x_centered = x - tft.mean(x)
y_normalized = tft.scale_to_0_1(y)
s_integerized = tft.compute_and_apply_vocabulary(s)
x_centered_times_y_normalized = (x_centered * y_normalized)

x_centrado

Com a entrada de [1, 2, 3] a média de x é 2, e a subtraímos de x para centralizar nossos valores de x em 0. Portanto, nosso resultado de [-1.0, 0.0, 1.0] está correto.

y_normalized

Queríamos escalar nossos valores de y entre 0 e 1. Nossa entrada foi [1, 2, 3] então nosso resultado de [0.0, 0.5, 1.0] está correto.

s_integerized

Queríamos mapear nossas strings para índices em um vocabulário e havia apenas 2 palavras em nosso vocabulário ("hello" e "world"). Então, com a entrada de ["hello", "world", "hello"] nosso resultado de [0, 1, 0] está correto. Como "olá" ocorre com mais frequência nesses dados, será a primeira entrada no vocabulário.

x_centered_times_y_normalized

Queríamos criar um novo recurso cruzando x_centered e y_normalized usando multiplicação. Observe que isso multiplica os resultados, não os valores originais, e nosso novo resultado de [-0.0, 0.0, 1.0] está correto.