Масштабирование tf.io.gfile.GFile со скоростью до 100 МБ / с - PullRequest
6 голосов
/ 10 января 2020

Чтобы полностью использовать графический процессор во время обучения, мне нужно иметь возможность передавать около 250 МБ / с необработанных данных в графический процессор (данные не сжимаются). Я получаю доступ к данным через быструю сеть, которая может без проблем работать со скоростью более 2 ГБ / с c. GIL Python делает довольно сложным включение этих скоростей в тот же процесс, который запускает Tensorflow без негативного влияния на тренировку l oop. Общая память Python 3.8 может облегчить это, но это пока не поддерживается Tensorflow.

Поэтому я использую tf.io.gfile.GFile для чтения данных по сети (данные хранятся на высокой пропускной способности S3 совместимый интерфейс). Значение GFile состоит в том, что он не задействует GIL и, таким образом, хорошо играет с обучением l oop. Для достижения высокой пропускной способности требуется существенное распараллеливание сетевого ввода-вывода.

Мне кажется, что я могу получить только 75-100 МБ / с c из этого подхода.

Я рассчитал два подхода:

  • Создайте tf.data.Dataset и используйте tf.data.Dataset.map(mymapfunc, num_parallel_calls=50) (я пробовал много значений num_parallel_calls, включая AUTOTUNE).
  • Создайте функцию, которая читает данные, используя tf.io.gfile.GFile, и просто запустите ее, используя несколько потоков в concurrent.futures.ThreadPoolExecutor, попытка подсчитать количество потоков примерно до 100 (улучшение не превышает примерно 20, и в конечном итоге больше потоков замедляет ее вниз).

В обоих случаях у меня стоит 75-100 МБ / с c.

Вопросы:

Мне интересно, есть ли причина для GFile для достижения верхнего предела, который, возможно, более очевиден для кого-то еще.

Я также предполагаю, что мне следует проверить: tf.io.gfile.GFile работает на numpy земле, в обоих случаях выше, я выполняю GFile операций с python земли (в случае tf.data.Dataset Я использую tf.py_function). Если GFile предназначен для более эффективного выполнения операций с графами, я не знаю об этом и должен быть исправлен.

1 Ответ

0 голосов
/ 03 февраля 2020

Окончательное решение этого вопроса для меня таково:

  • Я не могу загрузить GFile с особенно высокой скоростью, boto3.Client.download_file намного быстрее, поскольку в нем используются несколько потоков.
  • Я запустил отдельный процесс (multiprocessing) для обработки ввода-вывода через boto3, он локально загружает непрерывно меняющееся окно большого (терабайт +) набора данных.
  • Затем выполняется выборка другого процесса локальные файлы и записывает файлы TF Records на RAM-диск, затем он передает имена файлов на tf.data.TFRecordDataset во время их записи.
  • Необходимо было передать потоки данных большого масштаба в тензорный поток через файлы TFRecords, потому что десериализация в Python заблокирует GIL и задержит обучение l oop (в частности, общая память SystemV для Python 3.8 может решить эту проблему, но TF 2.2 - первая версия, ожидаемая для поддержки Python 3.8 ).
  • Диск RAM избежал перегрузки ввода-вывода, хотя мне все еще требовалась производительность ввода-вывода уровня NVMe для одновременной загрузки (10 0 МБ / с c IO), чтение файлов необработанных данных и создание записей tf (200 МБ / с c IO).
  • Мое оптимальное решение для работы с набором данных терабайт +, который не полностью подходил локально - загружать непрерывно обновляемое окно файлов необработанных данных локально через boto3 и запускать 2 процесса, выбирая из доступных локальных файлов и записывая файлы TF Records на RAM-диск, затем передавая эти имена файлов в tf.data.TFRecordDataset, поскольку они генерируются. Компоненты могут быть написаны почти полностью отделенными, поэтому отладка не страшна.
  • При таком решении графический процессор остается> 90%. IO требует около 300 МБ / с c совокупного чтения / записи. Использование памяти: ~ 10 ГБ в ОЗУ и ~ 5 ГБ в процессах. Эта модель использует около 200 МБ / с c необработанных (несжимаемых) данных.
...