Il componente della pipeline Trasforma TFX

Il componente della pipeline Transform TFX esegue l'ingegneria delle funzionalità su tf.Examples emessi da un componente ExampleGen , utilizzando uno schema di dati creato da un componente SchemaGen ed emette sia un SavedModel che statistiche sui dati sia pre-trasformazione che post-trasformazione. Quando viene eseguito, il SavedModel accetterà tf.Examples emessi da un componente ExampleGen ed emetterà i dati delle caratteristiche trasformate.

  • Consuma: tf.Examples da un componente ExampleGen e uno schema di dati da un componente SchemaGen.
  • Emette: un modello salvato in un componente Trainer, statistiche pre-trasformazione e post-trasformazione.

Configurazione di un componente di trasformazione

Una volta che il tuo preprocessing_fn è stato scritto, deve essere definito in un modulo Python che viene quindi fornito al componente Transform come input. Questo modulo verrà caricato da transform e la funzione denominata preprocessing_fn verrà trovata e utilizzata da Transform per costruire la pipeline di preelaborazione.

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

Inoltre, potresti voler fornire opzioni per il calcolo delle statistiche pre-trasformazione o post-trasformazione basato su TFDV . Per fare ciò, definisci un stats_options_updater_fn all'interno dello stesso modulo.

Trasforma e trasforma TensorFlow

Transform fa ampio uso di TensorFlow Transform per eseguire l'ingegneria delle funzionalità sul tuo set di dati. TensorFlow Transform è un ottimo strumento per trasformare i dati delle caratteristiche prima che vadano al modello e come parte del processo di addestramento. Le trasformazioni delle caratteristiche comuni includono:

  • Incorporamento : convertire le caratteristiche sparse (come gli ID interi prodotti da un vocabolario) in caratteristiche dense trovando una mappatura significativa dallo spazio ad alta dimensione allo spazio a bassa dimensione. Per un'introduzione agli incorporamenti, vedere l' unità Incorporamenti nel corso di arresto anomalo dell'apprendimento automatico .
  • Generazione del vocabolario : convertire stringhe o altre caratteristiche non numeriche in numeri interi creando un vocabolario che associa ogni valore univoco a un numero ID.
  • Normalizzazione dei valori : trasformazione delle caratteristiche numeriche in modo che rientrino tutte in un intervallo simile.
  • Bucketizzazione : conversione di funzionalità a valore continuo in funzionalità categoriali assegnando valori a bucket discreti.
  • Arricchimento delle funzionalità di testo : produzione di funzionalità da dati grezzi come token, n-grammi, entità, sentiment, ecc., Per arricchire il set di funzionalità.

TensorFlow Transform fornisce supporto per questi e molti altri tipi di trasformazioni:

  • Genera automaticamente un vocabolario dai tuoi ultimi dati.

  • Esegui trasformazioni arbitrarie sui tuoi dati prima di inviarli al tuo modello. TensorFlow Transform crea trasformazioni nel grafico TensorFlow per il tuo modello in modo che le stesse trasformazioni vengano eseguite al momento dell'addestramento e dell'inferenza. Puoi definire trasformazioni che fanno riferimento a proprietà globali dei dati, come il valore massimo di una funzionalità in tutte le istanze di addestramento.

Puoi trasformare i tuoi dati come preferisci prima di eseguire TFX. Ma se lo fai all'interno di TensorFlow Transform, le trasformazioni diventano parte del grafico TensorFlow. Questo approccio aiuta a evitare lo sbilanciamento dell'allenamento/servizio.

Le trasformazioni all'interno del codice di modellazione utilizzano FeatureColumns. Utilizzando FeatureColumns, puoi definire bucketization, integrazioni che utilizzano vocabolari predefiniti o qualsiasi altra trasformazione che può essere definita senza guardare i dati.

Al contrario, TensorFlow Transform è progettato per trasformazioni che richiedono un passaggio completo dei dati per calcolare valori non noti in anticipo. Ad esempio, la generazione del vocabolario richiede un passaggio completo sui dati.

