TransformTFXパイプラインコンポーネント

Transform TFX パイプライン コンポーネントは、 SchemaGenコンポーネントによって作成されたデータ スキーマを使用して、 ExampleGenコンポーネントから発行された tf.Examples に対して機能エンジニアリングを実行し、SavedModel と、変換前および変換後のデータの両方に関する統計の両方を発行します。実行されると、SavedModel は ExampleGen コンポーネントから発行された tf.Examples を受け入れ、変換された機能データを発行します。

  • 消費: ExampleGen コンポーネントからの tf.Examples、および SchemaGen コンポーネントからのデータ スキーマ。
  • エミット: トレーナー コンポーネントへの SavedModel、変換前および変換後の統計。

変換コンポーネントの構成

preprocessing_fnを記述したら、python モジュールで定義する必要があります。このモジュールは、入力として Transform コンポーネントに提供されます。このモジュールは変換によってロードされ、 preprocessing_fnという名前の関数が検出され、変換によって使用されて前処理パイプラインが構築されます。

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

さらに、 TFDVベースの変換前または変換後の統計計算にオプションを提供したい場合があります。これを行うには、同じモジュール内でstats_options_updater_fnを定義します。

変換と TensorFlow 変換

Transform は、 TensorFlow Transformを広範囲に使用して、データセットで特徴量エンジニアリングを実行します。 TensorFlow Transform は、特徴データをモデルに渡す前に、トレーニング プロセスの一部として変換するための優れたツールです。一般的な機能変換には次のものがあります。

  • 埋め込み: 高次元空間から低次元空間への意味のあるマッピングを見つけることにより、疎な機能 (語彙によって生成される整数 ID など) を密な機能に変換します。埋め込みの概要については、機械学習クラッシュ コースの埋め込みの単元を参照してください。
  • 語彙の生成: それぞれの一意の値を ID 番号にマップする語彙を作成することにより、文字列またはその他の数値以外の特徴を整数に変換します。
  • 値の正規化: 数値機能を変換して、すべてが同様の範囲内に収まるようにします。
  • バケット化: 個別のバケットに値を割り当てることにより、連続値の特徴をカテゴリ特徴に変換します。
  • テキスト機能の強化 : トークン、n-gram、エンティティ、センチメントなどの生データから機能を生成して、機能セットを強化します。

TensorFlow Transform は、これらおよび他の多くの種類の変換をサポートします。

  • 最新のデータから語彙を自動的に生成します。

  • モデルに送信する前に、データに対して任意の変換を実行します。 TensorFlow Transform は、モデルの TensorFlow グラフに変換を構築するため、トレーニング時と推論時に同じ変換が実行されます。すべてのトレーニング インスタンスにわたる特徴の最大値など、データのグローバル プロパティを参照する変換を定義できます。

TFX を実行する前に、好きなようにデータを変換できます。しかし、TensorFlow Transform 内で行うと、変換は TensorFlow グラフの一部になります。このアプローチは、トレーニング/サービング スキューを回避するのに役立ちます。

モデリング コード内の変換は FeatureColumns を使用します。 FeatureColumns を使用すると、事前定義された語彙を使用するバケット化、整数化、またはデータを見ずに定義できるその他の変換を定義できます。

対照的に、TensorFlow Transform は、事前にわからない値を計算するためにデータを完全に渡す必要がある変換用に設計されています。たとえば、ボキャブラリの生成には、データ全体の完全なパスが必要です。

TensorFlow Transform では、Apache Beam を使用して値を計算するだけでなく、ユーザーがこれらの値を TensorFlow グラフに埋め込むことができ、それをトレーニング グラフに読み込むことができます。たとえば、機能を正規化する場合、 tft.scale_to_z_score関数は機能の平均と標準偏差を計算し、平均を引いて標準偏差で割る関数の TensorFlow グラフでの表現も計算します。 TensorFlow Transform は、統計だけでなく TensorFlow グラフを発行することで、前処理パイプラインの作成プロセスを簡素化します。

前処理はグラフとして表現されるため、サーバー上で発生する可能性があり、トレーニングとサービングの間で一貫性が保証されます。この一貫性により、トレーニング/サービング スキューの 1 つの原因が排除されます。

TensorFlow Transform により、ユーザーは TensorFlow コードを使用して前処理パイプラインを指定できます。これは、パイプラインが TensorFlow グラフと同じ方法で構築されることを意味します。このグラフで TensorFlow ops のみが使用された場合、パイプラインは入力のバッチを受け入れ、出力のバッチを返す純粋なマップになります。このようなパイプラインは、 tf.Estimator API を使用するときにこのグラフをinput_fn内に配置することと同等です。分位数の計算などのフルパス操作を指定するために、TensorFlow Transform は、TensorFlow ops のように見えるanalyzersと呼ばれる特別な関数を提供しますが、実際には、Apache Beam によって実行される遅延計算を指定し、出力をグラフに挿入します。絶え間ない。通常の TensorFlow op は入力として 1 つのバッチを受け取り、そのバッチだけで何らかの計算を実行してバッチを発行しますが、 analyzerはすべてのバッチに対してグローバル削減 (Apache Beam で実装) を実行し、結果を返します。

