<jupyter_start><jupyter_text>Copyright 2021 The TensorFlow Authors.<jupyter_code>#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.<jupyter_output><empty_output><jupyter_text>TFX Keras コンポーネントのチュートリアル***TensorFlow Extended (TFX) の各コンポーネントの紹介*** 注：この例は、Jupyter スタイルのノートブックで今すぐ実行できます。セットアップは必要ありません。「Google Colab で実行」をクリックするだけです TensorFlow.org で表示 Google Colab で実行 GitHub でソースを表示 ノートブックをダウンロード この Colab ベースのチュートリアルでは、TensorFlow Extended (TFX) のそれぞれの組み込みコンポーネントをインタラクティブに説明します。ここではデータの取り込みからモデルのプッシュ、サービングまで、エンド ツー エンドの機械学習パイプラインのすべてのステップを見ていきます。完了したら、このノートブックのコンテンツを TFX パイプライン ソース コードとして自動的にエクスポートできます。これは、Apache Airflow および Apache Beam とオーケストレーションできます。注意: このノートブックは、TFX パイプラインでのネイティブ Keras モデルの使用を示しています。**TFX は TensorFlow 2 バージョンの Keras のみをサポートします**。  背景情報このノートブックは、Jupyter/Colab 環境で TFX を使用する方法を示しています。 ここでは、インタラクティブなノートブックでシカゴのタクシーの例を見ていきます。TFX パイプラインの構造に慣れるのには、インタラクティブなノートブックで作業するのが便利です。独自のパイプラインを軽量の開発環境として開発する場合にも役立ちますが、インタラクティブ ノートブックのオーケストレーションとメタデータ アーティファクトへのアクセス方法には違いがあるので注意してください。 オーケストレーションTFX の実稼働デプロイメントでは、Apache Airflow、Kubeflow Pipelines、Apache Beam などのオーケストレーターを使用して、TFX コンポーネントの事前定義済みパイプライン グラフをオーケストレーションします。インタラクティブなノートブックでは、ノートブック自体がオーケストレーターであり、ノートブック セルを実行するときにそれぞれの TFX コンポーネントを実行します。 メタデータTFX の実稼働デプロイメントでは、ML Metadata（MLMD）API を介してメタデータにアクセスします。MLMD は、メタデータ プロパティを MySQL や SQLite などのデータベースに格納し、メタデータ ペイロードをファイル システムなどの永続ストアに保存します。インタラクティブなノートブックでは、プロパティとペイロードの両方が、Jupyter ノートブックまたは Colab サーバーの `/tmp` ディレクトリにあるエフェメラル SQLite データベースに保存されます。  セットアップまず、必要なパッケージをインストールしてインポートし、パスを設定して、データをダウンロードします。  Pip のアップグレードローカルで実行する場合にシステム Pipをアップグレードしないようにするには、Colab で実行していることを確認してください。もちろん、ローカルシステムは個別にアップグレードできます。<jupyter_code>try:
  import colab
  !pip install --upgrade pip
except:
  pass<jupyter_output><empty_output><jupyter_text>TFX をインストールする**注：Google Colab では、パッケージが更新されるため、このセルを初めて実行するときに、ランタイムを再起動する必要があります（[ランタイム]&gt; [ランタイムの再起動...]）。**<jupyter_code>!pip install -U tfx<jupyter_output><empty_output><jupyter_text>ランタイムを再起動しましたか？Google Colab を使用している場合は、上記のセルを初めて実行するときにランタイムを再起動する必要があります（[ランタイム]&gt; [ランタイムの再起動...]）。 これは、Colab がパッケージを読み込むために必要ですです。  パッケージをインポートする標準の TFX コンポーネント クラスを含む必要なパッケージをインポートします。<jupyter_code>import os
import pprint
import tempfile
import urllib

import absl
import tensorflow as tf
import tensorflow_model_analysis as tfma
tf.get_logger().propagate = False
pp = pprint.PrettyPrinter()

from tfx import v1 as tfx
from tfx.orchestration.experimental.interactive.interactive_context import InteractiveContext

%load_ext tfx.orchestration.experimental.interactive.notebook_extensions.skip<jupyter_output><empty_output><jupyter_text>ライブラリのバージョンを確認します。<jupyter_code>print('TensorFlow version: {}'.format(tf.__version__))
print('TFX version: {}'.format(tfx.__version__))<jupyter_output><empty_output><jupyter_text>パイプライン パスを設定<jupyter_code># This is the root directory for your TFX pip package installation.
_tfx_root = tfx.__path__[0]

# This is the directory containing the TFX Chicago Taxi Pipeline example.
_taxi_root = os.path.join(_tfx_root, 'examples/chicago_taxi_pipeline')

# This is the path where your model will be pushed for serving.
_serving_model_dir = os.path.join(
    tempfile.mkdtemp(), 'serving_model/taxi_simple')

