API набора данных Tensorflow не использует графический процессор - PullRequest
2 голосов
/ 06 мая 2019

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 мс.

Ответы [ 2 ]

0 голосов
/ 07 мая 2019

Насколько мне известно, операции API набора данных обычно выполняются на процессоре, поэтому на самом деле нормально, что вы не можете запустить свой конвейер ввода на графическом процессоре.

Кто-то написал итератор который может решить вашу проблему.

0 голосов
/ 06 мая 2019

Оберните свой NN-код, используя with tf.device('/gpu:0'):, где gpu: 0 - это первый графический процессор в вашей системе.

Если вы хотите использовать несколько графических процессоров:

for d in ['/device:GPU:2', '/device:GPU:3']:
  with tf.device(d):
    <your code here>

Некоторые полезные рекомендациис сайта tenorflow

...