API набора данных Tensorflow медленнее, чем очереди?

Я заменил конвейер предварительной обработки CIFAR-10 в проекте подходом Dataset API, что привело к снижению производительности примерно на 10-20%.

Предварительная обработка довольно стандартна: - читать изображение с диска - произвольно / обрезать и переворачивать - перемешивать, пакетно - передавать в модель

В целом я вижу, что пакетная обработка теперь на 15% быстрее, но время от времени (или, точнее, всякий раз, когда я повторно инициализирую фрейм данных или ожидаю перетасовки), пакет блокируется на долгое время (30 секунд), что в сумме составляет более медленную эпоху -периодическая обработка.

Такое поведение, похоже, связано с внутренним хешированием. Если я уменьшу N в ds.shuffle (buffer_size = N), задержки будут короче, но пропорционально более частыми. Удаление перемешивания во всех результатах приводит к задержкам, как если бы buffer_size был установлен равным размеру набора данных.

Может ли кто-нибудь объяснить внутреннюю логику Dataset API, когда дело доходит до чтения / кеширования? Есть ли вообще причина ожидать, что API набора данных будет работать быстрее, чем очереди, созданные вручную?

Я использую TF 1.3.


person y.selivonchyk    schedule 21.11.2017    source источник


Ответы (2)


Если вы реализуете тот же конвейер с помощью _1 _ API и использование очередей, производительность версии набора данных должна быть лучше, чем версия на основе очереди.

Однако есть несколько рекомендаций по производительности, которые необходимо соблюдать, чтобы добиться максимальной производительности. Мы собрали их в руководстве по производительности для tf.data. Вот основные проблемы:

  • Предварительная выборка важна: конвейеры на основе очередей выполняют предварительную выборку по умолчанию, а конвейеры набора данных - нет. Добавление dataset.prefetch(1) в конец вашего конвейера даст вам большую часть преимуществ предварительной выборки, но вам может потребоваться дополнительная настройка.

  • Оператор перемешивания имеет задержку в начале, пока он заполняет свой буфер. Конвейеры на основе очередей перемешивают конкатенацию всех эпох, что означает, что буфер заполняется только один раз. В конвейере набора данных это будет эквивалентно dataset.repeat(NUM_EPOCHS).shuffle(N). Напротив, вы также можете написать dataset.shuffle(N).repeat(NUM_EPOCHS), но для этого необходимо перезапускать перемешивание в каждую эпоху. Последний подход немного предпочтительнее (и более соответствует определению SGD, например), но разница может быть незаметной, если ваш набор данных большой.

    Мы добавляем объединенную версию shuffle-and-repeat, которая не вызывает задержки, а ночная сборка TensorFlow будет включать пользовательский _ 6_ преобразование, которое эквивалентно dataset.shuffle(N).repeat(NUM_EPOCHS), но не страдает задержкой в ​​начале каждой эпохи.

Сказав это, если у вас есть конвейер, который значительно медленнее при использовании tf.data, чем очереди, сообщите о проблеме GitHub. с подробностями, и мы посмотрим!

person mrry    schedule 22.12.2017

Предлагаемые вещи не решали мою проблему в те дни, но я хотел бы добавить пару рекомендаций для тех, кто не хочет узнавать об очередях и при этом получать максимальную отдачу от конвейера данных TF:

.

files = tf.data.Dataset.list_files(data_dir)
ds = tf.data.TFRecordDataset(files, num_parallel_reads=32)
ds = (ds.shuffle(10000)
    .repeat(EPOCHS)
    .map(parser_fn, num_parallel_calls=64)
    .batch(batch_size)
)
dataset = dataset.prefetch(2)

Здесь следует обратить внимание на 3 основных компонента:

  • num_parallel_read=32 для распараллеливания дисковых операций ввода-вывода
  • num_parallel_calls=64 для распараллеливания вызовов функции синтаксического анализатора
  • prefetch(2)
person y.selivonchyk    schedule 27.05.2019