# Set up logging.
absl.logging.set_verbosity(absl.logging.INFO)<jupyter_output><empty_output><jupyter_text>サンプルデータのダウンロードTFX パイプラインで使用するサンプル データセットをダウンロードします。使用しているデータセットは、シカゴ市がリリースした [タクシートリップデータセット](https://data.cityofchicago.org/Transportation/Taxi-Trips/wrvz-psew)です。 このデータセットの列は次のとおりです。pickup_community_areafaretrip_start_monthtrip_start_hourtrip_start_daytrip_start_timestamppickup_latitudepickup_longitudedropoff_latitudedropoff_longitudetrip_milespickup_census_tractdropoff_census_tractpayment_typecompanytrip_secondsdropoff_community_areatipsこのデータセットを使用して、タクシー乗車の`tips`を予測するモデルを構築します。<jupyter_code>_data_root = tempfile.mkdtemp(prefix='tfx-data')
DATA_PATH = 'https://raw.githubusercontent.com/tensorflow/tfx/master/tfx/examples/chicago_taxi_pipeline/data/simple/data.csv'
_data_filepath = os.path.join(_data_root, "data.csv")
urllib.request.urlretrieve(DATA_PATH, _data_filepath)<jupyter_output><empty_output><jupyter_text>CSV ファイルを見てみましょう。<jupyter_code>!head {_data_filepath}<jupyter_output><empty_output><jupyter_text>*注：このWeb サイトは、シカゴ市の公式 Web サイト www.cityofchicago.org で公開されたデータを変更して使用するアプリケーションを提供します。シカゴ市は、この Web サイトで提供されるデータの内容、正確性、適時性、または完全性について一切の表明を行いません。この Web サイトで提供されるデータは、いつでも変更される可能性があります。かかる Web サイトで提供されるデータはユーザーの自己責任で利用されるものとします。*  InteractiveContext を作成する最後に、このノートブックで TFX コンポーネントをインタラクティブに実行できるようにする InteractiveContext を作成します。<jupyter_code># Here, we create an InteractiveContext using default parameters. This will
# use a temporary directory with an ephemeral ML Metadata database instance.
# To use your own pipeline root or database, the optional properties
# `pipeline_root` and `metadata_connection_config` may be passed to
# InteractiveContext. Calls to InteractiveContext are no-ops outside of the
# notebook.
context = InteractiveContext()<jupyter_output><empty_output><jupyter_text>TFX コンポーネントをインタラクティブに実行する次のセルでは、TFX コンポーネントを 1 つずつ作成し、それぞれを実行して、出力アーティファクトを視覚化します。  ExampleGen`ExampleGen` コンポーネントは通常、TFX パイプラインの先頭にあり、以下を実行します。1. データをトレーニング セットと評価セットに分割します (デフォルトでは、2/3 トレーニング + 1/3 評価)。2. データを `tf.Example` 形式に変換します。 (詳細は[こちら](https://www.tensorflow.org/tutorials/load_data/tfrecord))3. 他のコンポーネントがアクセスできるように、データを `_tfx_root` ディレクトリにコピーします。`ExampleGen` は、データソースへのパスを入力として受け取ります。 ここでは、これはダウンロードした CSV を含む `_data_root` パスです。注意: このノートブックでは、コンポーネントを 1 つずつインスタンス化し、`InteractiveContext.run()` で実行しますが、実稼働環境では、すべてのコンポーネントを事前に `Pipeline`で指定して、オーケストレーターに渡します（[TFX パイプライン ガイドの構築](https://www.tensorflow.org/tfx/guide/build_tfx_pipeline)を参照してください）。<jupyter_code>example_gen = tfx.components.CsvExampleGen(input_base=_data_root)
context.run(example_gen)<jupyter_output><empty_output><jupyter_text>`ExampleGen`の出力アーティファクトを調べてみましょう。このコンポーネントは、トレーニングサンプルと評価サンプルの 2 つのアーティファクトを生成します。<jupyter_code>artifact = example_gen.outputs['examples'].get()[0]
print(artifact.split_names, artifact.uri)<jupyter_output><empty_output><jupyter_text>また、最初の 3 つのトレーニングサンプルも見てみます。<jupyter_code># Get the URI of the output artifact representing the training examples, which is a directory
train_uri = os.path.join(example_gen.outputs['examples'].get()[0].uri, 'Split-train')

# Get the list of files in this directory (all compressed TFRecord files)
tfrecord_filenames = [os.path.join(train_uri, name)
                      for name in os.listdir(train_uri)]

# Create a `TFRecordDataset` to read these files
dataset = tf.data.TFRecordDataset(tfrecord_filenames, compression_type="GZIP")

# Iterate over the first 3 records and decode them.
for tfrecord in dataset.take(3):
  serialized_example = tfrecord.numpy()
  example = tf.train.Example()
  example.ParseFromString(serialized_example)
  pp.pprint(example)<jupyter_output><empty_output><jupyter_text>`ExampleGen`がデータの取り込みを完了したので、次のステップ、データ分析に進みます。  StatisticsGen`StatisticsGen`コンポーネントは、データ分析用のデータセットの統計を計算し、ダウンストリームのコンポーネントで使用します。これは、[TensorFlow Data Validation](https://www.tensorflow.org/tfx/data_validation/get_started) ライブラリを使用します。`StatisticsGen`コンポーネントは、データ分析用のデータセットの統計を計算し、ダウンストリーム コンポーネントで使用します。<jupyter_code>statistics_gen = tfx.components.StatisticsGen(
    examples=example_gen.outputs['examples'])
context.run(statistics_gen)<jupyter_output><empty_output><jupyter_text>`StatisticsGen` の実行が完了すると、出力された統計を視覚化できます。 色々なプロットを試してみてください！<jupyter_code>context.show(statistics_gen.outputs['statistics'])<jupyter_output><empty_output><jupyter_text>SchemaGen`SchemaGen` コンポーネントは、データ統計に基づいてスキーマを生成します。（スキーマは、データセット内の特徴の予想される境界、タイプ、プロパティを定義します。）また、[TensorFlow データ検証](https://www.tensorflow.org/tfx/data_validation/get_started)ライブラリも使用します。注意: 生成されたスキーマはベストエフォートのもので、データの基本的なプロパティだけを推論しようとします。確認し、必要に応じて修正する必要があります。`SchemaGen` は、`StatisticsGen` で生成した統計を入力として受け取り、デフォルトでトレーニング分割を参照します。<jupyter_code>schema_gen = tfx.components.SchemaGen(
    statistics=statistics_gen.outputs['statistics'],
    infer_feature_shape=False)
context.run(schema_gen)<jupyter_output><empty_output><jupyter_text>`SchemaGen` の実行が完了すると、生成されたスキーマをテーブルとして視覚化できます。<jupyter_code>context.show(schema_gen.outputs['schema'])<jupyter_output><empty_output><jupyter_text>データセットのそれぞれの特徴は、スキーマ テーブルのプロパティの横に行として表示されます。スキーマは、ドメインとして示される、カテゴリ特徴が取るすべての値もキャプチャします。スキーマの詳細については、[SchemaGen のドキュメント](https://www.tensorflow.org/tfx/guide/schemagen)をご覧ください。  ExampleValidator`ExampleValidator` コンポーネントは、スキーマで定義された期待に基づいて、データの異常を検出します。また、[TensorFlow Data Validation](https://www.tensorflow.org/tfx/data_validation/get_started) ライブラリも使用します。`ExampleValidator` は、`Statistics Gen{/code 1} からの統計と SchemaGen` からのスキーマを入力として受け取ります。<jupyter_code>example_validator = tfx.components.ExampleValidator(
    statistics=statistics_gen.outputs['statistics'],
    schema=schema_gen.outputs['schema'])
context.run(example_validator)<jupyter_output><empty_output><jupyter_text>`ExampleValidator` の実行が完了すると、異常をテーブルとして視覚化できます。<jupyter_code>context.show(example_validator.outputs['anomalies'])<jupyter_output><empty_output><jupyter_text>異常テーブルでは、異常がないことがわかります。これは、分析した最初のデータセットで、スキーマはこれに合わせて調整されているため、異常がないことが予想されます。このスキーマを確認する必要があります。予期されないものは、データに異常があることを意味します。確認されたスキーマを使用して将来のデータを保護できます。ここで生成された異常は、モデルのパフォーマンスをデバッグし、データが時間の経過とともにどのように変化するかを理解し、データ エラーを特定するために使用できます。  変換`Transform`コンポーネントは、トレーニングとサービングの両方で特徴量エンジニアリングを実行します。これは、 [TensorFlow Transform](https://www.tensorflow.org/tfx/transform/get_started) ライブラリを使用します。`Transform`は、`ExampleGen`からのデータ、`SchemaGen`からのスキーマ、ユーザー定義の Transform コードを含むモジュールを入力として受け取ります。以下のユーザー定義の Transform コードの例を見てみましょう（TensorFlow Transform API の概要については、[チュートリアルを参照してください](https://www.tensorflow.org/tfx/tutorials/transform/simple)）。まず、特徴量エンジニアリングのいくつかの定数を定義します。注意: `%%writefile` セル マジックは、セルの内容をディスク上の`.py`ファイルとして保存します。これにより、`Transform` コンポーネントはコードをモジュールとして読み込むことができます。<jupyter_code>_taxi_constants_module_file = 'taxi_constants.py'
%%writefile {_taxi_constants_module_file}

# Categorical features are assumed to each have a maximum value in the dataset.
MAX_CATEGORICAL_FEATURE_VALUES = [24, 31, 12]

CATEGORICAL_FEATURE_KEYS = [
    'trip_start_hour', 'trip_start_day', 'trip_start_month',
    'pickup_census_tract', 'dropoff_census_tract', 'pickup_community_area',
    'dropoff_community_area'
]

DENSE_FLOAT_FEATURE_KEYS = ['trip_miles', 'fare', 'trip_seconds']

# Number of buckets used by tf.transform for encoding each feature.
FEATURE_BUCKET_COUNT = 10

BUCKET_FEATURE_KEYS = [
    'pickup_latitude', 'pickup_longitude', 'dropoff_latitude',
    'dropoff_longitude'
]

# Number of vocabulary terms used for encoding VOCAB_FEATURES by tf.transform
VOCAB_SIZE = 1000

# Count of out-of-vocab buckets in which unrecognized VOCAB_FEATURES are hashed.
OOV_SIZE = 10

VOCAB_FEATURE_KEYS = [
    'payment_type',
    'company',
]

# Keys
LABEL_KEY = 'tips'
FARE_KEY = 'fare'

def transformed_name(key):
  return key + '_xf'<jupyter_output><empty_output><jupyter_text>次に、生データを入力として受け取り、モデルがトレーニングできる変換された特徴量を返す {code 0}preprocessing _fn を記述します。<jupyter_code>_taxi_transform_module_file = 'taxi_transform.py'
%%writefile {_taxi_transform_module_file}

import tensorflow as tf
import tensorflow_transform as tft

import taxi_constants

_DENSE_FLOAT_FEATURE_KEYS = taxi_constants.DENSE_FLOAT_FEATURE_KEYS
_VOCAB_FEATURE_KEYS = taxi_constants.VOCAB_FEATURE_KEYS
_VOCAB_SIZE = taxi_constants.VOCAB_SIZE
_OOV_SIZE = taxi_constants.OOV_SIZE
_FEATURE_BUCKET_COUNT = taxi_constants.FEATURE_BUCKET_COUNT
_BUCKET_FEATURE_KEYS = taxi_constants.BUCKET_FEATURE_KEYS
_CATEGORICAL_FEATURE_KEYS = taxi_constants.CATEGORICAL_FEATURE_KEYS
_FARE_KEY = taxi_constants.FARE_KEY
_LABEL_KEY = taxi_constants.LABEL_KEY
_transformed_name = taxi_constants.transformed_name


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:
    # Preserve this feature as a dense float, setting nan's to the mean.
    outputs[_transformed_name(key)] = tft.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)] = tft.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)] = tft.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.math.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


