MLコミュニティデーは11月9日です! TensorFlow、JAXからの更新のために私たちに参加し、より多くの詳細をご覧ください

TensorFlowデータの検証

TensorFlowExtendedの主要コンポーネントの例

このサンプルのcolabノートブックは、TensorFlow Data Validation(TFDV)を使用してデータセットを調査および視覚化する方法を示しています。これには、記述統計の確認、スキーマの推測、異常のチェックと修正、データセットのドリフトとスキューのチェックが含まれます。データセットの特性を理解することが重要です。これには、本番パイプラインで時間の経過とともにどのように変化するかなどが含まれます。また、データの異常を探し、トレーニング、評価、および提供データセットを比較して、それらが一貫していることを確認することも重要です。

私たちは、からのデータ使用しますタクシーは、データセットをTripsのシカゴ市が発表しました。

もっと読む内のデータセットに関するGoogleのBigQueryのを。で完全なデータセットを探検BigQueryのUIを

データセットの列は次のとおりです。

Pickup_community_area運賃trip_start_month
trip_start_hour trip_start_day trip_start_timestamp
Pickup_latitude Pickup_longitude dropoff_latitude
dropoff_longitude trip_miles Pickup_census_tract
dropoff_census_tract払いの種類会社
trip_seconds dropoff_community_areaチップ

アップグレードピップ

ローカルで実行しているときにシステムでPipをアップグレードしないようにするには、Colabで実行していることを確認してください。もちろん、ローカルシステムは個別にアップグレードできます。

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

TensorFlowをインストールします

pip install tensorflow==2.2.0

Pythonのバージョンを確認する

import sys

# Confirm that we're using Python 3
assert sys.version_info.major is 3, 'Oops, not running Python 3. Use Runtime > Change runtime type'

TFDVをインストールします

これにより、すべての依存関係が取得されます。これには1分かかります。互換性のない依存関係バージョンに関する警告またはエラーは無視してください。

import tensorflow as tf

print('Installing TensorFlow Data Validation')
!pip install -q tensorflow_data_validation[visualization]

ランタイムを再起動しましたか?

上記のセルを初めて実行するときにGoogleColabを使用している場合は、ランタイムを再起動する必要があります([ランタイム]> [ランタイムの再起動...])。これは、Colabがパッケージをロードする方法が原因です。

ファイルをロードする

Google CloudStorageからデータセットをダウンロードします。

import os
import tempfile, urllib, zipfile

# Set up some globals for our file paths
BASE_DIR = tempfile.mkdtemp()
DATA_DIR = os.path.join(BASE_DIR, 'data')
OUTPUT_DIR = os.path.join(BASE_DIR, 'chicago_taxi_output')
TRAIN_DATA = os.path.join(DATA_DIR, 'train', 'data.csv')
EVAL_DATA = os.path.join(DATA_DIR, 'eval', 'data.csv')
SERVING_DATA = os.path.join(DATA_DIR, 'serving', 'data.csv')

# Download the zip file from GCP and unzip it
zip, headers = urllib.request.urlretrieve('https://storage.googleapis.com/artifacts.tfx-oss-public.appspot.com/datasets/chicago_data.zip')
zipfile.ZipFile(zip).extractall(BASE_DIR)
zipfile.ZipFile(zip).close()

print("Here's what we downloaded:")
!ls -R {os.path.join(BASE_DIR, 'data')}
Here's what we downloaded:
/tmp/tmp9ac2o66s/data:
eval  serving  train

/tmp/tmp9ac2o66s/data/eval:
data.csv

/tmp/tmp9ac2o66s/data/serving:
data.csv

/tmp/tmp9ac2o66s/data/train:
data.csv

バージョンを確認する

import tensorflow_data_validation as tfdv
print('TFDV version: {}'.format(tfdv.version.__version__))
TFDV version: 0.27.0

統計を計算して視覚化する

まず、使用しますtfdv.generate_statistics_from_csv私たちのトレーニングデータのための統計の計算に。 (きびきびとした警告は無視してください)

TFDVは、記述を計算することができます統計存在している機能とその値分布の形状の観点からデータの簡単な概要を提供します。