Oltre a calcolare i valori utilizzando Apache Beam, TensorFlow Transform consente agli utenti di incorporare questi valori in un grafico TensorFlow, che può quindi essere caricato nel grafico di addestramento. Ad esempio, durante la normalizzazione delle caratteristiche, la funzione tft.scale_to_z_score calcolerà la media e la deviazione standard di una caratteristica e anche una rappresentazione, in un grafico TensorFlow, della funzione che sottrae la media e la divide per la deviazione standard. Emettendo un grafico TensorFlow, non solo statistiche, TensorFlow Transform semplifica il processo di creazione della pipeline di preelaborazione.

Poiché la preelaborazione è espressa sotto forma di grafico, può avvenire sul server ed è garantito che sia coerente tra l'addestramento e il servizio. Questa coerenza elimina una fonte di distorsione di addestramento/servizio.

TensorFlow Transform consente agli utenti di specificare la pipeline di preelaborazione utilizzando il codice TensorFlow. Ciò significa che una pipeline viene costruita allo stesso modo di un grafico TensorFlow. Se in questo grafico venissero utilizzate solo le operazioni TensorFlow, la pipeline sarebbe una mappa pura che accetta batch di input e restituisce batch di output. Tale pipeline equivarrebbe a posizionare questo grafico all'interno input_fn quando si utilizza l'API tf.Estimator . Per specificare operazioni full-pass come il calcolo dei quantili, TensorFlow Transform fornisce funzioni speciali chiamate analyzers che appaiono come TensorFlow ops, ma in realtà specificano un calcolo differito che verrà eseguito da Apache Beam e l'output inserito nel grafico come costante. Mentre una normale operazione TensorFlow prenderà un singolo batch come input, eseguirà alcuni calcoli solo su quel batch ed emetterà un batch, un analyzer eseguirà una riduzione globale (implementata in Apache Beam) su tutti i batch e restituirà il risultato.

Combinando le normali operazioni TensorFlow e gli analizzatori TensorFlow Transform, gli utenti possono creare pipeline complesse per preelaborare i propri dati. Ad esempio, la funzione tft.scale_to_z_score prende un tensore di input e restituisce quel tensore normalizzato con media 0 e varianza 1 . Lo fa chiamando sotto il cofano gli analizzatori di mean e var , che genereranno effettivamente costanti nel grafico uguali alla media e alla varianza del tensore di input. Utilizzerà quindi le operazioni TensorFlow per sottrarre la media e dividere per la deviazione standard.

Il TensorFlow Transform preprocessing_fn

Il componente TFX Transform semplifica l'uso di Transform gestendo le chiamate API relative alla lettura e scrittura dei dati e scrivendo l'output SavedModel su disco. Come utente TFX, devi solo definire una singola funzione chiamata preprocessing_fn . In preprocessing_fn si definisce una serie di funzioni che manipolano l'input dict dei tensori per produrre l'output dict dei tensori. Puoi trovare funzioni di supporto come scale_to_0_1 e compute_and_apply_vocabulary nell'API di trasformazione di TensorFlow o utilizzare le normali funzioni di TensorFlow come mostrato di seguito.

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

Comprendere gli input per preprocessing_fn

Il preprocessing_fn descrive una serie di operazioni sui tensori (cioè Tensor s o SparseTensor s) e quindi per scrivere il preprocessing_fn correttamente è necessario capire come i propri dati vengono rappresentati come tensori. L'input per preprocessing_fn è determinato dallo schema. Un prototipo di Schema contiene un elenco di Feature e Transform le converte in una "specifica di funzionalità" (a volte chiamata "specifica di analisi") che è un dict le cui chiavi sono nomi di funzionalità e i cui valori sono uno di FixedLenFeature o VarLenFeature (o altro opzioni non utilizzate da TensorFlow Transform).

