Обучение нескольких нейронных сетей асинхронно параллельно - PullRequest
3 голосов
/ 05 марта 2020

Проблема

В настоящее время я работаю над проектом, которым, к сожалению, не могу поделиться с вами. Проект о гиперпараметрической оптимизации для нейронных сетей, и требует, чтобы я параллельно обучал несколько моделей нейронных сетей (больше, чем я могу хранить на моем GPU) Сетевые архитектуры остаются прежними, но сетевые параметры и гиперпараметры подвергаются изменениям между каждым интервалом обучения. В настоящее время я достигаю этого, используя PyTorch в среде linux, чтобы позволить NVIDIA GTX 1660 (6 ГБ ОЗУ) использовать функцию многопроцессорной обработки, которую предоставляет PyTorch.

Код (упрощенный):

def training_function(checkpoint):
   load(checkpoint)
   train(checkpoint)
   unload(checkpoint)

for step in range(training_steps):
   trained_checkpoints = list()
   for trained_checkpoint in pool.imap_unordered(training_function, checkpoints):
      trained_checkpoints.append(trained_checkpoint)
   for optimized_checkpoint in optimize(trained_checkpoints):
      checkpoints.update(optimized_checkpoint)

В настоящее время я тестирую с набором из 30 нейронных сетей (то есть с 30 контрольными точками) с наборами данных MNIST и FashionMNIST, которые состоят из 70 000 (50k обучение, 10k проверка, 10k тестирование) изображений 28x28 с 1 каналом, соответственно. Сеть, которую я обучаю, представляет собой простую реализацию Lenet5.

Я использую пул torch.multiprocessing и позволяю создавать 7 процессов. Каждый процесс использует часть доступной памяти графического процессора только для инициализации среды CUDA в каждом процессе. После обучения контрольные точки адаптируются с помощью моей техники оптимизации гиперпараметров.

Функция load в training_function загружает состояние модели и оптимизатора (содержит тензоры сетевых параметров) из локального файла в Память GPU с использованием torch.load. unload сохраняет вновь обученные состояния обратно в файл, используя torch.save, и удаляет их из памяти. Я делаю это потому, что PyTorch будет отсоединять тензоры GPU только тогда, когда на них не ссылается ни одна переменная. Я должен сделать это, потому что у меня ограниченная память GPU.

Текущая настройка работает, но каждая инициализация CUDA занимает более 700 МБ ОЗУ GPU, и поэтому мне интересно, есть ли другие способы, которые я мог бы сделать это, которые могут использовать меньше памяти без ущерба для эффективности.

Мои попытки

Я подозревал, что могу использовать пул потоков для экономии памяти, и это имело место. Создав 7 потоков вместо 7 процессов, CUDA был инициализирован только один раз, что сэкономило почти половину моей памяти. Тем не менее, это приводит к новой проблеме, в которой графический процессор используется только ок. 30% загрузка в соответствии с nvidia-smi, которую я отслеживаю в отдельном linux терминале. Без потоков я получаю около 85-90% использования.

Я также перепутал с torch.multiprocessing.set_sharing_strategy, который в настоящее время установлен как 'file_descriptor', но безуспешно.

Мои вопросы

  1. Существует ли лучший способ работы с несколькими состояниями модели и оптимизатора без сохранения и загрузки их в файлы во время обучения? Я пытался переместить модель в ЦП с помощью model.cpu() перед сохранением state_dict, но в моей реализации это не сработало (утечки памяти).
  2. Существует ли эффективный способ обучения нескольких нейронных сетей на в то же время, что использует меньше памяти GPU? При поиске в Интернете я нахожу ссылки только на nn.DataParallel, который обучает одну и ту же модель на нескольких графических процессорах, копируя ее на каждый графический процессор. Это не работает для моей проблемы.

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

Обновление (09.03.2020)

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

Еще одно важное замечание: при передаче устройство (например, 'cuda: 1') для каждой torch.cuda -функции, вы можете обнаружить, что torch делает что-то с устройством cuda по умолчанию 'cuda: 0' где-то в коде, инициализируя CUDA на этом устройстве для каждого процесса, который тратит память на нежелательная и ненужная инициализация CUDA. Я исправил эту проблему с помощью with torch.cuda.device(device_id), который инкапсулирует все training_function.

. В итоге я не использовал многопроцессорные пулы и вместо этого определил свой собственный класс процессов, который содержит устройство и функцию обучения. Это означает, что мне нужно поддерживать очереди для каждого процесса устройства, но все они имеют одну и ту же очередь, то есть я могу получить результаты, как только они станут доступны. Я подумал, что написать собственный класс процесса проще, чем написать собственный класс пула. Я отчаянно пытался продолжать использовать пулы, поскольку они легко поддерживаются, но мне пришлось использовать несколько imap -функций, и поэтому результаты не могли быть получены по одному за раз, что приводило к менее эффективной тренировке - l oop.

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

Running 20 processes shared equally among two GPUs. The majority of the memory is allocated to CUDA initialization.

Обновление (10.03.2020 )

Я реализовал другой способ хранения заявлений модели и оптимизатора вне ОЗУ графического процессора. Я написал функцию, которая заменяет каждый тензор в диктантах на .to('cpu') эквивалент. Это стоит мне немного памяти процессора, но это более надежно, чем хранение локальных файлов.

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