内部的には、TFDVは使用アパッチビーム大規模なデータセット上統計の計算をスケーリングするのデータ並列処理フレームワーク。 TFDVとより深く統合したいアプリケーション(たとえば、データ生成パイプラインの最後に統計生成をアタッチする)の場合、APIは統計生成用のBeamPTransformも公開します。

train_stats = tfdv.generate_statistics_from_csv(data_location=TRAIN_DATA)
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:apache_beam.io.tfrecordio:Couldn't find python-snappy so the implementation of _TFRecordUtil._masked_crc32c is not as fast as it could be.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow_data_validation/utils/stats_util.py:247: tf_record_iterator (from tensorflow.python.lib.io.tf_record) is deprecated and will be removed in a future version.
Instructions for updating:
Use eager execution and: 
`tf.data.TFRecordDataset(path)`
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow_data_validation/utils/stats_util.py:247: tf_record_iterator (from tensorflow.python.lib.io.tf_record) is deprecated and will be removed in a future version.
Instructions for updating:
Use eager execution and: 
`tf.data.TFRecordDataset(path)`

それでは使用せtfdv.visualize_statistics使用した、ファセットを私たちのトレーニングデータの簡潔なビジュアライゼーションを作成するには:

  • 数値の特徴とカテゴリの特徴が別々に視覚化され、各特徴の分布を示すグラフが表示されていることに注意してください。
  • 値が欠落しているかゼロの機能は、それらの機能の例に問題がある可能性があることを視覚的に示すために、パーセンテージが赤で表示されることに注意してください。パーセンテージは、その機能の値が欠落しているかゼロである例のパーセンテージです。
  • 値を持つ例は存在しないことを注意してくださいpickup_census_tract 。これは次元削減の機会です!
  • グラフの上にある[展開]をクリックして、表示を変更してみてください
  • グラフのバーにカーソルを合わせて、バケットの範囲とカウントを表示してみてください
  • 対数スケールがについて多くの詳細を明らかにどのようにログとリニアスケールを切り替えてみてください、と予告payment_typeカテゴリ機能
  • [表示するグラフ]メニューから[分位数]を選択し、マーカーにカーソルを合わせて分位数のパーセンテージを表示してみてください
tfdv.visualize_statistics(train_stats)

スキーマを推測する

それでは使用せtfdv.infer_schema我々のデータのスキーマを作成します。スキーマは、MLに関連するデータの制約を定義します。制約の例には、数値かカテゴリかを問わず、各フィーチャのデータタイプ、またはデータ内に存在する頻度が含まれます。カテゴリ機能の場合、スキーマはドメイン(許容値のリスト)も定義します。スキーマの作成は、特に多くの機能を備えたデータセットの場合、面倒な作業になる可能性があるため、TFDVは、記述統計に基づいてスキーマの初期バージョンを生成する方法を提供します。

スキーマを正しく取得することは重要です。これは、本番パイプラインの残りの部分が、TFDVが生成するスキーマが正しいことに依存するためです。スキーマはデータのドキュメントも提供するため、異なる開発者が同じデータで作業する場合に役立ちます。レッツ・利用tfdv.display_schema我々はそれを見直すことができるように推論されたスキーマを表示します。

schema = tfdv.infer_schema(statistics=train_stats)
tfdv.display_schema(schema=schema)
/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow_data_validation/utils/display_util.py:151: FutureWarning: Passing a negative integer is deprecated in version 1.0 and will not be supported in future version. Instead, use None to not limit the column width.
  pd.set_option('max_colwidth', -1)

評価データにエラーがないか確認してください

