Chainer: производительность ParallelUpdater против MultiprocessUpdater

Я хотел бы обучить CNN на наборе данных CIFAR10 с цепочкой на нескольких графических процессорах на одном узле. Я попытался адаптировать этот пример для использования ParallelUpdater в способом, идентичным параллельному примеру данных mnist но производительность обучения была очень низкой - медленнее, чем обучение на одном графическом процессоре, хотя использовались все 8 графических процессоров. Я перешел на MultiprocessUpdater, и производительность (итеров в секунду) стала намного лучше.

Плохой:

num_gpus = 8
chainer.cuda.get_device_from_id(0).use()
train_iter = chainer.iterators.SerialIterator(train, batch_size)

if num_gpus > 0:
    updater = training.updater.ParallelUpdater(
        train_iter,
        optimizer,
        devices={('main' if device == 0 else str(device)): device for device in range(num_gpus)},
    )
else:
    updater = training.updater.StandardUpdater(train_iter, optimizer, device=0)

Хорошо:

num_gpus = 8

devices = range(num_gpus)

train_iters = [chainer.iterators.MultiprocessIterator(i, batch_size, n_processes=num_gpus) \
               for i in chainer.datasets.split_dataset_n_random(train, len(devices))]
test_iter = chainer.iterators.MultiprocessIterator(test, batch_size, repeat=False, n_processes=num_gpus)
device = 0 if num_gpus > 0 else -1  # -1 indicates CPU, 0 indicates first GPU device.

if num_gpus > 0:
    updater = training.updaters.MultiprocessParallelUpdater(train_iters, optimizer, devices=range(num_gpus))
else:
    updater = training.updater.StandardUpdater(train_iters[0], optimizer, device=device)

Я также запускал эти сценарии тестирования с 8 графическими процессорами, используя ParallelUpdater, но производительность также была очень низкой: https://github.com/mitmul/chainer-cifar10/blob/master/train.py

У меня вопрос: как добиться хорошей производительности от ParallelUpdater и что я могу с ним делать не так?

Спасибо!


person Andre    schedule 03.05.2018    source источник


Ответы (2)


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

person Taizan Yonetuji    schedule 04.05.2018
comment
Ах я вижу. К сожалению, я не смог найти никакой комбинации размера пакета и скорости обучения, которая значительно ускорила обучение (по крайней мере, не близка к линейной, на что я надеялся). - person Andre; 04.05.2018

Я не так хорошо знаком с ParallelUpdater, поэтому мое понимание может быть неправильным.

Я предполагаю, что цель ParallelUpdater не в быстродействии, а в том, чтобы эффективно использовать память для вычисления градиента большого пакета.

При чтении исходного кода обновление модели выполняется в цикле python for, поэтому из-за механизма GIL (Global Interpreter Lock) я предполагаю, что его вычисление не выполняется параллельно. https://github.com/chainer/chainer/blob/master/chainer/training/updaters/parallel_updater.py#L118

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

Кроме того, вы можете рассмотреть возможность использования ChainerMN, которая представляет собой библиотеку расширений для обучения с несколькими графическими процессорами с помощью цепочки.

person corochann    schedule 04.05.2018
comment
поэтому из-за механизма GIL (Global Interpreter Lock) я предполагаю, что его вычисление не выполняется параллельно. Я понимаю, в этом есть смысл. Я буду придерживаться MultiprocessParallelUpdater для скорости - пока я пытаюсь обеспечить быстрое обучение на одном узле без необходимости использования MPI. (Поскольку chainermn и MultiprocessParallelUpdater используют NCCL, я ожидаю аналогичной производительности) - person Andre; 04.05.2018