通常の TensorFlow ops と TensorFlow Transform アナライザーを組み合わせることで、ユーザーは複雑なパイプラインを作成してデータを前処理できます。たとえば、 tft.scale_to_z_score関数は入力テンソルを取り、平均0と分散1を持つように正規化されたテンソルを返します。内部でmeanおよびvarアナライザーを呼び出すことによってこれを行います。これにより、入力テンソルの平均および分散に等しいグラフ内の定数が効果的に生成されます。次に、TensorFlow ops を使用して平均を引き、標準偏差で割ります。

TensorFlow 変換preprocessing_fn

TFX Transform コンポーネントは、データの読み取りと書き込みに関連する API 呼び出しを処理し、出力の SavedModel をディスクに書き込むことによって、Transform の使用を簡素化します。 TFX ユーザーは、 preprocessing_fnという 1 つの関数を定義するだけで済みます。 preprocessing_fnでは、テンソルの入力辞書を操作してテンソルの出力辞書を生成する一連の関数を定義します。 TensorFlow Transform APIの scale_to_0_1 や compute_and_apply_vocabulary などのヘルパー関数を見つけるか、以下に示すように通常の TensorFlow 関数を使用できます。

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

preprocessing_fn への入力を理解する

preprocessing_fnは、テンソル (つまり、 Tensor s、 SparseTensor s、またはRaggedTensor s) に対する一連の操作を記述します。 preprocessing_fnを正しく定義するには、データがテンソルとしてどのように表現されるかを理解する必要があります。 preprocessing_fnへの入力は、スキーマによって決定されます。 Schema protoは最終的に、データ解析に使用される「機能仕様」(「解析仕様」とも呼ばれる) に変換されます。変換ロジックの詳細については、こちらを参照してください。

TensorFlow Transform を使用して文字列ラベルを処理する

通常、TensorFlow Transform を使用して語彙を生成し、その語彙を適用して文字列を整数に変換したいと考えています。このワークフローに従うと、モデルで構築されたinput_fnは整数化された文字列を出力します。ただし、ラベルは例外です。モデルが出力 (整数) ラベルを文字列にマップできるようにするために、モデルは文字列ラベルを出力するためのinput_fnと、ラベルの可能な値のリストを必要とするためです。たとえば、ラベルがcatdogの場合、 input_fnの出力はこれらの生の文字列である必要があり、キー["cat", "dog"]をパラメーターとして推定器に渡す必要があります (以下の詳細を参照)。

文字列ラベルの整数へのマッピングを処理するには、TensorFlow Transform を使用して語彙を生成する必要があります。以下のコード スニペットでこれを示します。

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)

  ...

上記の前処理関数は、生の入力機能 (前処理関数の出力の一部としても返されます) を受け取り、それtft.vocabularyを呼び出します。これにより、モデルでアクセスできるeducation用の語彙が生成されます。

この例では、ラベルを変換してから、変換されたラベルの語彙を生成する方法も示しています。特に、未加工のラベルeducationを取得し、ラベルを整数に変換せずに、(頻度で) 上位 5 つのラベルを除くすべてのラベルをUNKNOWNに変換します。

モデル コードでは、 tft.vocabularyによって生成された語彙をlabel_vocabulary引数として分類子に指定する必要があります。これは、最初にこの語彙をヘルパー関数のリストとして読み取ることによって行われます。これは、以下のスニペットに示されています。サンプルコードは上記の変換されたラベルを使用していますが、ここでは未加工のラベルを使用するコードを示しています。

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

変換前および変換後の統計の構成

前述のように、Transform コンポーネントは TFDV を呼び出して、変換前と変換後の両方の統計を計算します。 TFDV は、オプションのStatsOptionsオブジェクトを入力として受け取ります。ユーザーは、特定の追加の統計 (NLP 統計など) を有効にしたり、検証されるしきい値 (最小/最大トークン頻度など) を設定したりするために、このオブジェクトを構成することができます。これを行うには、モジュール ファイルでstats_options_updater_fnを定義します。

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

変換後の統計は、多くの場合、フィーチャの前処理に使用される語彙の知識から恩恵を受けます。語彙名からパスへのマッピングは、TFT で生成された語彙ごとに StatsOptions (したがって TFDV) に提供されます。さらに、外部で作成された語彙のマッピングは、(i) StatsOptions 内のvocab_paths辞書を直接変更するか、(ii) tft.annotate_assetを使用して追加できます。