これまでは、トレーニングデータのみを確認してきました。同じスキーマを使用していることを含め、評価データがトレーニングデータと一致していることが重要です。また、評価データにトレーニングデータとほぼ同じ数値特徴の値の例が含まれていることも重要です。これにより、評価中の損失面のカバレッジはトレーニング中とほぼ同じになります。カテゴリ機能についても同じことが言えます。そうしないと、損失面の一部を評価しなかったため、評価中に特定されないトレーニングの問題が発生する可能性があります。

  • 各機能に、トレーニングデータセットと評価データセットの両方の統計が含まれていることに注意してください。
  • チャートにトレーニングデータセットと評価データセットの両方がオーバーレイされ、それらを簡単に比較できるようになっていることに注意してください。
  • チャートにパーセンテージビューが含まれていることに注意してください。これは、ログまたはデフォルトの線形スケールと組み合わせることができます。
  • 平均値と中央値ということに注意してくださいtrip_miles評価データセットに対する訓練のために異なっています。それは問題を引き起こしますか?
  • うわー、最大tips 、評価データセットに対する訓練のための非常に異なっています。それは問題を引き起こしますか?
  • 数値機能チャートの展開をクリックし、対数スケールを選択します。確認trip_seconds備わっています、そして最大の違いに気づきます。評価は損失面の一部を見逃しますか?
# Compute stats for evaluation data
eval_stats = tfdv.generate_statistics_from_csv(data_location=EVAL_DATA)

# Compare evaluation data with training data
tfdv.visualize_statistics(lhs_statistics=eval_stats, rhs_statistics=train_stats,
                          lhs_name='EVAL_DATASET', rhs_name='TRAIN_DATASET')

評価の異常をチェックする

評価データセットは、トレーニングデータセットのスキーマと一致していますか?これは、許容値の範囲を特定するカテゴリ機能にとって特に重要です。

# Check eval data for errors by validating the eval data stats using the previously inferred schema.
anomalies = tfdv.validate_statistics(statistics=eval_stats, schema=schema)
tfdv.display_anomalies(anomalies)
/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow_data_validation/utils/display_util.py:186: FutureWarning: Passing a negative integer is deprecated in version 1.0 and will not be supported in future version. Instead, use None to not limit the column width.
  pd.set_option('max_colwidth', -1)

スキーマの評価の異常を修正する

おっとっと!我々はいくつかの新しい値を持っているように見えcompany当社の評価データに我々はトレーニングデータに持っていなかったこと、。我々はまた、新しい値持つpayment_type 。これらは異常と見なす必要がありますが、それらに対して何をするかは、データに関するドメイン知識によって異なります。異常が本当にデータエラーを示している場合は、基になるデータを修正する必要があります。それ以外の場合は、スキーマを更新して、evalデータセットに値を含めることができます。

評価データセットを変更しない限り、すべてを修正することはできませんが、受け入れやすいスキーマ内のものを修正することはできます。これには、特定の機能の異常とは何かという見方を緩和することや、カテゴリ機能の欠落値を含めるようにスキーマを更新することが含まれます。 TFDVにより、修正が必要なものを見つけることができました。

今すぐこれらの修正を行ってから、もう一度確認してみましょう。

# Relax the minimum fraction of values that must come from the domain for feature company.
company = tfdv.get_feature(schema, 'company')
company.distribution_constraints.min_domain_mass = 0.9

# Add new value to the domain of feature payment_type.
payment_type_domain = tfdv.get_domain(schema, 'payment_type')
payment_type_domain.value.append('Prcard')

# Validate eval stats after updating the schema 
updated_anomalies = tfdv.validate_statistics(eval_stats, schema)
tfdv.display_anomalies(updated_anomalies)

ねえ、それを見てください!トレーニングと評価のデータに一貫性があることを確認しました。ありがとうTFDV;)

スキーマ環境

また、この例では「サービング」データセットを分割しているので、それも確認する必要があります。デフォルトでは、パイプライン内のすべてのデータセットは同じスキーマを使用する必要がありますが、多くの場合、例外があります。たとえば、教師あり学習では、データセットにラベルを含める必要がありますが、推論用のモデルを提供する場合、ラベルは含まれません。場合によっては、わずかなスキーマのバリエーションを導入する必要があります。

環境は、このような要件を表現するために使用することができます。具体的には、スキーマ内の特徴は、使用環境のセットに関連付けることができるdefault_environmentin_environmentnot_in_environment

たとえば、このデータセットにtips機能は、訓練のためのラベルとして含まれているが、それはなるデータに欠けています。環境を指定しないと、異常として表示されます。

serving_stats = tfdv.generate_statistics_from_csv(SERVING_DATA)
serving_anomalies = tfdv.validate_statistics(serving_stats, schema)