Le regole per dedurre una specifica di funzionalità dallo Schema sono

  • Ogni feature con shape set risulterà in un tf.FixedLenFeature con shape e default_value=None . presence.min_fraction deve essere 1 in caso contrario e risulterà un errore, poiché quando non esiste un valore predefinito, un tf.FixedLenFeature richiede che la funzione sia sempre presente.
  • Ogni feature con shape non impostata risulterà in una VarLenFeature .
  • Ogni sparse_feature risulterà in una tf.SparseFeature cui size e is_sorted sono determinate dai campi fixed_shape e is_sorted del messaggio SparseFeature .
  • Le funzionalità utilizzate come index_feature o value_feature di sparse_feature non avranno una propria voce generata nella specifica della funzionalità.
  • La corrispondenza tra il campo type della feature (o la caratteristica dei valori di un prototipo sparse_feature ) e il dtype della specifica della caratteristica è data dalla tabella seguente:
type dtype
schema_pb2.INT tf.int64
schema_pb2.FLOAT tf.float32
schema_pb2.BYTES tf.string

Utilizzo di TensorFlow Transform per gestire le etichette delle stringhe

Di solito si vuole usare TensorFlow Transform sia per generare un vocabolario sia per applicare quel vocabolario per convertire le stringhe in numeri interi. Quando si segue questo flusso di lavoro, l' input_fn costruito nel modello produrrà la stringa intera. Tuttavia, le etichette sono un'eccezione, perché affinché il modello sia in grado di mappare le etichette di output (intere) alle stringhe, il modello ha bisogno di input_fn per produrre un'etichetta di stringa, insieme a un elenco di possibili valori dell'etichetta. Ad esempio, se le etichette sono cat e dog , l'output di input_fn dovrebbe essere queste stringhe grezze e le chiavi ["cat", "dog"] devono essere passate allo stimatore come parametro (vedere i dettagli di seguito).

Per gestire la mappatura delle etichette delle stringhe in numeri interi, dovresti usare TensorFlow Transform per generare un vocabolario. Lo dimostriamo nello snippet di codice qui sotto:

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 funzione di preelaborazione sopra prende la funzione di input grezzo (che verrà anche restituita come parte dell'output della funzione di preelaborazione) e chiama tft.vocabulary su di essa. Ciò si traduce nella generazione di un vocabolario per education a cui è possibile accedere nel modello.

L'esempio mostra anche come trasformare un'etichetta e quindi generare un vocabolario per l'etichetta trasformata. In particolare prende l' education dell'etichetta grezza e converte tutte le etichette tranne le prime 5 (per frequenza) in UNKNOWN , senza convertire l'etichetta in un numero intero.

Nel codice del modello, al classificatore deve essere assegnato il vocabolario generato da tft.vocabulary come argomento label_vocabulary . Questo viene fatto leggendo prima questo vocabolario come un elenco con una funzione di supporto. Questo è mostrato nello snippet di seguito. Nota che il codice di esempio utilizza l'etichetta trasformata discussa sopra, ma qui mostriamo il codice per l'utilizzo dell'etichetta grezza.

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

Configurazione delle statistiche pre-trasformazione e post-trasformazione

Come accennato in precedenza, il componente Transform invoca TFDV per calcolare sia le statistiche pre-trasformazione che post-trasformazione. TFDV accetta come input un oggetto StatsOptions opzionale. Gli utenti potrebbero voler configurare questo oggetto per abilitare determinate statistiche aggiuntive (es. statistiche NLP) o per impostare soglie che vengono convalidate (es. frequenza minima / massima del token). Per fare ciò, definisci una stats_options_updater_fn nel file del modulo.

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

Le statistiche post-trasformazione spesso traggono vantaggio dalla conoscenza del vocabolario utilizzato per la preelaborazione di una funzione. Il nome del vocabolario per la mappatura del percorso viene fornito a StatsOptions (e quindi TFDV) per ogni vocabolario generato da TFT. Inoltre, le mappature per i vocabolari creati esternamente possono essere aggiunte (i) modificando direttamente il dizionario vocab_paths all'interno di StatsOptions o (ii) usando tft.annotate_asset .