Transform TFX パイプライン コンポーネントは、 SchemaGenコンポーネントによって作成されたデータ スキーマを使用して、 ExampleGenコンポーネントから発行された tf.Examples に対して機能エンジニアリングを実行し、SavedModel と、変換前および変換後のデータの両方に関する統計の両方を発行します。実行されると、SavedModel は ExampleGen コンポーネントから発行された tf.Examples を受け入れ、変換された機能データを発行します。

  • 消費: ExampleGen コンポーネントからの tf.Examples、および SchemaGen コンポーネントからのデータ スキーマ。
  • エミット: トレーナー コンポーネントへの SavedModel、変換前および変換後の統計。

変換コンポーネントの構成

preprocessing_fnを記述したら、python モジュールで定義する必要があります。このモジュールは、入力として Transform コンポーネントに提供されます。このモジュールは変換によってロードされ、 preprocessing_fnという名前の関数が検出され、変換によって使用されて前処理パイプラインが構築されます。

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

さらに、 TFDVベースの変換前または変換後の統計計算にオプションを提供したい場合があります。これを行うには、同じモジュール内でstats_options_updater_fnを定義します。

変換と TensorFlow 変換

Transform は、 TensorFlow Transformを広範囲に使用して、データセットで特徴量エンジニアリングを実行します。 TensorFlow Transform は、特徴データをモデルに渡す前に、トレーニング プロセスの一部として変換するための優れたツールです。一般的な機能変換には次のものがあります。

  • 埋め込み: 高次元空間から低次元空間への意味のあるマッピングを見つけることにより、疎な機能 (語彙によって生成される整数 ID など) を密な機能に変換します。埋め込みの概要については、機械学習クラッシュ コースの埋め込みの単元を参照してください。
  • 語彙の生成: それぞれの一意の値を ID 番号にマップする語彙を作成することにより、文字列またはその他の数値以外の特徴を整数に変換します。
  • 値の正規化: 数値機能を変換して、すべてが同様の範囲内に収まるようにします。
  • バケット化: 個別のバケットに値を割り当てることにより、連続値の特徴をカテゴリ特徴に変換します。
  • テキスト機能の強化 : トークン、n-gram、エンティティ、センチメントなどの生データから機能を生成して、機能セットを強化します。

TensorFlow Transform は、これらおよび他の多くの種類の変換をサポートします。

  • 最新のデータから語彙を自動的に生成します。

  • モデルに送信する前に、データに対して任意の変換を実行します。 TensorFlow Transform は、モデルの TensorFlow グラフに変換を構築するため、トレーニング時と推論時に同じ変換が実行されます。すべてのトレーニング インスタンスにわたる特徴の最大値など、データのグローバル プロパティを参照する変換を定義できます。

TFX を実行する前に、好きなようにデータを変換できます。しかし、TensorFlow Transform 内で行うと、変換は TensorFlow グラフの一部になります。このアプローチは、トレーニング/サービング スキューを回避するのに役立ちます。

モデリング コード内の変換は FeatureColumns を使用します。 FeatureColumns を使用すると、事前定義された語彙を使用するバケット化、整数化、またはデータを見ずに定義できるその他の変換を定義できます。

対照的に、TensorFlow Transform は、事前にわからない値を計算するためにデータを完全に渡す必要がある変換用に設計されています。たとえば、ボキャブラリの生成には、データ全体の完全なパスが必要です。

TensorFlow Transform では、Apache Beam を使用して値を計算するだけでなく、ユーザーがこれらの値を TensorFlow グラフに埋め込むことができ、それをトレーニング グラフに読み込むことができます。たとえば、機能を正規化する場合、 tft.scale_to_z_score関数は機能の平均と標準偏差を計算し、平均を引いて標準偏差で割る関数の TensorFlow グラフでの表現も計算します。 TensorFlow Transform は、統計だけでなく TensorFlow グラフを発行することで、前処理パイプラインの作成プロセスを簡素化します。

前処理はグラフとして表現されるため、サーバー上で発生する可能性があり、トレーニングとサービングの間で一貫性が保証されます。この一貫性により、トレーニング/サービング スキューの 1 つの原因が排除されます。

TensorFlow Transform により、ユーザーは TensorFlow コードを使用して前処理パイプラインを指定できます。これは、パイプラインが TensorFlow グラフと同じ方法で構築されることを意味します。このグラフで TensorFlow ops のみが使用された場合、パイプラインは入力のバッチを受け入れ、出力のバッチを返す純粋なマップになります。このようなパイプラインは、 tf.Estimator API を使用するときにこのグラフをinput_fn内に配置することと同等です。分位数の計算などのフルパス操作を指定するために、TensorFlow Transform は、TensorFlow ops のように見えるanalyzersと呼ばれる特別な関数を提供しますが、実際には、Apache Beam によって実行される遅延計算を指定し、出力をグラフに挿入します。絶え間ない。通常の TensorFlow op は入力として 1 つのバッチを受け取り、そのバッチだけで何らかの計算を実行してバッチを発行しますが、 analyzerはすべてのバッチに対してグローバル削減 (Apache Beam で実装) を実行し、結果を返します。

