El componente de canalización Transform TFX

El componente de canalización Transform TFX realiza ingeniería de características en tf.Examples emitidos desde un componente EjemploGen , utilizando un esquema de datos creado por un componente SchemaGen , y emite tanto un SavedModel como estadísticas sobre datos previos y posteriores a la transformación. Cuando se ejecuta, SavedModel aceptará tf.Examples emitidos desde un componente EjemploGen y emitirá los datos de características transformados.

  • Consume: tf.Examples de un componente de EjemploGen y un esquema de datos de un componente de SchemaGen.
  • Emite: un modelo guardado para un componente de entrenador, estadísticas previas y posteriores a la transformación.

Configurar un componente de transformación

Una vez escrito su preprocessing_fn , debe definirse en un módulo de Python que luego se proporciona al componente Transform como entrada. Transform cargará este módulo y Transform encontrará y utilizará la función denominada preprocessing_fn para construir la canalización de preprocesamiento.

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

Además, es posible que desee proporcionar opciones para el cálculo de estadísticas previas o posteriores a la transformación basadas en TFDV . Para hacerlo, defina un stats_options_updater_fn dentro del mismo módulo.

Transformación y transformación de TensorFlow

Transform hace un uso extensivo de TensorFlow Transform para realizar ingeniería de funciones en su conjunto de datos. TensorFlow Transform es una gran herramienta para transformar datos de características antes de enviarlos a su modelo y como parte del proceso de capacitación. Las transformaciones de características comunes incluyen:

  • Incrustación : convertir características dispersas (como los ID de números enteros producidos por un vocabulario) en características densas al encontrar un mapeo significativo desde el espacio de alta dimensión al espacio de baja dimensión. Consulte la unidad Incrustaciones en el curso intensivo de aprendizaje automático para obtener una introducción a las incrustaciones.
  • Generación de vocabulario : convertir cadenas u otras características no numéricas en números enteros mediante la creación de un vocabulario que asigne cada valor único a un número de identificación.
  • Normalizar valores : transformar características numéricas para que todas caigan dentro de un rango similar.
  • Bucketización : convertir características de valores continuos en características categóricas asignando valores a depósitos discretos.
  • Enriquecimiento de funciones de texto : producción de funciones a partir de datos sin procesar como tokens, n-gramas, entidades, sentimientos, etc., para enriquecer el conjunto de funciones.

TensorFlow Transform brinda soporte para estos y muchos otros tipos de transformaciones:

  • Genere automáticamente un vocabulario a partir de sus datos más recientes.

  • Realice transformaciones arbitrarias en sus datos antes de enviarlos a su modelo. TensorFlow Transform crea transformaciones en el gráfico de TensorFlow para su modelo, de modo que las mismas transformaciones se realicen en el momento del entrenamiento y la inferencia. Puede definir transformaciones que hagan referencia a propiedades globales de los datos, como el valor máximo de una característica en todas las instancias de entrenamiento.

Puede transformar sus datos como desee antes de ejecutar TFX. Pero si lo haces dentro de TensorFlow Transform, las transformaciones pasan a formar parte del gráfico de TensorFlow. Este enfoque ayuda a evitar el sesgo en la capacitación/servicio.

Las transformaciones dentro de su código de modelado utilizan FeatureColumns. Con FeatureColumns, puede definir agrupaciones, integraciones que utilizan vocabularios predefinidos o cualquier otra transformación que se pueda definir sin mirar los datos.

Por el contrario, TensorFlow Transform está diseñado para transformaciones que requieren un paso completo por los datos para calcular valores que no se conocen de antemano. Por ejemplo, la generación de vocabulario requiere una revisión completa de los datos.

Además de calcular valores utilizando Apache Beam, TensorFlow Transform permite a los usuarios incrustar estos valores en un gráfico de TensorFlow, que luego se puede cargar en el gráfico de entrenamiento. Por ejemplo, al normalizar características, la función tft.scale_to_z_score calculará la media y la desviación estándar de una característica, y también una representación, en un gráfico de TensorFlow, de la función que resta la media y divide por la desviación estándar. Al emitir un gráfico de TensorFlow, no solo estadísticas, TensorFlow Transform simplifica el proceso de creación de su canal de preprocesamiento.

Dado que el preprocesamiento se expresa como un gráfico, puede ocurrir en el servidor y se garantiza que será consistente entre el entrenamiento y el servicio. Esta consistencia elimina una fuente de sesgo en la capacitación/servicio.

TensorFlow Transform permite a los usuarios especificar su canal de preprocesamiento utilizando el código de TensorFlow. Esto significa que una tubería se construye de la misma manera que un gráfico de TensorFlow. Si solo se usaran operaciones de TensorFlow en este gráfico, la canalización sería un mapa puro que acepta lotes de entrada y devuelve lotes de salida. Una canalización de este tipo sería equivalente a colocar este gráfico dentro de su input_fn cuando utilice la API tf.Estimator . Para especificar operaciones de paso completo, como el cálculo de cuantiles, TensorFlow Transform proporciona funciones especiales llamadas analyzers que parecen operaciones de TensorFlow, pero que en realidad especifican un cálculo diferido que realizará Apache Beam y la salida se insertará en el gráfico como un constante. Mientras que una operación ordinaria de TensorFlow tomará un solo lote como entrada, realizará algunos cálculos solo en ese lote y emitirá un lote, un analyzer realizará una reducción global (implementada en Apache Beam) en todos los lotes y devolverá el resultado.

