0x00 сводка
Эта статья основана на нескольких официальных документах PyTorch для понимания дизайна и внутренней структуры распределенного автограда, при переводе нет дословного перевода, и к нему добавлено кое-что из моего собственного понимания. На основе этой статьи будет также основываться анализ распространяемых последующих статей autograd.
Другие статьи о распространении PyTorch:
[Анализ исходного кода] Распространение PyTorch (1) ------ история и обзор
[Анализ исходного кода] Как PyTorch использует GPU
[Анализ исходного кода] Распределенный PyTorch (2) ----- DataParallel (включен)
[Анализ исходного кода] Распределенный PyTorch (3) ----- DataParallel (ниже)
[Анализ исходного кода] Распределенный PyTorch (7) ----- Группа процессов DistributedDataParallel
[Анализ исходного кода] Распределенный PyTorch (8) -------- Бумага DistributedDataParallel
[Анализ исходного кода] Распределенный PyTorch (9) ----- Инициализация DistributedDataParallel
0x01 Распределенная структура RPC
Эта статья в основном посвященаpy torch.org/docs/master…В качестве эталона, но исходный документ требует, чтобы пользователи были знакомы сМеханизм АвтоградиРаспределенная среда RPC, поскольку мы уже разобрали механизм Автограда, давайте сначала рассмотрим егоРаспределенная среда RPC.
1.1 Платформа RPC
RPC (удаленный вызов процедур) — это дизайн или техническая идея, а не протокол или спецификация.
Самое простое понимание RPC состоит в том, что узел запрашивает услуги, предоставляемые другим узлом, но для пользовательского кода ему необходимо поддерживать ощущение «локального вызова», то есть для удаленных вызовов функций удаленный сервис должен быть таким же, как вызов локальные функции, или код выглядит так, как будто он выполняется локально.
RPC должен решить несколько проблем:
- Как общаться: Как установить соединение между вызывающим абонентом и поставщиком услуг.
- Как обращаться: то есть, как звонящий находит поставщика услуг, и как он узнает, какие услуги в нем есть.
- Как отправлять параметры: когда вызывающая сторона инициирует удаленный вызов, параметры метода должны быть переданы на сервер через такие протоколы, как TCP Как сериализовать параметры?
- Как принимать параметры: как десериализовать и вызвать после того, как сервис-провайдер получит параметры.
- Как вернуть: как отправить возвращаемое значение вызывающей стороне после того, как поставщик услуг вызовет локально предоставляемую службу.
1.2 Четыре столпа PyTorch RPC
Следующее переведено из официальной документацииpy torch.org/docs/master…
Распределенная среда RPC предоставляет механизм обучения модели на нескольких машинах с помощью набора примитивов, обеспечивающих удаленную связь, и высокоуровневый API для автоматического различения моделей, разделенных на нескольких машинах. Распределенная среда RPC упрощает удаленный запуск функций, поддерживает ссылки на удаленные объекты без копирования реальных данных и предоставляет API-интерфейсы автоградации и оптимизатора для прозрачного запуска в обратном направлении и обновления параметров за пределами границ RPC. Эти функции можно разделить на четыре группы API.
-
Удаленный вызов процедур (RPC)Поддерживает запуск функции на указанном рабочем потоке с заданными параметрами и получение возвращаемого значения или создание ссылки на возвращаемое значение. Существует три основных API RPC:
rpc_sync()
(Синхронизировать),rpc_async()
(асинхронный) иremote()
(асинхронно и возвращает ссылку на удаленное возвращаемое значение). Если пользовательский код не может продолжать работу без возвращаемого значения, используйте синхронный API. В противном случае используйте асинхронный API для получения Future и ждите Future, когда вызывающему объекту потребуется возвращаемое значение.remote()
API-интерфейсы полезны, когда что-то нужно создать удаленно, но не нужно передавать вызывающей стороне. Представьте ситуацию, когда процесс-драйвер задает параметры сервера и тренера. Драйвер может создать таблицу внедрения на сервере параметров, а затем поделиться ссылкой на таблицу внедрения с тренером, но сам никогда не будет использовать таблицу внедрения локально. при этих обстоятельствах,rpc_sync()
иrpc_async()
Больше не применимы, так как они всегда подразумевают, что возвращаемое значение отправляется вызывающей стороне немедленно или в будущем. -
Удаленная ссылка (RRef)Используется как распределенный общий указатель на локальный или удаленный объект. Им можно поделиться с другими работниками, и подсчет ссылок будет осуществляться прозрачно. У каждого RRef есть только один владелец, и объект существует только внутри этого владельца. Рабочий процесс, не являющийся владельцем, владеющий RRef, может получить копию объекта от владельца, явно запросив его. Когда работнику необходимо получить доступ к объекту данных, но он не является создателем самого объекта
remote()
Это полезно, когда вызывающая функция также не является владельцем объекта. Распределенный оптимизатор является примером такого варианта использования. - Distributed AutogradСшивает вместе все локальные механизмы автоградации, участвующие в рабочих процессах прямого прохода, и автоматически связывается с ними для вычисления градиентов во время обратного прохода. Это особенно полезно при выполнении прямых проходов, которые должны охватывать несколько компьютеров, таких как параллельное обучение распределенной модели, обучение сервера параметров и т. д. Благодаря этой функции пользовательскому коду больше не нужно беспокоиться о том, как отправлять градиенты через границы RPC и в каком порядке следует запускать локальный механизм автоградации, что может стать очень сложным, если в прямом проходе есть вложенные и взаимозависимые вызовы RPC.
-
оптимизатор распределенияДля строительства требуется
Optimizer()
(Например,SGD()
,Adagrad()
и т.д.) и список аргументов RRefs. т. е. создать по одному поверх каждого владельца ссылки.Optimizer()
экземпляр, затем запуститеstep()
Обновите параметры соответствующим образом. Когда пользователи выполняют распределенное прямое и обратное распространение, параметры и градиенты будут распределены между несколькими рабочими процессами, поэтому каждый связанный рабочий процесс необходимо оптимизировать. Distributed Optimizer объединяет все эти локальные оптимизаторы в один и предоставляет краткие конструкторы иstep()
API.
1.3 RRef
Ниже мы используемpy torch.org/docs/master…Станьте эталоном для изучения основных концепций и некоторых деталей дизайна протокола удаленного цитирования.
RRef — это аббревиатура от Remote REFerence. Это ссылка на объект, расположенный на локальном или удаленном рабочем сервере, и ссылки подсчитываются прозрачно внутри. Концептуально его можно рассматривать как распределенный общий указатель. приложение может позвонитьremote()
Создайте RRef. Каждый RRefremote()
принадлежит вызывающей стороне (т. е. владельцу) объекта и может использоваться несколькими пользователями. Владелец хранит фактические данные и отслеживает глобальный счетчик ссылок. К каждому RRef может обращаться глобальныйRRefId
уникальный идентификатор, глобальныйRRefId
созданremote()
назначение вызывающего абонента.
Среди рабочих-собственников есть только одинOwnerRRef
Экземпляры содержат реальные данные, а среди пользовательских воркеров могут содержать сколько угодноUserRRefs
,UserRRef
Данные не сохраняются. При использовании RRP владелец будет использовать глобально уникальный RRefId для получения уникального экземпляра OwnerRRef. существуетrpc_sync()
,rpc_async()
илиremote()
В вызове владелец создаетUserRRef
и используйте его как параметр или возвращаемое значение. Владелец будет уведомлен, а количество ссылок обновлено соответствующим образом. Если глобальный неUserRRef
экземпляр, и нет права на владельцаOwnerRRef
цитаты, тоOwnerRRef
и его данные будут удалены.
1.3.1 Предположения
Дизайн протокола RRef основан на следующих предположениях.
- Временные сбои сети (Transient Network Failures): RRef предназначен для обработки временных сетевых сбоев путем повторной отправки сообщений. RRef не может обрабатывать сбои узлов или постоянные сетевые разделы, и при возникновении этих событий приложение должно завершить работу всех рабочих процессов, вернуться к предыдущей контрольной точке и возобновить обучение.
- Неидемпотентная определяемая пользователем функция (Non-idempotent UDFs): мы предполагаем, что
rpc_sync()
,rpc_async()
илиremote()
Пользовательская функция (UDF) не является идемпотентной, поэтому повторная попытка невозможна. Однако внутренние управляющие сообщения RRef являются идемпотентными и могут повторяться при сбое сообщения. - Доставка сообщений вне очереди (Out of Order Message Delivery): Мы не делаем предположений о порядке доставки сообщений между парой узлов, потому что и отправитель, и получатель используют несколько потоков, поэтому нет гарантии, какое сообщение будет обработано первым.
Далее мы лишь кратко объясним, как его использовать.py torch.org/docs/master…
1.3.2 Синхронный вызов
Далее нужно вызвать API синхронно, метод находится в workerto
выполняет блокирующий вызов RPC сверху для запускаfunc
. Сообщения RPC отправляются и принимаются параллельно с выполнением кода Python. Этот метод является потокобезопасным.
torch.distributed.rpc.rpc_sync( to , func , args = None , kwargs = None , timeout = - 1.0 )
Конкретные параметры следующие:
- to– Имя/ранг/WorkerInfo целевого работника.
- func (callable) — вызываемая функция, такая как вызываемые функции Python, встроенные операторы (например, add() ) и аннотированные функции TorchScript.
-
args–
func
Кортеж аргументов для вызова. -
kwargs–
func
Словарь аргументов ключевых слов для вызова. - timeout– Тайм-аут (в секундах), используемый для этого RPC.
Возвращаемое значение должно использоватьargs
and kwargs
бегатьfunc
результат.
Пример:
удостоверитьсяMASTER_ADDR
and MASTER_PORT
Уже настроен поверх двух рабочих.
export MASTER_ADDR=localhost
export MASTER_PORT=5678
Затем запустите следующий код в двух разных процессах.
>>> # On worker 0:
>>> import torch
>>> import torch.distributed.rpc as rpc
>>> rpc.init_rpc("worker0", rank=0, world_size=2)
>>> ret = rpc.rpc_sync("worker1", torch.add, args=(torch.ones(2), 3))
>>> rpc.shutdown()
>>> # On worker 1:
>>> import torch.distributed.rpc as rpc
>>> rpc.init_rpc("worker1", rank=1, world_size=2)
>>> rpc.shutdown()
1.3.2 Асинхронный вызов
Ниже приведен API асинхронного вызова, метод находится в рабочемto
выполняет неблокирующий вызов RPC сверху для запускаfunc
. Сообщения RPC отправляются и принимаются параллельно с выполнением кода Python. Этот метод является потокобезопасным. Метод немедленно возвращает ожидаемоеFuture
.
torch.distributed.rpc.rpc_async(to, func, args=None, kwargs=None, timeout=- 1.0)
Конкретные параметры следующие:
-
to– имя/ранг/ целевого работника
WorkerInfo
. - func (callable) — вызываемая функция, такая как вызываемые функции Python, встроенные операторы (например, add() ) и аннотированные функции TorchScript.
-
args–
func
Кортеж аргументов для вызова. -
kwargs- Да
func
Словарь аргументов ключевых слов для вызова. - timeout– Тайм-аут (в секундах), используемый для этого RPC.
возвращает ожидаемыйFuture
объект. После этого его можно извлечь из объекта.func
Возвращаемое значение.
Пример:
удостоверитьсяMASTER_ADDR
and MASTER_PORT
Уже настроен поверх двух рабочих.
>>> export MASTER_ADDR=localhost
>>> export MASTER_PORT=5678
Затем запустите следующий код в двух разных процессах.
>>> # On worker 0:
>>> import torch
>>> import torch.distributed.rpc as rpc
>>> rpc.init_rpc("worker0", rank=0, world_size=2)
>>> fut1 = rpc.rpc_async("worker1", torch.add, args=(torch.ones(2), 3))
>>> fut2 = rpc.rpc_async("worker1", min, args=(1, 2))
>>> result = fut1.wait() + fut2.wait()
>>> rpc.shutdown()
>>> # On worker 1:
>>> import torch.distributed.rpc as rpc
>>> rpc.init_rpc("worker1", rank=1, world_size=2)
>>> rpc.shutdown()
пример 0x02
Мы следующиеpy torch.org/docs/master…Учиться на основе.
Предположим, у вас есть два узла и очень простая модель, разделенная на два узла. Это можно использоватьtorch.distributed.rpc
Реализовано следующим образом.
Основной мотивацией распределенного автограда является запуск обратного распространения в этой распределенной модели.loss
, мы вычислили и записали градиенты всех тензоров, которым требуются градиенты.
import torch
import torch.distributed.rpc as rpc
def my_add(t1, t2):
return torch.add(t1, t2)
# On worker 0:
t1 = torch.rand((3, 3), requires_grad=True)
t2 = torch.rand((3, 3), requires_grad=True)
# Perform some computation remotely.
t3 = rpc.rpc_sync("worker1", my_add, args=(t1, t2))
# Perform some computation locally based on remote result.
t4 = torch.rand((3, 3), requires_grad=True)
t5 = torch.mul(t3, t4)
# Compute some loss.
loss = t5.sum()
0x03 Записи Autograd во время прямого распространения
PyTorch строит график автоградации во время прямого прохода, который используется для выполнения обратного прохода. Подробнее см.Как автоград кодирует историю.
Для распределенного автограда нам необходимо отслеживать все RPC во время прямого распространения, чтобы обеспечить правильное обратное распространение. Для этого при выполнении RPC ставимsend
иrecv
функции привязаны к графу автограда.
- Должен
send
Функция присоединена к исходному узлу RPC, а ее выходное ребро указывает на функцию автоградации входного тензора RPC. При обратном распространенииsend
Вход в функцию поступает от цели и является соответствующимrecv
вывод функции. - Должен
recv
Функция присоединяется к принимающему целевому узлу RPC, и ее входные данные получаются от определенных операторов, которые выполняются на принимающем целевом RPC с использованием входных тензоров. При обратном распространенииrecv
Выходной градиент функции будет отправлен через исходный узел и использован какsend
ввод метода. - Каждый
send-recv
присваивается глобально уникальныйautograd_message_id
чтобы однозначно идентифицироватьsend-recv
правильно. Это полезно для поиска соответствующих функций на удаленных узлах во время обратного распространения. - заRRef, всякий раз, когда мы звоним
torch.distributed.rpc.RRef.to_here()
, мы все добавляем соответствующий тензор к задействованным тензорамsend-recv
правильно.
Например, вот как выглядит график автоградации в нашем примере выше (t5.sum() опущено для простоты).
Мы видим, что метод отправки является отправителем в прямом проходе, но получателем в обратном проходе.
0x04 Распределенный контекст Autograd
Каждому прямому и обратному проходу с использованием распределенного автограда назначается уникальныйtorch.distributed.autograd.context
, и этот контекст имеет глобально уникальныйautograd_context_id
. Контекст создается на каждом узле, если это необходимо.
Контекст работает следующим образом:
- Несколько узлов с распределенным обратным распространением могут накапливать градиенты на одном и том же тензоре и сохранять их в памяти тензора.
.grad
выше. Прежде чем мы запустим оптимизатор, тензор.grad
Градиенты от различных распределенных обратных распространений могут накапливаться. Это похоже на то, чтобы поставитьtorch.autograd.backward()
Сделайте несколько звонков локально. Чтобы обеспечить способ разделения каждого градиента обратного распространения, в каждом проходе обратного распространения градиент будет накапливаться вtorch.distributed.autograd.context
среди. - Во время прямого прохода мы сохраняем в контексте значение каждого прохода автограда
send
иrecv
функция. Это гарантирует, что мы сохраним ссылку на соответствующий узел в графе autograd, чтобы поддерживать его в рабочем состоянии. Среди прочего, это также упрощает поиск соответствующихsend
иrecv
функция. - В общем, мы также используем этот контекст для хранения некоторых метаданных для каждого распределенного распространения autograd.
С точки зрения пользователя контекст автограда задается следующим образом:
import torch.distributed.autograd as dist_autograd
with dist_autograd.context() as context_id:
loss = model.forward()
dist_autograd.backward(context_id, loss)
Важно отметить, что прямое распространение модели должно вызываться в диспетчере распределенного контекста autograd, потому что для обеспечения того, чтобы:send
иrecv
Методы сохраняются и распространяются обратно на все участвующие узлы.
0x05 Распределенное обратное распространение
В этом разделе мы описываем проблемы точного вычисления зависимостей во время распределенного обратного распространения, а также описываем несколько алгоритмов выполнения распределенного обратного распространения (в алгоритме есть компромиссы).
5.1 Вычисление зависимостей
Во-первых, рассмотрите возможность запуска следующего кода на одной машине.
import torch
a = torch.rand((3, 3), requires_grad=True)
b = torch.rand((3, 3), requires_grad=True)
c = torch.rand((3, 3), requires_grad=True)
d = a + b
e = b * c
d.sum.().backward()
На следующем рисунке показан график автоградации, соответствующий приведенному выше коду.
В рамках обратного распространения первый шаг, выполняемый механизмом autograd, — подсчет количества зависимостей для каждого узла в графе autograd. Это помогает движку autograd узнать, когда узлы в графе готовы к выполнению. цифры в скобкахadd(1)
иmul(0)
Представляет количество зависимостей. Как видите, это означает, что при обратном распространенииadd
Узел требует 1 вход,mul
Узлы не требуют никаких входных данных (другими словами, их не нужно выполнять). Локальный механизм автоградации запускается с корневого узла (в данном случаеd
) пройти по графу, чтобы вычислить эти зависимости.
На практике некоторые узлы в графе Autograd могут не выполняться при обратном проходе. Этот факт представляет собой проблему для распределенного автограда. Рассмотрим этот код, который использует RPC.
import torch
import torch.distributed.rpc as rpc
a = torch.rand((3, 3), requires_grad=True)
b = torch.rand((3, 3), requires_grad=True)
c = torch.rand((3, 3), requires_grad=True)
d = rpc.rpc_sync("worker1", torch.add, args=(a, b))
e = rpc.rpc_sync("worker1", torch.mul, args=(b, c))
loss = d.sum()
Связанный график autograd для приведенного выше кода будет выглядеть так:
Вычисление зависимостей этого распределенного графа autograd является более сложным и требует некоторых накладных расходов (с точки зрения вычислений или сетевого взаимодействия).
Для приложений, чувствительных к производительности, мы можем сделать это, предполагая, что каждыйsend
иrecv
Все функции являются эффективными компонентами обратного распространения, чтобы избежать больших накладных расходов (большинство приложений не выполняют неиспользуемые RPC). Это упрощает распределенный алгоритм автоградации и делает его более эффективным за счет приложения, которое должно знать об этих ограничениях. Этот алгоритм называетсяАлгоритм режима FAST, подробно описано ниже.
В общем случае в рамках обратного распространения может не понадобиться для каждогоsend
иrecv
функции действительны. Для решения этой проблемы мы предлагаемАлгоритм режима SMART, этот алгоритм будет описан в следующем разделе. Обратите внимание, что в настоящее время реализован только алгоритм режима FAST.
5.2 Алгоритм режима FAST
Ключевое предположение этого алгоритма состоит в том, что когда мы запускаем обратное распространение, каждыйsend
Функция имеет зависимость 1. Другими словами, мы предполагаем, что будем получать градиенты через RPC от другого узла.
Алгоритм следующий:
- Начнем с воркеров с корнями обратного распространения (все корни должны быть локальными).
- Найти весь текущий распределенный контекст Autograd.
send
функция . - из предоставленного корня и все, что мы получили
send
Функция запускается, и мы вычисляем зависимости локально. - После вычисления зависимостей используйте предоставленный корень для запуска локального механизма автоградации.
- Когда движок автограда выполняет
recv
функция,recv
Функция отправляет входной градиент соответствующему воркеру через RPC. каждыйrecv
Функция знает идентификатор целевого рабочего, поскольку он записывается как часть прямого прохода. пройти черезautograd_context_id
иautograd_message_id
Долженrecv
Функция отправляется на удаленный хост. - Когда удаленный хост получает этот запрос, мы используем
autograd_context_id
иautograd_message_id
найти подходящееsend
функция. - Если это первый раз, когда работник получил
autograd_context_id
запросы, он будет вычислять зависимости локально, как описано в пунктах 1-3 выше. - то получит в точке 6
send
Методы вставляются в очередь для выполнения на локальном механизме автоградации этого рабочего. - Наконец, мы не в Тензоре.
.grad
вместо того, чтобы накапливать градиенты поверх каждого распределенного контекста Autograd отдельно. Градиенты хранятся вDict[Tensor, Tensor]
среди ,Dict[Tensor, Tensor]
По сути, это карта от Tensor к связанным с ними градиентам, и эту карту можно получить с помощью API get_gradients().
Например, полный код распределенного автограда выглядит следующим образом:
import torch
import torch.distributed.autograd as dist_autograd
import torch.distributed.rpc as rpc
def my_add(t1, t2):
return torch.add(t1, t2)
# On worker 0:
# Setup the autograd context. Computations that take
# part in the distributed backward pass must be within
# the distributed autograd context manager.
with dist_autograd.context() as context_id:
t1 = torch.rand((3, 3), requires_grad=True)
t2 = torch.rand((3, 3), requires_grad=True)
# Perform some computation remotely.
t3 = rpc.rpc_sync("worker1", my_add, args=(t1, t2))
# Perform some computation locally based on remote result.
t4 = torch.rand((3, 3), requires_grad=True)
t5 = torch.mul(t3, t4)
# Compute some loss.
loss = t5.sum()
# Run the backward pass.
dist_autograd.backward(context_id, [loss])
# Retrieve the gradients from the context.
dist_autograd.get_gradients(context_id)
Распределенный граф autograd с зависимостями выглядит следующим образом (t5.sum() исключен для простоты):
Алгоритм режима FAST, примененный к приведенному выше примеру, выглядит следующим образом:
- существует
Worker 0
вверх, мы начинаем с корняloss
иsend1
Начните вычислять зависимости. результат,send1
правильноWorker 0
Количество зависимостей равно 1,mul
правильноWorker 0
Количество зависимостей равно 1. - Теперь мы
Worker 0
Запустите локальный движок автограда на . Сначала мы выполняемmul
функция с выводом в видеt4
Градиент , накопленный в контексте автограда. Затем мы выполняемrecv2
, который отправляет эти градиенты вWorker 1
. - Так как это
Worker 1
Зная об этом обратном распространении в первый раз, он выполнит вычисление зависимости и соответствующим образом пометит его.send2
,add
иrecv1
зависимость. - Далее, в
Worker 1
местныйautograd
адмирал двигателяsend2
Вставить в очередь, движок будет выполняться последовательноadd
иrecv1
. - при исполнении
recv1
, он отправляет градиент вWorker 0
. - так как
Worker 0
Эта зависимость с обратным распространением уже рассчитана, поэтому она может применяться только локально.send1
Вставить в очередь и выполнить. - Наконец,
t1
,t2
иt4
Градиенты накапливаются в распределенном контексте Autograd.
5.3 Алгоритм режима SMART
Полная информация об алгоритме все еще находится в разработке, но для общего представления вы можете обратиться кRFCсерединаУмный режим распределенного алгоритма Autogradчасть .
0x06 Распределенный оптимизатор
ДолженDistributedOptimizer
Операция выглядит следующим образом:
- Получить удаленные параметры для оптимизации (
RRef
) список. Эти параметры также могут быть включены локальноRRef
локальные параметры. - положить
Optimizer
class действует как локальный оптимизатор, которыйRRef
беги от хозяина. - Распределенный оптимизатор создает локальный
Optimizer
экземпляр и для каждогоOptimizer
сохранитьRRef
. - при звонке
torch.distributed.optim.DistributedOptimizer.step()
, распределенный оптимизатор выполняет все локальные оптимизаторы удаленно на соответствующем удаленном рабочем месте с помощью RPC. должно бытьtorch.distributed.optim.DistributedOptimizer.step()
Предоставляет распределенный автоградcontext_id
. использование локального оптимизатораcontext_id
Храните градиенты в соответствующем контексте. - Если несколько параллельных распределенных оптимизаторов обновляют один и тот же пакет параметров рабочего процесса, эти обновления будут выполняться через блокировки.
0x07 Простой сквозной пример
С учетом всего сказанного, вот простой сквозной пример с использованием распределенного автограда и распределенного оптимизатора. Если вы поместите свой код в файл с именем «dist_autograd_simple.py», вы можете запустить его с помощью:MASTER_ADDR="localhost" MASTER_PORT=29500 python dist_autograd_simple.py
import torch
import torch.multiprocessing as mp
import torch.distributed.autograd as dist_autograd
from torch.distributed import rpc
from torch import optim
from torch.distributed.optim import DistributedOptimizer
def random_tensor():
return torch.rand((3, 3), requires_grad=True)
def _run_process(rank, dst_rank, world_size):
name = "worker{}".format(rank)
dst_name = "worker{}".format(dst_rank)
# Initialize RPC.
rpc.init_rpc(
name=name,
rank=rank,
world_size=world_size
)
# Use a distributed autograd context.
with dist_autograd.context() as context_id:
# Forward pass (create references on remote nodes).
rref1 = rpc.remote(dst_name, random_tensor)
rref2 = rpc.remote(dst_name, random_tensor)
loss = rref1.to_here() + rref2.to_here()
# Backward pass (run distributed autograd).
dist_autograd.backward(context_id, [loss.sum()])
# Build DistributedOptimizer.
dist_optim = DistributedOptimizer(
optim.SGD,
[rref1, rref2],
lr=0.05,
)
# Run the distributed optimizer step.
dist_optim.step(context_id)
def run_process(rank, world_size):
dst_rank = (rank + 1) % world_size
_run_process(rank, dst_rank, world_size)
rpc.shutdown()
if __name__ == '__main__':
# Run world_size workers
world_size = 2
mp.spawn(run_process, args=(world_size,), nprocs=world_size)
0xEE Личная информация
★★★★★★Думая о жизни и технологиях★★★★★★
Публичный аккаунт WeChat:мысли Росси