TensorflowでマルチGPUジョブを実行し、キューベースモデル(string_input_producerインターフェースを使用)から新しいTensorflow Dataset APIへの移行を評価しています。後者は、TrainとValidationを同時に切り替える簡単な方法を提供するようです。
以下のコードスニペットは、これを行う方法を示しています。
train_dataset, train_iterator = get_dataset(train_files, batch_size, epochs)
val_dataset, val_iterator = get_dataset(val_files, batch_size, epochs)
is_validating = tf.placeholder(dtype=bool, shape=())
next_batch = tf.cond(is_validating,
lambda: val_iterator.get_next(),
lambda: train_iterator.get_next())
validation_tower = self.num_gpus - 1
tower_grads = []
for i in range(self.num_gpus):
with tf.variable_scope(tf.get_variable_scope(),reuse=(i > 0)):
with tf.device('/gpu:%d' % i), tf.name_scope('%s_%d' % ('gpu_', i)) as scope:
if i == validation_tower:
images, labels = next_batch
# Loss funcs snipped out
else:
images, labels = next_batch
# Loss funcs snipped out
Get_dataset関数は、データセットを構築し、マップ関数とバッチサイズを設定します。イテレータも作成しますが、初期化はしません。イテレータの初期化は、セッションの開始前に行われます。
Is_validatingブール値はセッションの実行中に提供され、検証データセットを使用するためにfeed_dictを介してis_validatingをTrueとして渡すいくつかのステップごとに
私が持っている質問は:
8つのGPUがあるとしましょう。したがって、7つのGPUでトレーニングを実行します。イテレーターはこれらの7つのGPUのそれぞれについて同じポイントから進み、7つのGPUすべてに同じデータを提供しますか?
現在、3つの主なオプションがあり、使いやすさとパフォーマンスのトレードオフが異なります。
Dataset.batch()
変換で、すべてのGPUの例を含む単一の大きなバッチを作成します。次に、tf.split(..., self.num_gpus)
の出力で Iterator.get_next()
を使用して、各GPUのサブバッチを作成します。これはおそらく最も簡単な方法ですが、クリティカルパスに分割を配置します。
Dataset.batch()
変換で、単一のGPUに合わせたサイズのミニバッチを作成します。次に、GPUごとに1回Iterator.get_next()
を呼び出して、複数の異なるバッチを取得します。 (対照的に、現在のコードでは、_next_batch
_の同じ値が各GPUに送信されますが、これはおそらくあなたが望んでいたことではありません。)
GPUごとに1つずつ、複数のイテレーターを作成します。 Dataset.shard()
を使用してデータをシャーディングします(たとえば、データセットがシャーディングされている場合は、ファイルのリストで)。このアプローチはホスト上のより多くのリソースを消費するため、バッファーサイズや並列度をダイヤルダウンする必要がある場合があることに注意してください。
現在の_tf.data
_パイプラインはCPUでのみ実行され、効率的なパイプラインの重要な側面は、前のステップがまだ実行されている間にトレーニング入力をGPUにステージングすることです。データをGPUに効率的にステージングする方法を示すコード例については、 TensorFlow CNNベンチマーク を参照してください。現在、このサポートを_tf.data
_ APIに直接追加する作業を行っています。