Является ли генератор классов (наследующий последовательность) потокобезопасным в Keras / Tensorflow? - PullRequest
0 голосов
/ 22 октября 2018

Для ускорения обучения модели представляется целесообразным заполнять / генерировать пакеты на процессоре и параллельно проводить обучение модели на графическом процессоре.Для этого на Python может быть написан класс генератора, который наследует класс Sequence.

Вот ссылка на документацию: https://www.tensorflow.org/api_docs/python/tf/keras/utils/Sequence

Важная вещь, о которой говорится в документеis:

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

И это дает простой пример кода:

from skimage.io import imread
from skimage.transform import resize
import numpy as np
import math

# Here, `x_set` is list of path to the images
# and `y_set` are the associated classes.

class CIFAR10Sequence(Sequence):

    def __init__(self, x_set, y_set, batch_size):
        self.x, self.y = x_set, y_set
        self.batch_size = batch_size

    def __len__(self):
        return math.ceil(len(self.x) / self.batch_size)

    def __getitem__(self, idx):
        batch_x = self.x[idx * self.batch_size:(idx + 1) *
        self.batch_size]
        batch_y = self.y[idx * self.batch_size:(idx + 1) *
        self.batch_size]

        return np.array([
            resize(imread(file_name), (200, 200))
               for file_name in batch_x]), np.array(batch_y)

Что, на мой взгляд, в идеале нужно сделать в модели, это создать экземпляр этого класса генератора и передать его функции fit_generator(...).

gen = CIFAR10Sequence(x_set, y_set, batch_size)
# Train the model
model.fit_generator(generator=gen,
                    use_multiprocessing=True,
                    workers=6)

Вот цитата из документации Keras:

Использование keras.utils.Sequence гарантирует порядок и гарантирует однократное использование каждого входа за эпоху при использовании use_multiprocessing=True.

В этой форме я предполагаю, что эта установка является поточно-ориентированной. Вопрос 1) Правильно ли мое предположение?

Одна сбивающая с толку вещь заключается в том, что параметр use_multiprocessing не может быть установлен в True в Windows 10. Keras не допускает этого;По-видимому, это может быть установлено в True только в Linux.(Я не знаю, как это происходит на других платформах.) Но для параметра workers все равно можно установить значение, которое больше 0.

Давайте посмотрим на определение этих двух параметров:

workers: Целое число.Максимальное количество процессов, которые могут ускоряться при использовании потоков на основе процессов.Если не указано, рабочие по умолчанию будут равны 1. Если 0, генератор будет выполняться в главном потоке.

use_multiprocessing: Boolean.Если True, используйте основанные на процессах потоки.Если не указано, use_multiprocessing по умолчанию будет False.Обратите внимание, что поскольку эта реализация опирается на многопроцессорность, вы не должны передавать невыгружаемые аргументы генератору, поскольку их нелегко передать дочерним процессам.

Итак, используя параметр workersпредставляется возможным создать несколько процессов для ускорения обучения независимо от того, является ли use_multiprocessing Истиной или нет.

Если кто-то хочет использовать класс генератора, наследующий Sequence ( в Windows10 ), он / она должен установить для use_multiprocessing значение False следующим образом:

gen = CIFAR10Sequence(x_set, y_set, batch_size)
# Train the model
model.fit_generator(generator=gen,
                    use_multiprocessing=False,  # CHANGED
                    workers=6)

И здесь все еще выполняется несколько процессов, потому что рабочий = 6.

Вопрос 2) Эта настройка все еще поддерживает потокобезопасность или характеристика потока безопасна теперь, если для параметра use_multiprocessing установлено значение False?Я не могу объяснить это на основании документации.

Вопрос 3) По-прежнему относится к этой теме ... Когда обучение выполняется таким образом, когда данные генерируются процессором, а обучение на графическом процессореесли обучаемая модель является мелкой, загрузка графического процессора заканчивается на очень низком уровне, а загрузка процессора становится значительно выше, поскольку графический процессор продолжает ожидать данные, поступающие из процессора.В таких случаях, есть ли способ использовать ресурсы GPU для генерации данных?

1 Ответ

0 голосов
/ 04 декабря 2018

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