tfdv.display_anomalies(serving_anomalies)
/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow_data_validation/utils/display_util.py:186: FutureWarning: Passing a negative integer is deprecated in version 1.0 and will not be supported in future version. Instead, use None to not limit the column width.
  pd.set_option('max_colwidth', -1)

私たちは対処しますtips下記備えています。また、スキーマがFLOATを期待していたトリップ秒にINT値があります。 TFDVは、その違いを認識させることで、トレーニングと提供のためにデータを生成する方法の不整合を明らかにするのに役立ちます。モデルのパフォーマンスが低下するまで、時には壊滅的に、そのような問題に気付かないのは非常に簡単です。これは重大な問題である場合とそうでない場合がありますが、いずれにせよ、これはさらなる調査の原因となるはずです。

この場合、INT値をFLOATに安全に変換できるため、スキーマを使用して型を推測するようにTFDVに指示します。今それをしましょう。

options = tfdv.StatsOptions(schema=schema, infer_type_from_schema=True)
serving_stats = tfdv.generate_statistics_from_csv(SERVING_DATA, stats_options=options)
serving_anomalies = tfdv.validate_statistics(serving_stats, schema)

tfdv.display_anomalies(serving_anomalies)
/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow_data_validation/utils/display_util.py:186: FutureWarning: Passing a negative integer is deprecated in version 1.0 and will not be supported in future version. Instead, use None to not limit the column width.
  pd.set_option('max_colwidth', -1)

今、私たちはしているtips異常(「列はドロップ」)として表示(私たちのラベルである)が備わっています。もちろん、提供データにラベルが含まれることは想定されていないため、TFDVにそれを無視するように指示しましょう。

# All features are by default in both TRAINING and SERVING environments.
schema.default_environment.append('TRAINING')
schema.default_environment.append('SERVING')

# Specify that 'tips' feature is not in SERVING environment.
tfdv.get_feature(schema, 'tips').not_in_environment.append('SERVING')

serving_anomalies_with_env = tfdv.validate_statistics(
    serving_stats, schema, environment='SERVING')

tfdv.display_anomalies(serving_anomalies_with_env)

ドリフトとスキューをチェックします

データセットがスキーマで設定された期待値に準拠しているかどうかを確認することに加えて、TFDVはドリフトとスキューを検出する機能も提供します。 TFDVは、スキーマで指定されたドリフト/スキューコンパレータに基づいてさまざまなデータセットの統計を比較することにより、このチェックを実行します。

ドリフト

ドリフト検出は、カテゴリの特徴と、トレーニングデータの異なる日の間など、データの連続するスパン間(つまり、スパンNとスパンN + 1の間)でサポートされます。我々はの面でドリフトを表現L-無限の距離、およびドリフトが許容可能であるよりも高いときに、あなたが警告を受け取ることができるように、あなたは閾値距離を設定することができます。正しい距離を設定することは、通常、ドメインの知識と実験を必要とする反復プロセスです。

斜め

TFDVは、データ内の3種類のスキュー(スキーマスキュー、機能スキュー、および分布スキュー)を検出できます。

スキーマスキュー

スキーマスキューは、トレーニングデータとサービングデータが同じスキーマに準拠していない場合に発生します。トレーニングデータと提供データの両方が同じスキーマに準拠することが期待されます。 2つの間に予想される偏差(ラベル機能はトレーニングデータにのみ存在し、サービングには存在しないなど)は、スキーマの環境フィールドで指定する必要があります。

機能スキュー

特徴スキューは、モデルがトレーニングする特徴値が、サービング時に表示される特徴値と異なる場合に発生します。たとえば、これは次の場合に発生する可能性があります。

  • いくつかの特徴値を提供するデータソースは、トレーニングと提供時間の間で変更されます
  • トレーニングとサービングの間で機能を生成するための異なるロジックがあります。たとえば、2つのコードパスのいずれかでのみ変換を適用する場合です。

分布スキュー

