Path: blob/master/site/ja/datasets/determinism.ipynb
38540 views
Copyright 2020 The TensorFlow Authors.
TFDS と決定論
このドキュメントでは、以下について説明します。
TFDS は決定論を保証する
TFDS が例を読み取る順序
さまざまな警告と落とし穴
MNIST モデルをビルドする
データセット
TFDS がデータを読み取る仕組みを理解するには、何らかのこんてきすとが必要です。
TFDS は生成中に、元のデータを標準化された .tfrecord ファイルに書き込みます。大型のデータセットの場合、複数の .tfrecord ファイルが作成され、ファイルごとに複数の Example が含められます。これらの .tfrecord ファイルはそれぞれシャードと呼ばれています。
このガイドでは、1024 個のシャードを持つ imagenet を使用します。
データセットの Example ID を特定する
決定論についてのみ関心がある場合は、次のセクションにスキップできます。
各データセットの Example は、id によって一意に識別されています(例: 'imagenet2012-train.tfrecord-01023-of-01024__32')。この id は、read_config.add_tfds_id = True によって回復できます。これにより、tf.data.Dataset からの dict に 'tfds_id' キーが追加されます。
このチュートリアルでは、データセットの Example ID を出力する小さな util を定義します(人間が読めるように数値に変換します)。
読み取る際の決定論
このセクションでは、tfds.load の決定論的保証を説明します。
shuffle_files=False を使用する(デフォルト)
デフォルトでは、TFDS は決定論的に Example を生成します(shuffle_files=False)。
パフォーマンスについては、TFDS は tf.data.Dataset.interleave を使用して同時に複数のシャードを読み取ります。この例では、TFDS が 16 個の Example(..., 14, 15, 1251, 1252, ...)を読み取った後に、シャード 2 に切り替えているのがわかります。(..., 14, 15, 1251, 1252, ...)。インターリーブについて以下をご覧ください。
同様に、subsplit API も決定論的です。
2 エポック以上をトレーニングしている場合、すべてのエポックが同じ順序でシャードを読み取るため、上記のセットアップは推奨されません(つまりランダム性は、ds = ds.shuffle(buffer) バッファサイズに制限されています)。
shuffle_files=True を使用する
shuffle_files=True を使用すると、シャードはエポックごとにシャッフルされるため、読み取りは決定論的でなくなってしまいます。
注意: shuffle_files=True に設定することでも、パフォーマンスを促進するために、tf.data.Options で deterministic が無効化されます。そのため、シャードが 1 つしかないような小さなデータセット(mnist など)であっても、非決定論的になります。
決定論的ファイルをシャッフルするには、以下のレシピをご覧ください。
決定論の注意事項: インターリーブ引数
read_config.interleave_cycle_length を変更すると、read_config.interleave_block_length によって Example の順序が変わります。
TFDS は tf.data.Dataset.interleave を使用して、一度に読み込むシャード数を少なくし、パフォーマンスの改善とメモリ使用率の低減を行っています。
Example の順序は、インターリーブ引数の固定値に対してのみ同じであることが保証されています。どの cycle_length と block_length が対応しているかも知るには、インターリーブのドキュメントをご覧ください。
cycle_length=16、block_length=16(デフォルト、上記と同じ):
cycle_length=3、block_length=2:
2 つ目の例では、データセットがシャード内の 2 つの Example(block_length=2)を読み取ってから次のシャードに切り替えていることがわかります。2 x 3(cycle_length=3)Example ごとに、最初のシャードに戻ります(shard0-ex0、shard0-ex1、shard1-ex0、shard1-ex1、shard2-ex0、shard2-ex1、shard0-ex2、shard0-ex3、shard1-ex2、shard1-ex3、shard2-ex2、など)。
Subsplit と Example の順序
各 Example には id 0, 1, ..., num_examples-1 があります。subsplit API は、Example のスライス(例: train[:x] select 0, 1, ..., x-1)を選択します。
ただし、Subsplit の中では、Example は ID の昇順には読み取られません(シャードとインターリーブのため)。
より具体的には、ds.take(x) と split='train[:x]' は同等ではありません!
このことは、Example が様々なシャードから取得される上記のインターリーブの例で簡単に確認できます。
16(block_length)の Example の後、train[:25] が最初のシャードの Example を読み取り続ける間、.take(25) は次のシャードに切り替えます。
レシピ
決定論的ファイルシャッフル
決定的シャッフルを行うには 2 つの方法があります。
shuffle_seedを設定する方法。注意: これにはエポックごとにシードを変更する必要があります。変更しない場合、シャードは、エポックごとに同じ順序で読み取られてしまいます。
experimental_interleave_sort_fnを使用する方法: この場合、ds.shuffleの順序に依存せずに、どのシャードがどの順序で読み取られるかを完全に制御できます。
決定論的プリエンプティブルパイプライン
これはより複雑なレシピです。簡単で満足のいくソリューションはありません。
ds.shuffleを使用せず、決定論的シャッフルを使用すると、理論的には、読み取られた Example をカウントし、どの Example が書くシャード内で読み取られたか(関数cycle_length、block_length、およびシャード順)を演繹することは可能です。その後に、skipと各シャードのtakeをexperimental_interleave_sort_fnを介して注入することができます。ds.shuffleを使用した場合、完全なトレーニングパイプラインを再生せずにはほぼ不可能です。どの Example が読み取られたかを演繹するには、ds.shuffleバッファの状態を保存する必要があります。Example は非連続的(たとえばshard5_ex2,shard5_ex4が読み取られてもshard5_ex3は読み取られないなど)となる可能性があります。.ds.shuffleを使用した場合、読み取られたすべての shards_ids/example_ids(tfds_idから演繹)を保存し、そのからファイルの命令を演繹する方法が考えられます。
1. の最も単純なケースは、.skip(x).take(y) を train[x:x+y] をマッチさせることです。これには以下が必要となります。
cycle_length=1を設定する(シャードが順次読み取られるように)shuffle_files=Falseを設定するds.shuffleを使用しない
トレーニングが 1 エポックだけの大型のデータセットでのみ使用することをお勧めします。Example はデフォルトのシャッフル順に読み取られます。
特定の Subsplit でどのシャード/Example が読み取られたかを調べる
tfds.core.DatasetInfo を使うと、読み取り命令に直接アクセスできます。
TensorFlow.org で表示
Google Colab で実行
GitHub でソースを表示
ノートブックをダウンロード