По-видимому, написание класса-генератора на Python, который наследует класс Sequence, просто не поддерживается в Windows .(Казалось бы, вы можете заставить его работать в Linux.) Чтобы иметь возможность заставить его работать, вам нужно установить параметр use_multiprocessing=True (с подходом класса).Но это не работает в Windows, как уже упоминалось, поэтому вы должны установить use_multiprocessing в False (в Windows).Тем не менее, это не означает, что многопроцессорность не работает в Windows.Даже если вы установите use_multiprocessing=False, многопроцессорная обработка может поддерживаться при выполнении кода со следующей настройкой, в которой для параметра workers вы просто устанавливаете любое значение больше 1.

Пример:

history = \
   merged_model.fit_generator(generator=train_generator,
                              steps_per_epoch=trainset_steps_per_epoch,
                              epochs=300,
                              verbose=1,
                              use_multiprocessing=False,
                              workers=3,
                              max_queue_size=4)

На этом этапе давайте снова вспомним документацию Keras:

Использование keras.utils.Sequence гарантирует упорядочение и гарантирует одно использование каждого ввода за эпоху при использованииuse_multiprocessing = True.

Насколько я понимаю, если use_multiprocessing=False, то генератор больше не является потокобезопасным, что затрудняет написание класса генератора , который наследует Sequence.

Чтобы обойти эту проблему, я сам написал генератор, который вручную сделал потокобезопасным.Вот пример псевдокода:

import tensorflow as tf
import threading

class threadsafe_iter:
    """Takes an iterator/generator and makes it thread-safe by
    serializing call to the `next` method of given iterator/generator.
    """
    def __init__(self, it):
        self.it = it
        self.lock = threading.Lock()

    def __iter__(self):
        return self

    def __next__(self): # Py3
        return next(self.it)

    #def next(self):     # Python2 only
    #    with self.lock:
    #        return self.it.next()

def threadsafe_generator(f):
    """A decorator that takes a generator function and makes it thread-safe.
    """
    def g(*a, **kw):
        return threadsafe_iter(f(*a, **kw))
    return g


@threadsafe_generator
def generate_data(tfrecord_file_path_list, ...):

    dataset = tf.data.TFRecordDataset(tfrecord_file_path_list)

    # example proto decode
    def _parse_function(example_proto):
      ...
      return batch_data

    # Parse the record into tensors.
    dataset = dataset.map(_parse_function)  

    dataset = dataset.shuffle(buffer_size=100000)

    # Repeat the input indefinitly
    dataset = dataset.repeat()  

    # Generate batches
    dataset = dataset.batch(batch_size)

    # Create an initializable iterator
    iterator = dataset.make_initializable_iterator()

    # Get batch data
    batch_data = iterator.get_next()

    iterator_init_op = iterator.make_initializer(dataset)

    with tf.Session() as sess:

        sess.run(iterator_init_op)

        while True:            
            try:
                batch_data = sess.run(batch_data)
            except tf.errors.OutOfRangeError:
                break
            yield batch_data

Что ж, это можно обсудить, если это действительно элегантно сделать таким образом, но, кажется, он работает довольно хорошо.

Подводя итог:

  • Если вы пишете свою программу в Windows, установите use_multiprocessing в False.
  • (Насколько мне известно) на данный момент не поддерживается создание класса генератора, которыйнаследует Sequence при написании кода в Windows.(Думаю, это проблема Tensorflow / Keras).
  • Чтобы обойти эту проблему, напишите обычный генератор, сделайте ваш поток генератора безопасным и установите для workers значение больше 1.

Важное примечание: В этой настройке генератор работает на CPU, а обучение - на GPU.Одна проблема, которую я мог бы заметить, заключается в том, что если модель, которую вы тренируете, достаточно поверхностна, использование графического процессора остается очень низким, а загрузка процессора - высокой.Если модель мелкая и набор данных достаточно мал, это может быть хорошим вариантом для сохранения всех данных в памяти и запуска всего на GPU.Это должно значительно ускорить обучение.Если по какой-либо причине вы хотите использовать ЦП и ГП одновременно, моя скромная рекомендация состоит в том, чтобы попытаться использовать API Tensorflow tf.data, который значительно ускоряет предварительную обработку данных и пакетную подготовку.Если генератор написан только на Python, GPU продолжает ждать данных, чтобы продолжить обучение.Можно сказать все о документации Tensorflow / Keras, но это действительно эффективный код!

Любой, кто обладает более полным знанием API и видит этот пост, не стесняйтесь поправлять меня здесь, если я что-то неправильно понимаю илиAPI обновлен для решения проблем даже в Windows.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...