分布スキューは、トレーニングデータセットの分布がサービングデータセットの分布と大幅に異なる場合に発生します。分布スキューの主な原因の1つは、トレーニングデータセットを生成するために異なるコードまたは異なるデータソースを使用することです。もう1つの理由は、トレーニングするサービングデータの代表的でないサブサンプルを選択するサンプリングメカニズムの欠陥です。

# Add skew comparator for 'payment_type' feature.
payment_type = tfdv.get_feature(schema, 'payment_type')
payment_type.skew_comparator.infinity_norm.threshold = 0.01

# Add drift comparator for 'company' feature.
company=tfdv.get_feature(schema, 'company')
company.drift_comparator.infinity_norm.threshold = 0.001

skew_anomalies = tfdv.validate_statistics(train_stats, schema,
                                          previous_statistics=eval_stats,
                                          serving_statistics=serving_stats)

tfdv.display_anomalies(skew_anomalies)
/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow_data_validation/utils/display_util.py:186: FutureWarning: Passing a negative integer is deprecated in version 1.0 and will not be supported in future version. Instead, use None to not limit the column width.
  pd.set_option('max_colwidth', -1)

この例では、多少のドリフトが見られますが、設定したしきい値をはるかに下回っています。

スキーマをフリーズします

スキーマがレビューおよびキュレートされたので、「凍結」状態を反映するようにスキーマをファイルに保存します。

from tensorflow.python.lib.io import file_io
from google.protobuf import text_format

file_io.recursive_create_dir(OUTPUT_DIR)
schema_file = os.path.join(OUTPUT_DIR, 'schema.pbtxt')
tfdv.write_schema_text(schema, schema_file)