Al combinar operaciones ordinarias de TensorFlow y analizadores de TensorFlow Transform, los usuarios pueden crear canalizaciones complejas para preprocesar sus datos. Por ejemplo, la función tft.scale_to_z_score toma un tensor de entrada y devuelve ese tensor normalizado para tener media 0 y varianza 1 . Para ello, llama a los analizadores mean y var internos, que generarán efectivamente constantes en el gráfico iguales a la media y la varianza del tensor de entrada. Luego utilizará las operaciones de TensorFlow para restar la media y dividirla por la desviación estándar.

La transformación de TensorFlow preprocessing_fn

El componente TFX Transform simplifica el uso de Transform al manejar las llamadas API relacionadas con la lectura y escritura de datos, y al escribir el SavedModel de salida en el disco. Como usuario de TFX, solo tiene que definir una única función llamada preprocessing_fn . En preprocessing_fn , define una serie de funciones que manipulan el dictado de entrada de los tensores para producir el dictado de salida de los tensores. Puede encontrar funciones auxiliares como scale_to_0_1 y Compute_and_apply_vocabulary en la API de transformación de TensorFlow o usar funciones normales de TensorFlow como se muestra a continuación.

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

Comprender las entradas a preprocessing_fn

preprocessing_fn describe una serie de operaciones en tensores (es decir, Tensor s, SparseTensor s o RaggedTensor s). Para definir preprocessing_fn correctamente es necesario comprender cómo se representan los datos como tensores. La entrada a preprocessing_fn está determinada por el esquema. Un protocolo Schema finalmente se convierte en una "especificación de función" (a veces llamada "especificación de análisis") que se utiliza para el análisis de datos; consulte más detalles sobre la lógica de conversión aquí .

Usando TensorFlow Transform para manejar etiquetas de cadenas

Por lo general, uno quiere usar TensorFlow Transform para generar un vocabulario y aplicar ese vocabulario para convertir cadenas en números enteros. Al seguir este flujo de trabajo, el input_fn construido en el modelo generará la cadena entera. Sin embargo, las etiquetas son una excepción, porque para que el modelo pueda asignar las etiquetas de salida (enteras) a cadenas, el modelo necesita input_fn para generar una etiqueta de cadena, junto con una lista de posibles valores de la etiqueta. Por ejemplo, si las etiquetas son cat y dog , entonces la salida de input_fn deberían ser estas cadenas sin formato, y las claves ["cat", "dog"] deben pasarse al estimador como parámetro (consulte los detalles a continuación).

Para manejar el mapeo de etiquetas de cadenas a números enteros, debes usar TensorFlow Transform para generar un vocabulario. Demostramos esto en el siguiente fragmento de código:

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)

  ...

La función de preprocesamiento anterior toma la característica de entrada sin formato (que también se devolverá como parte de la salida de la función de preprocesamiento) y llama a tft.vocabulary en ella. Esto da como resultado que se genere un vocabulario para education al que se puede acceder en el modelo.

El ejemplo también muestra cómo transformar una etiqueta y luego generar un vocabulario para la etiqueta transformada. En particular, toma la education de etiquetas sin procesar y convierte todas las etiquetas excepto las 5 principales (por frecuencia) a UNKNOWN , sin convertir la etiqueta a un número entero.

En el código del modelo, al clasificador se le debe proporcionar el vocabulario generado por tft.vocabulary como argumento label_vocabulary . Esto se hace leyendo primero este vocabulario como una lista con una función auxiliar. Esto se muestra en el siguiente fragmento. Tenga en cuenta que el código de ejemplo utiliza la etiqueta transformada analizada anteriormente, pero aquí mostramos el código para usar la etiqueta sin formato.

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,
      ...)

Configuración de estadísticas previas y posteriores a la transformación

Como se mencionó anteriormente, el componente Transform invoca TFDV para calcular estadísticas previas y posteriores a la transformación. TFDV toma como entrada un objeto StatsOptions opcional. Es posible que los usuarios deseen configurar este objeto para habilitar ciertas estadísticas adicionales (por ejemplo, estadísticas de PNL) o para establecer umbrales que se validen (por ejemplo, frecuencia de token mínima/máxima). Para hacerlo, defina stats_options_updater_fn en el archivo del 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

Las estadísticas posteriores a la transformación a menudo se benefician del conocimiento del vocabulario que se utiliza para preprocesar una característica. El nombre del vocabulario al mapeo de ruta se proporciona a StatsOptions (y por lo tanto a TFDV) para cada vocabulario generado por TFT. Además, se pueden agregar asignaciones para vocabularios creados externamente (i) modificando directamente el diccionario vocab_paths dentro de StatsOptions o (ii) usando tft.annotate_asset .