通常の TensorFlow ops と TensorFlow Transform アナライザーを組み合わせることで、ユーザーは複雑なパイプラインを作成してデータを前処理できます。たとえば、 tft.scale_to_z_score関数は入力テンソルを取り、平均0と分散1を持つように正規化されたテンソルを返します。内部でmeanおよびvarアナライザーを呼び出すことによってこれを行います。これにより、入力テンソルの平均および分散に等しいグラフ内の定数が効果的に生成されます。次に、TensorFlow ops を使用して平均を引き、標準偏差で割ります。

TensorFlow 変換preprocessing_fn

TFX Transform コンポーネントは、データの読み取りと書き込みに関連する API 呼び出しを処理し、出力の SavedModel をディスクに書き込むことによって、Transform の使用を簡素化します。 TFX ユーザーは、 preprocessing_fnという 1 つの関数を定義するだけで済みます。 preprocessing_fnでは、テンソルの入力辞書を操作してテンソルの出力辞書を生成する一連の関数を定義します。 TensorFlow Transform APIの scale_to_0_1 や compute_and_apply_vocabulary などのヘルパー関数を見つけるか、以下に示すように通常の TensorFlow 関数を使用できます。

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

preprocessing_fn への入力を理解する

preprocessing_fnは、テンソル (つまり、 Tensor s、 SparseTensor s、またはRaggedTensor s) に対する一連の操作を記述します。 preprocessing_fnを正しく定義するには、データがテンソルとしてどのように表現されるかを理解する必要があります。 preprocessing_fnへの入力は、スキーマによって決定されます。 Schema protoは最終的に、データ解析に使用される「機能仕様」(「解析仕様」とも呼ばれる) に変換されます。変換ロジックの詳細については、こちらを参照してください。

TensorFlow Transform を使用して文字列ラベルを処理する

通常、TensorFlow Transform を使用して語彙を生成し、その語彙を適用して文字列を整数に変換したいと考えています。このワークフローに従うと、モデルで構築されたinput_fnは整数化された文字列を出力します。ただし、ラベルは例外です。モデルが出力 (整数) ラベルを文字列にマップできるようにするために、モデルは文字列ラベルを出力するためのinput_fnと、ラベルの可能な値のリストを必要とするためです。たとえば、ラベルがcatdogの場合、 input_fnの出力はこれらの生の文字列である必要があり、キー["cat", "dog"]をパラメーターとして推定器に渡す必要があります (以下の詳細を参照)。

文字列ラベルの整数へのマッピングを処理するには、TensorFlow Transform を使用して語彙を生成する必要があります。以下のコード スニペットでこれを示します。

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)

  ...

上記の前処理関数は、生の入力機能 (前処理関数の出力の一部としても返されます) を受け取り、それtft.vocabularyを呼び出します。これにより、モデルでアクセスできるeducation用の語彙が生成されます。

この例では、ラベルを変換してから、変換されたラベルの語彙を生成する方法も示しています。特に、未加工のラベルeducationを取得し、ラベルを整数に変換せずに、(頻度で) 上位 5 つのラベルを除くすべてのラベルをUNKNOWNに変換します。

モデル コードでは、 tft.vocabularyによって生成された語彙をlabel_vocabulary引数として分類子に指定する必要があります。これは、最初にこの語彙をヘルパー関数のリストとして読み取ることによって行われます。これは、以下のスニペットに示されています。サンプルコードは上記の変換されたラベルを使用していますが、ここでは未加工のラベルを使用するコードを示しています。

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

変換前および変換後の統計の構成

前述のように、Transform コンポーネントは TFDV を呼び出して、変換前と変換後の両方の統計を計算します。 TFDV は、オプションのStatsOptionsオブジェクトを入力として受け取ります。ユーザーは、特定の追加の統計 (NLP 統計など) を有効にしたり、検証されるしきい値 (最小/最大トークン頻度など) を設定したりするために、このオブジェクトを構成することができます。これを行うには、モジュール ファイルでstats_options_updater_fnを定義します。

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

変換後の統計は、多くの場合、フィーチャの前処理に使用される語彙の知識から恩恵を受けます。語彙名からパスへのマッピングは、TFT で生成された語彙ごとに StatsOptions (したがって TFDV) に提供されます。さらに、外部で作成された語彙のマッピングは、(i) StatsOptions 内のvocab_paths辞書を直接変更するか、(ii) tft.annotate_assetを使用して追加できます。