!cat {schema_file}
feature {
  name: "payment_type"
  type: BYTES
  domain: "payment_type"
  presence {
    min_fraction: 1.0
    min_count: 1
  }
  skew_comparator {
    infinity_norm {
      threshold: 0.01
    }
  }
  shape {
    dim {
      size: 1
    }
  }
}
feature {
  name: "company"
  value_count {
    min: 1
    max: 1
  }
  type: BYTES
  domain: "company"
  presence {
    min_count: 1
  }
  distribution_constraints {
    min_domain_mass: 0.9
  }
  drift_comparator {
    infinity_norm {
      threshold: 0.001
    }
  }
}
feature {
  name: "pickup_community_area"
  type: INT
  presence {
    min_fraction: 1.0
    min_count: 1
  }
  shape {
    dim {
      size: 1
    }
  }
}
feature {
  name: "fare"
  type: FLOAT
  presence {
    min_fraction: 1.0
    min_count: 1
  }
  shape {
    dim {
      size: 1
    }
  }
}
feature {
  name: "trip_start_month"
  type: INT
  presence {
    min_fraction: 1.0
    min_count: 1
  }
  shape {
    dim {
      size: 1
    }
  }
}
feature {
  name: "trip_start_hour"
  type: INT
  presence {
    min_fraction: 1.0
    min_count: 1
  }
  shape {
    dim {
      size: 1
    }
  }
}
feature {
  name: "trip_start_day"
  type: INT
  presence {
    min_fraction: 1.0
    min_count: 1
  }
  shape {
    dim {
      size: 1
    }
  }
}
feature {
  name: "trip_start_timestamp"
  type: INT
  presence {
    min_fraction: 1.0
    min_count: 1
  }
  shape {
    dim {
      size: 1
    }
  }
}
feature {
  name: "pickup_latitude"
  type: FLOAT
  presence {
    min_fraction: 1.0
    min_count: 1
  }
  shape {
    dim {
      size: 1
    }
  }
}
feature {
  name: "pickup_longitude"
  type: FLOAT
  presence {
    min_fraction: 1.0
    min_count: 1
  }
  shape {
    dim {
      size: 1
    }
  }
}
feature {
  name: "dropoff_latitude"
  value_count {
    min: 1
    max: 1
  }
  type: FLOAT
  presence {
    min_count: 1
  }
}
feature {
  name: "dropoff_longitude"
  value_count {
    min: 1
    max: 1
  }
  type: FLOAT
  presence {
    min_count: 1
  }
}
feature {
  name: "trip_miles"
  type: FLOAT
  presence {
    min_fraction: 1.0
    min_count: 1
  }
  shape {
    dim {
      size: 1
    }
  }
}
feature {
  name: "pickup_census_tract"
  type: BYTES
  presence {
    min_count: 0
  }
}
feature {
  name: "dropoff_census_tract"
  value_count {
    min: 1
    max: 1
  }
  type: INT
  presence {
    min_count: 1
  }
}
feature {
  name: "trip_seconds"
  type: INT
  presence {
    min_fraction: 1.0
    min_count: 1
  }
  shape {
    dim {
      size: 1
    }
  }
}
feature {
  name: "dropoff_community_area"
  value_count {
    min: 1
    max: 1
  }
  type: INT
  presence {
    min_count: 1
  }
}
feature {
  name: "tips"
  type: FLOAT
  presence {
    min_fraction: 1.0
    min_count: 1
  }
  not_in_environment: "SERVING"
  shape {
    dim {
      size: 1
    }
  }
}
string_domain {
  name: "payment_type"
  value: "Cash"
  value: "Credit Card"
  value: "Dispute"
  value: "No Charge"
  value: "Pcard"
  value: "Unknown"
  value: "Prcard"
}
string_domain {
  name: "company"
  value: "0118 - 42111 Godfrey S.Awir"
  value: "0694 - 59280 Chinesco Trans Inc"
  value: "1085 - 72312 N and W Cab Co"
  value: "2733 - 74600 Benny Jona"
  value: "2809 - 95474 C & D Cab Co Inc."
  value: "3011 - 66308 JBL Cab Inc."
  value: "3152 - 97284 Crystal Abernathy"
  value: "3201 - C&D Cab Co Inc"
  value: "3201 - CID Cab Co Inc"
  value: "3253 - 91138 Gaither Cab Co."
  value: "3385 - 23210 Eman Cab"
  value: "3623 - 72222 Arrington Enterprises"
  value: "3897 - Ilie Malec"
  value: "4053 - Adwar H. Nikola"
  value: "4197 - 41842 Royal Star"
  value: "4615 - 83503 Tyrone Henderson"
  value: "4615 - Tyrone Henderson"
  value: "4623 - Jay Kim"
  value: "5006 - 39261 Salifu Bawa"
  value: "5006 - Salifu Bawa"
  value: "5074 - 54002 Ahzmi Inc"
  value: "5074 - Ahzmi Inc"
  value: "5129 - 87128"
  value: "5129 - 98755 Mengisti Taxi"
  value: "5129 - Mengisti Taxi"
  value: "5724 - KYVI Cab Inc"
  value: "585 - Valley Cab Co"
  value: "5864 - 73614 Thomas Owusu"
  value: "5864 - Thomas Owusu"
  value: "5874 - 73628 Sergey Cab Corp."
  value: "5997 - 65283 AW Services Inc."
  value: "5997 - AW Services Inc."
  value: "6488 - 83287 Zuha Taxi"
  value: "6743 - Luhak Corp"
  value: "Blue Ribbon Taxi Association Inc."
  value: "C & D Cab Co Inc"
  value: "Chicago Elite Cab Corp."
  value: "Chicago Elite Cab Corp. (Chicago Carriag"
  value: "Chicago Medallion Leasing INC"
  value: "Chicago Medallion Management"
  value: "Choice Taxi Association"
  value: "Dispatch Taxi Affiliation"
  value: "KOAM Taxi Association"
  value: "Northwest Management LLC"
  value: "Taxi Affiliation Services"
  value: "Top Cab Affiliation"
}
default_environment: "TRAINING"
default_environment: "SERVING"

TFDVを使用する場合

ここで行ったように、TFDVはトレーニングパイプラインの開始にのみ適用されると考えるのは簡単ですが、実際には多くの用途があります。さらにいくつかあります:

  • 推論のために新しいデータを検証して、悪い機能を突然受け取り始めていないことを確認します
  • 推論のために新しいデータを検証して、モデルが意思決定面のその部分でトレーニングされていることを確認します
  • 私たちはそれと完了機能エンジニアリングを変換した後、当社のデータの検証(おそらく使用して変換TensorFlowを確認してください、私たちが何かを間違っていないにします)