Apache MXNet - распределенное обучение

Эта глава посвящена распределенному обучению в Apache MXNet. Давайте начнем с понимания, каковы режимы вычислений в MXNet.

Режимы вычисления

MXNet, многоязычная библиотека ML, предлагает своим пользователям следующие два режима вычислений:

Императивный режим

Этот режим вычислений предоставляет интерфейс, подобный NumPy API. Например, в MXNet используйте следующий императивный код для построения тензора нулей как на CPU, так и на GPU:

import mxnet as mx
tensor_cpu = mx.nd.zeros((100,), ctx=mx.cpu())
tensor_gpu= mx.nd.zeros((100,), ctx=mx.gpu(0))

Как мы видим в приведенном выше коде, MXNets указывает место, где хранить тензор, в ЦП или устройстве ГП. В приведенном выше примере он находится в местоположении 0. MXNet обеспечивает невероятное использование устройства, потому что все вычисления выполняются лениво, а не мгновенно.

Символьный режим

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

С другой стороны, символьный режим предоставляет граф вычислений, такой как TensorFlow. Он устраняет недостаток императивного API, позволяя MXNet работать с символами или переменными вместо фиксированных / предварительно определенных структур данных. Впоследствии символы можно интерпретировать как набор операций следующим образом:

import mxnet as mx
x = mx.sym.Variable(“X”)
y = mx.sym.Variable(“Y”)
z = (x+y)
m = z/100

Виды параллелизма

Apache MXNet поддерживает распределенное обучение. Это позволяет нам использовать несколько машин для более быстрого и эффективного обучения.

Ниже приведены два способа, с помощью которых мы можем распределить рабочую нагрузку по обучению NN на несколько устройств, CPU или GPU.

Параллелизм данных

При таком виде параллелизма каждое устройство хранит полную копию модели и работает с другой частью набора данных. Устройства также совместно обновляют общую модель. Мы можем разместить все устройства на одной или нескольких машинах.

Параллелизм моделей

Это еще один вид параллелизма, который удобен, когда модели настолько велики, что не помещаются в память устройства. В параллелизме моделей разным устройствам ставится задача изучения разных частей модели. Здесь важно отметить, что в настоящее время Apache MXNet поддерживает параллелизм моделей только на одной машине.

Работа распределенного обучения

Приведенные ниже концепции являются ключом к пониманию работы распределенного обучения в Apache MXNet.

Типы процессов

Процессы взаимодействуют друг с другом, чтобы выполнить обучение модели. Apache MXNet имеет следующие три процесса:

Рабочий

Задача рабочего узла - выполнять обучение на пакете обучающих выборок. Узлы Worker будут получать веса с сервера перед обработкой каждого пакета. Узлы Worker будут отправлять градиенты на сервер после обработки пакета.

Сервер

MXNet может иметь несколько серверов для хранения параметров модели и для связи с рабочими узлами.

Планировщик

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

Магазин КВ

KV магазины - это Key-Valueмагазин. Это важный компонент, используемый для обучения с использованием нескольких устройств. Это важно, потому что передача параметров между устройствами на одной или нескольких машинах передается через один или несколько серверов с KVStore для параметров. Давайте разберемся в работе KVStore с помощью следующих пунктов -

  • Каждое значение в KVStore представлено key и value.

  • Каждому массиву параметров в сети назначается key и веса этого массива параметров обозначаются как value.

  • После этого рабочие узлы pushградиенты после обработки партии. Они такжеpull обновленные веса перед обработкой новой партии.

Понятие сервера KVStore существует только во время распределенного обучения, а его распределенный режим включается вызовом mxnet.kvstore.create функция со строковым аргументом, содержащим слово dist -

kv = mxnet.kvstore.create(‘dist_sync’)

Раздача ключей

Необязательно, чтобы все серверы хранили весь массив параметров или ключи, но они распределены по разным серверам. Такое распределение ключей по разным серверам прозрачно обрабатывается KVStore, и решение о том, на каком сервере хранится конкретный ключ, принимается произвольно.

KVStore, как обсуждалось выше, гарантирует, что всякий раз, когда ключ извлекается, его запрос отправляется на тот сервер, который имеет соответствующее значение. Что делать, если значение какого-то ключа велико? В этом случае он может использоваться на разных серверах.

Разделить данные обучения

Как пользователи, мы хотим, чтобы каждая машина работала с разными частями набора данных, особенно при выполнении распределенного обучения в параллельном режиме данных. Мы знаем, что для разделения пакета выборок, предоставленных итератором данных для параллельного обучения данных на одном воркере, мы можем использоватьmxnet.gluon.utils.split_and_load а затем загрузите каждую часть партии в устройство, которое будет обрабатывать ее дальше.

С другой стороны, в случае распределенного обучения нам нужно сначала разделить набор данных на nразные детали, так что каждый рабочий получает другую деталь. После получения каждый рабочий может использоватьsplit_and_loadчтобы снова разделить эту часть набора данных на разные устройства на одной машине. Все это происходит через итератор данных.mxnet.io.MNISTIterator а также mxnet.io.ImageRecordIter два таких итератора в MXNet, которые поддерживают эту функцию.

Обновление весов

Для обновления весов KVStore поддерживает следующие два режима:

  • Первый метод агрегирует градиенты и обновляет веса, используя эти градиенты.

  • Во втором методе сервер только агрегирует градиенты.

Если вы используете Gluon, есть возможность выбрать один из вышеуказанных методов, передав update_on_kvstoreпеременная. Давайте разберемся в этом, создавtrainer объект следующим образом -

trainer = gluon.Trainer(net.collect_params(), optimizer='sgd',
   optimizer_params={'learning_rate': opt.lr,
      'wd': opt.wd,
      'momentum': opt.momentum,
      'multi_precision': True},
      kvstore=kv,
   update_on_kvstore=True)

Режимы распределенного обучения

Если в строке создания KVStore есть слово dist, значит, включено распределенное обучение. Ниже приведены различные режимы распределенного обучения, которые можно включить с помощью различных типов KVStore.

dist_sync

Как следует из названия, это означает синхронное распределенное обучение. При этом все рабочие используют один и тот же синхронизированный набор параметров модели в начале каждой партии.

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

dist_async

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

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

dist_sync_device

Этот режим такой же, как dist_syncРежим. Единственное отличие состоит в том, что, когда на каждом узле используется несколько графических процессоровdist_sync_device агрегирует градиенты и обновляет веса на GPU, тогда как dist_sync агрегирует градиенты и обновляет веса в памяти ЦП.

Это снижает дорогостоящую связь между GPU и CPU. Поэтому он быстрее, чемdist_sync. Недостатком является то, что это увеличивает использование памяти на GPU.

dist_async_device

Этот режим работает так же, как dist_sync_device режим, но в асинхронном режиме.