def _fill_in_missing(x):
  """Replace missing values in a SparseTensor.
  Fills in missing values of `x` with '' or 0, and converts to a dense tensor.
  Args:
    x: A `SparseTensor` of rank 2.  Its dense shape should have size at most 1
      in the second dimension.
  Returns:
    A rank 1 tensor where missing values of `x` have been filled in.
  """
  if not isinstance(x, tf.sparse.SparseTensor):
    return x

  default_value = '' if x.dtype == tf.string else 0
  return tf.squeeze(
      tf.sparse.to_dense(
          tf.SparseTensor(x.indices, x.values, [x.dense_shape[0], 1]),
          default_value),
      axis=1)<jupyter_output><empty_output><jupyter_text>次に、この特徴量エンジニアリング コードを `Transform`コンポーネントに渡し、実行してデータを変換します。<jupyter_code>transform = tfx.components.Transform(
    examples=example_gen.outputs['examples'],
    schema=schema_gen.outputs['schema'],
    module_file=os.path.abspath(_taxi_transform_module_file))
context.run(transform)<jupyter_output><empty_output><jupyter_text>`Transform`の出力アーティファクトを調べてみましょう。このコンポーネントは、2 種類の出力を生成します。- `transform_graph` は、前処理演算を実行できるグラフです (このグラフは、サービングモデルと評価モデルに含まれます)。- `transformed_examples`は前処理されたトレーニングおよび評価データを表します。<jupyter_code>transform.outputs<jupyter_output><empty_output><jupyter_text>`transform_graph` アーティファクトを見てみましょう。これは、3 つのサブディレクトリを含むディレクトリを指しています。<jupyter_code>train_uri = transform.outputs['transform_graph'].get()[0].uri
os.listdir(train_uri)<jupyter_output><empty_output><jupyter_text>`transformed_metadata` サブディレクトリには、前処理されたデータのスキーマが含まれています。`transform_fn`サブディレクトリには、実際の前処理グラフが含まれています。`metadata`サブディレクトリには、元のデータのスキーマが含まれています。また、最初の 3 つの変換された例も見てみます。<jupyter_code># Get the URI of the output artifact representing the transformed examples, which is a directory
train_uri = os.path.join(transform.outputs['transformed_examples'].get()[0].uri, 'Split-train')

