1. Проблема:
У меня есть tf.data.Dataset
, который я даю модели Keras (tf.python.keras) с train_on_batch
.
Мой набор данных выглядит так:
Generate TFRecord path > tf.data.TFRecordDataset > Parse single example > Batch(2) > Map(merge) > Map(normalize) > Map(split to inputs,labels) > Batch(batch_size) > Prefetch(1)
Я использовал RunMetadata
для вывода временной шкалы, читаемой с помощью Chrome.
Похоже, что IteratorGetNext
работает только на процессоре и потребляет значительное количество времени.
(я не могу опубликовать изображения, IteratorGetNext
заняло 617 мс, MEMCPYHtoD
заняло 58 мс, а обучение заняло 500 мс)
Я не могу найти способ заставить IteratorGetNext работать на GPU, даже частично. В настоящее время процессор используется на 100%, а GPU - не более 40-60%.
Я бы ожидал что-то вроде:
Read from disk > Move from CPU to GPU > Preprocess.
В настоящее время я использую только один графический процессор, но позже я планирую использовать больше графических процессоров, чтобы было бы идеально масштабируемое решение!
Кстати, я использую tenorflow-gpu 1.13.1 в Windows 10 с CUDA 10.0 и python 3.6.7. Я не использую нетерпеливый режим.
Я не пробовал Ubuntu, но это возможно.
2. Что я пробовал:
Я пытался использовать prefetch_to_device
и copy_to_device
из tf.data.experimental
в нескольких местах в конвейере.
При использовании copy_to_device
IteratorGetNext занимал в два раза больше времени. Это выглядело так, как будто он копировал на GPU, чтобы копировать только обратно в CPU, потому что MEMCPYHtoD
все еще присутствовал после IteratorGetNext.
Я попытался заменить Keras 'train_on_batch
на session.run(train_op)
, но он не улучшился, единственное изменение, которое я заметил, это то, что действительно произошла некоторая предварительная выборка, уменьшив время IteratorGetNext для нескольких выборок (независимо от количества, которое я вставил) упреждающий ").
Кстати, prefetch(1)
или prefetch(tf.data.experimental.AUTOTUNE)
, похоже, не оказали никакого влияния.
Я пробовал session.run
как с, так и без copy_to_device
.
Я также пытался поместить здание набора данных в with tf.device("/gpu:0")
.
3. Какой-то код:
dataset = tf.data.Dataset.from_generator(self.random_shard_filepath_generator,
output_types=tf.string,
output_shapes=())
dataset = tf.data.TFRecordDataset(dataset)
dataset = dataset.map(lambda serialized_shard: self.parse_shard(serialized_shard, output_labels))
dataset = dataset.batch(self.shards_per_sample)
dataset = dataset.map(self.join_shards_randomly)
dataset = dataset.map(self.normalize_batch)
dataset = dataset.map(self.split_batch_io)
dataset = dataset.batch(batch_size).prefetch(1)
autoencoder.train_on_batch(dataset)
Наконец, я бы добавил, что моя модель может быть недостаточно большой, и я мог бы улучшить соотношение, просто увеличив его, но это не похоже на отличное решение.
- Изменить:
У меня было:
...
dataset = dataset.batch(batch_size).prefetch(1)
autoencoder.train_on_batch(dataset)
Который я изменил на:
...
dataset = dataset.batch(batch_size).prefetch(1)
dataset_iterator = dataset.make_initializable_iterator()
dataset_initializer = dataset_iterator.initializer
session.run(dataset_initializer)
x, y = dataset_iterator
autoencoder.train_on_batch(x, y)
Спасибо EdoardoG
за то, что заставили меня попробовать MultiDeviceIterator
, что заставило меня создать Iterator
вне Keras 'train_on_batch
.
Теперь IteratorGetNext
занимает всего около 0,05 мс, тогда как раньше - около 600 мс.