# Get the list of files in this directory (all compressed TFRecord files)
tfrecord_filenames = [os.path.join(train_uri, name)
                      for name in os.listdir(train_uri)]

# Create a `TFRecordDataset` to read these files
dataset = tf.data.TFRecordDataset(tfrecord_filenames, compression_type="GZIP")

# Iterate over the first 3 records and decode them.
for tfrecord in dataset.take(3):
  serialized_example = tfrecord.numpy()
  example = tf.train.Example()
  example.ParseFromString(serialized_example)
  pp.pprint(example)<jupyter_output><empty_output><jupyter_text>`Transform`コンポーネントがデータを特徴量に変換したら、次にモデルをトレーニングします。  トレーナー`Trainer`コンポーネントは、TensorFlow で定義したモデルをトレーニングします。デフォルトでは、Trainer は Estimator API をサポートします。Keras API を使用するには、トレーナーのコンストラクターで`custom_executor_spec=executor_spec.ExecutorClassSpec(GenericExecutor)`をセットアップして [Generic Trainer](https://github.com/tensorflow/community/blob/master/rfcs/20200117-tfx-generic-trainer.md) を指定する必要があります。`Trainer` は、`SchemaGen`からのスキーマ、`Transform`からの変換されたデータとグラフ、トレーニング パラメータ、およびユーザー定義されたモデル コードを含むモジュールを入力として受け取ります。以下のユーザー定義モデル コードの例を見てみましょう（TensorFlow Keras API の概要については、[チュートリアルを参照してください](https://www.tensorflow.org/guide/keras)）。<jupyter_code>_taxi_trainer_module_file = 'taxi_trainer.py'
%%writefile {_taxi_trainer_module_file}

from typing import List, Text

import os
import absl
import datetime
import tensorflow as tf
import tensorflow_transform as tft

from tfx import v1 as tfx
from tfx_bsl.public import tfxio

import taxi_constants

_DENSE_FLOAT_FEATURE_KEYS = taxi_constants.DENSE_FLOAT_FEATURE_KEYS
_VOCAB_FEATURE_KEYS = taxi_constants.VOCAB_FEATURE_KEYS
_VOCAB_SIZE = taxi_constants.VOCAB_SIZE
_OOV_SIZE = taxi_constants.OOV_SIZE
_FEATURE_BUCKET_COUNT = taxi_constants.FEATURE_BUCKET_COUNT
_BUCKET_FEATURE_KEYS = taxi_constants.BUCKET_FEATURE_KEYS
_CATEGORICAL_FEATURE_KEYS = taxi_constants.CATEGORICAL_FEATURE_KEYS
_MAX_CATEGORICAL_FEATURE_VALUES = taxi_constants.MAX_CATEGORICAL_FEATURE_VALUES
_LABEL_KEY = taxi_constants.LABEL_KEY
_transformed_name = taxi_constants.transformed_name


def _transformed_names(keys):
  return [_transformed_name(key) for key in keys]


def _get_serve_tf_examples_fn(model, tf_transform_output):
  """Returns a function that parses a serialized tf.Example and applies TFT."""

  model.tft_layer = tf_transform_output.transform_features_layer()

  @tf.function
  def serve_tf_examples_fn(serialized_tf_examples):
    """Returns the output to be used in the serving signature."""
    feature_spec = tf_transform_output.raw_feature_spec()
    feature_spec.pop(_LABEL_KEY)
    parsed_features = tf.io.parse_example(serialized_tf_examples, feature_spec)
    transformed_features = model.tft_layer(parsed_features)
    return model(transformed_features)

  return serve_tf_examples_fn


def _input_fn(file_pattern: List[Text],
              data_accessor: tfx.components.DataAccessor,
              tf_transform_output: tft.TFTransformOutput,
              batch_size: int = 200) -> tf.data.Dataset:
  """Generates features and label for tuning/training.

  Args:
    file_pattern: List of paths or patterns of input tfrecord files.
    data_accessor: DataAccessor for converting input to RecordBatch.
    tf_transform_output: A TFTransformOutput.
    batch_size: representing the number of consecutive elements of returned
      dataset to combine in a single batch

  Returns:
    A dataset that contains (features, indices) tuple where features is a
      dictionary of Tensors, and indices is a single Tensor of label indices.
  """
  return data_accessor.tf_dataset_factory(
      file_pattern,
      tfxio.TensorFlowDatasetOptions(
          batch_size=batch_size, label_key=_transformed_name(_LABEL_KEY)),
      tf_transform_output.transformed_metadata.schema)


def _build_keras_model(hidden_units: List[int] = None) -> tf.keras.Model:
  """Creates a DNN Keras model for classifying taxi data.

  Args:
    hidden_units: [int], the layer sizes of the DNN (input layer first).

  Returns:
    A keras Model.
  """
  real_valued_columns = [
      tf.feature_column.numeric_column(key, shape=())
      for key in _transformed_names(_DENSE_FLOAT_FEATURE_KEYS)
  ]
  categorical_columns = [
      tf.feature_column.categorical_column_with_identity(
          key, num_buckets=_VOCAB_SIZE + _OOV_SIZE, default_value=0)
      for key in _transformed_names(_VOCAB_FEATURE_KEYS)
  ]
  categorical_columns += [
      tf.feature_column.categorical_column_with_identity(
          key, num_buckets=_FEATURE_BUCKET_COUNT, default_value=0)
      for key in _transformed_names(_BUCKET_FEATURE_KEYS)
  ]
  categorical_columns += [
      tf.feature_column.categorical_column_with_identity(  # pylint: disable=g-complex-comprehension
          key,
          num_buckets=num_buckets,
          default_value=0) for key, num_buckets in zip(
              _transformed_names(_CATEGORICAL_FEATURE_KEYS),
              _MAX_CATEGORICAL_FEATURE_VALUES)
  ]
  indicator_column = [
      tf.feature_column.indicator_column(categorical_column)
      for categorical_column in categorical_columns
  ]

  model = _wide_and_deep_classifier(
      # TODO(b/139668410) replace with premade wide_and_deep keras model
      wide_columns=indicator_column,
      deep_columns=real_valued_columns,
      dnn_hidden_units=hidden_units or [100, 70, 50, 25])
  return model


def _wide_and_deep_classifier(wide_columns, deep_columns, dnn_hidden_units):
  """Build a simple keras wide and deep model.

  Args:
    wide_columns: Feature columns wrapped in indicator_column for wide (linear)
      part of the model.
    deep_columns: Feature columns for deep part of the model.
    dnn_hidden_units: [int], the layer sizes of the hidden DNN.

  Returns:
    A Wide and Deep Keras model
  """
  # Following values are hard coded for simplicity in this example,
  # However prefarably they should be passsed in as hparams.

  # Keras needs the feature definitions at compile time.
  # TODO(b/139081439): Automate generation of input layers from FeatureColumn.
  input_layers = {
      colname: tf.keras.layers.Input(name=colname, shape=(), dtype=tf.float32)
      for colname in _transformed_names(_DENSE_FLOAT_FEATURE_KEYS)
  }
  input_layers.update({
      colname: tf.keras.layers.Input(name=colname, shape=(), dtype='int32')
      for colname in _transformed_names(_VOCAB_FEATURE_KEYS)
  })
  input_layers.update({
      colname: tf.keras.layers.Input(name=colname, shape=(), dtype='int32')
      for colname in _transformed_names(_BUCKET_FEATURE_KEYS)
  })
  input_layers.update({
      colname: tf.keras.layers.Input(name=colname, shape=(), dtype='int32')
      for colname in _transformed_names(_CATEGORICAL_FEATURE_KEYS)
  })

  # TODO(b/161952382): Replace with Keras preprocessing layers.
  deep = tf.keras.layers.DenseFeatures(deep_columns)(input_layers)
  for numnodes in dnn_hidden_units:
    deep = tf.keras.layers.Dense(numnodes)(deep)
  wide = tf.keras.layers.DenseFeatures(wide_columns)(input_layers)

  output = tf.keras.layers.Dense(1)(
          tf.keras.layers.concatenate([deep, wide]))

  model = tf.keras.Model(input_layers, output)
  model.compile(
      loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
      optimizer=tf.keras.optimizers.Adam(lr=0.001),
      metrics=[tf.keras.metrics.BinaryAccuracy()])
  model.summary(print_fn=absl.logging.info)
  return model


# TFX Trainer will call this function.
def run_fn(fn_args: tfx.components.FnArgs):
  """Train the model based on given args.

  Args:
    fn_args: Holds args used to train the model as name/value pairs.
  """
  # Number of nodes in the first layer of the DNN
  first_dnn_layer_size = 100
  num_dnn_layers = 4
  dnn_decay_factor = 0.7

  tf_transform_output = tft.TFTransformOutput(fn_args.transform_output)

  train_dataset = _input_fn(fn_args.train_files, fn_args.data_accessor, 
                            tf_transform_output, 40)
  eval_dataset = _input_fn(fn_args.eval_files, fn_args.data_accessor, 
                           tf_transform_output, 40)

  model = _build_keras_model(
      # Construct layers sizes with exponetial decay
      hidden_units=[
          max(2, int(first_dnn_layer_size * dnn_decay_factor**i))
          for i in range(num_dnn_layers)
      ])

  tensorboard_callback = tf.keras.callbacks.TensorBoard(
      log_dir=fn_args.model_run_dir, update_freq='batch')
  model.fit(
      train_dataset,
      steps_per_epoch=fn_args.train_steps,
      validation_data=eval_dataset,
      validation_steps=fn_args.eval_steps,
      callbacks=[tensorboard_callback])

  signatures = {
      'serving_default':
          _get_serve_tf_examples_fn(model,
                                    tf_transform_output).get_concrete_function(
                                        tf.TensorSpec(
                                            shape=[None],
                                            dtype=tf.string,
                                            name='examples')),
  }
  model.save(fn_args.serving_model_dir, save_format='tf', signatures=signatures)<jupyter_output><empty_output><jupyter_text>次に、このモデル コードを`Trainer`コンポーネントに渡し、それを実行してモデルをトレーニングします。<jupyter_code>trainer = tfx.components.Trainer(
    module_file=os.path.abspath(_taxi_trainer_module_file),
    examples=transform.outputs['transformed_examples'],
    transform_graph=transform.outputs['transform_graph'],
    schema=schema_gen.outputs['schema'],
    train_args=tfx.proto.TrainArgs(num_steps=10000),
    eval_args=tfx.proto.EvalArgs(num_steps=5000))
context.run(trainer)<jupyter_output><empty_output><jupyter_text>TensorBoard でトレーニングを分析するトレーナーのアーティファクトを見てみましょう。これはモデルのサブディレクトリを含むディレクトリを指しています。<jupyter_code>model_artifact_dir = trainer.outputs['model'].get()[0].uri
pp.pprint(os.listdir(model_artifact_dir))
model_dir = os.path.join(model_artifact_dir, 'Format-Serving')
pp.pprint(os.listdir(model_dir))<jupyter_output><empty_output><jupyter_text>オプションで、TensorBoard を Trainer に接続して、モデルの学習曲線を分析できます。<jupyter_code>model_run_artifact_dir = trainer.outputs['model_run'].get()[0].uri

%load_ext tensorboard
%tensorboard --logdir {model_run_artifact_dir}<jupyter_output><empty_output><jupyter_text>Evaluator`Evaluator` コンポーネントは、評価セットに対してモデル パフォーマンス指標を計算します。[TensorFlow Model Analysis](https://www.tensorflow.org/tfx/model_analysis/get_started)ライブラリを使用します。`Evaluator`は、オプションで、新しくトレーニングされたモデルが以前のモデルよりも優れていることを検証できます。これは、モデルを毎日自動的にトレーニングおよび検証する実稼働環境のパイプライン設定で役立ちます。このノートブックでは 1 つのモデルのみをトレーニングするため、`Evaluator`はモデルに自動的に「good」というラベルを付けます。`Evaluator`は、`ExampleGen`からのデータ、`Trainer`からのトレーニング済みモデル、およびスライス構成を入力として受け取ります。スライス構成により、特徴値に関する指標をスライスすることができます (たとえば、午前 8 時から午後 8 時までのタクシー乗車でモデルがどのように動作するかなど)。 この構成の例は、以下を参照してください。<jupyter_code>eval_config = tfma.EvalConfig(
    model_specs=[
        # This assumes a serving model with signature 'serving_default'. If
        # using estimator based EvalSavedModel, add signature_name: 'eval' and 
        # remove the label_key.
        tfma.ModelSpec(label_key='tips')
    ],
    metrics_specs=[
        tfma.MetricsSpec(
            # The metrics added here are in addition to those saved with the
            # model (assuming either a keras model or EvalSavedModel is used).
            # Any metrics added into the saved model (for example using
            # model.compile(..., metrics=[...]), etc) will be computed
            # automatically.
            # To add validation thresholds for metrics saved with the model,
            # add them keyed by metric name to the thresholds map.
            metrics=[
                tfma.MetricConfig(class_name='ExampleCount'),
                tfma.MetricConfig(class_name='BinaryAccuracy',
                  threshold=tfma.MetricThreshold(
                      value_threshold=tfma.GenericValueThreshold(
                          lower_bound={'value': 0.5}),
                      # Change threshold will be ignored if there is no
                      # baseline model resolved from MLMD (first run).
                      change_threshold=tfma.GenericChangeThreshold(
                          direction=tfma.MetricDirection.HIGHER_IS_BETTER,
                          absolute={'value': -1e-10})))
            ]
        )
    ],
    slicing_specs=[
        # An empty slice spec means the overall slice, i.e. the whole dataset.
        tfma.SlicingSpec(),
        # Data can be sliced along a feature column. In this case, data is
        # sliced along feature column trip_start_hour.
        tfma.SlicingSpec(feature_keys=['trip_start_hour'])
    ])<jupyter_output><empty_output><jupyter_text>次に、この構成を `Evaluator`に渡して実行します。<jupyter_code># Use TFMA to compute a evaluation statistics over features of a model and
# validate them against a baseline.

# The model resolver is only required if performing model validation in addition
# to evaluation. In this case we validate against the latest blessed model. If
# no model has been blessed before (as in this case) the evaluator will make our
# candidate the first blessed model.
model_resolver = tfx.dsl.Resolver(
      strategy_class=tfx.dsl.experimental.LatestBlessedModelStrategy,
      model=tfx.dsl.Channel(type=tfx.types.standard_artifacts.Model),
      model_blessing=tfx.dsl.Channel(
          type=tfx.types.standard_artifacts.ModelBlessing)).with_id(
              'latest_blessed_model_resolver')
context.run(model_resolver)

evaluator = tfx.components.Evaluator(
    examples=example_gen.outputs['examples'],
    model=trainer.outputs['model'],
    baseline_model=model_resolver.outputs['model'],
    eval_config=eval_config)
context.run(evaluator)<jupyter_output><empty_output><jupyter_text>`Evaluator` の出力アーティファクトを調べてみましょう。<jupyter_code>evaluator.outputs<jupyter_output><empty_output><jupyter_text>`evaluation`出力を使用すると、評価セット全体のグローバル指標のデフォルトの視覚化を表示できます。<jupyter_code>context.show(evaluator.outputs['evaluation'])<jupyter_output><empty_output><jupyter_text>スライスされた評価メトリクスの視覚化を表示するには、TensorFlow Model Analysis ライブラリを直接呼び出します。<jupyter_code>import tensorflow_model_analysis as tfma

# Get the TFMA output result path and load the result.
PATH_TO_RESULT = evaluator.outputs['evaluation'].get()[0].uri
tfma_result = tfma.load_eval_result(PATH_TO_RESULT)

# Show data sliced along feature column trip_start_hour.
tfma.view.render_slicing_metrics(
    tfma_result, slicing_column='trip_start_hour')<jupyter_output><empty_output><jupyter_text>この視覚化は同じ指標を示していますが、評価セット全体ではなく、`trip_start_hour`のすべての特徴値で計算されています。TensorFlow モデル分析は、公平性インジケーターやモデル パフォーマンスの時系列のプロットなど、他の多くの視覚化をサポートしています。 詳細については、[チュートリアル](https://www.tensorflow.org/tfx/tutorials/model_analysis/tfma_basic)を参照してください。 構成にしきい値を追加したため、検証出力も利用できます。{code 0}blessing{/code 0} アーティファクトの存在は、モデルが検証に合格したことを示しています。これは実行される最初の検証であるため、候補は自動的に bless されます。<jupyter_code>blessing_uri = evaluator.outputs['blessing'].get()[0].uri
!ls -l {blessing_uri}<jupyter_output><empty_output><jupyter_text>検証結果レコードを読み込み、成功を確認することもできます。<jupyter_code>PATH_TO_RESULT = evaluator.outputs['evaluation'].get()[0].uri
print(tfma.load_validation_result(PATH_TO_RESULT))<jupyter_output><empty_output><jupyter_text>Pusher`Pusher` コンポーネントは通常、TFX パイプラインの最後にあります。このコンポーネントはモデルが検証に合格したかどうかをチェックし、合格した場合はモデルを `_serving_model_dir`にエクスポートします。<jupyter_code>pusher = tfx.components.Pusher(
    model=trainer.outputs['model'],
    model_blessing=evaluator.outputs['blessing'],
    push_destination=tfx.proto.PushDestination(
        filesystem=tfx.proto.PushDestination.Filesystem(
            base_directory=_serving_model_dir)))
context.run(pusher)<jupyter_output><empty_output><jupyter_text>次に`Pusher`の出力アーティファクトを調べてみましょう。<jupyter_code>pusher.outputs<jupyter_output><empty_output><jupyter_text>特に、Pusher はモデルを次のような SavedModel 形式でエクスポートします。<jupyter_code>push_uri = pusher.outputs['pushed_model'].get()[0].uri
model = tf.saved_model.load(push_uri)

for item in model.signatures.items():
  pp.pprint(item)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08958806772717089, 'fraction_numerical': 0.005281182984988637, 'mean_word_length': 5.985021238542365, 'pattern_counts': {'":': 0, '<': 153, '<?xml version=': 0, '>': 156, 'https://': 15, 'lorem ipsum': 0, 'www.': 13, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '38', 'dir': 'jupyter-structured-clean-dedup', 'id': '520025', 'license': 'Apache-2.0', 'n_tokens_mistral': 14065, 'n_tokens_neox': 13355, 'n_words': 1792, 'path': 'site/ja/tfx/tutorials/tfx/components_keras.ipynb', 'repo_name': 'phoenix-fork-tensorflow/docs-l10n', 'size': '31243'}