pytorch的并行方法和分布式方法如何工作?

fan*_*ars 17 c++ parallel-processing distributed-computing python-3.x pytorch

我不是分布式系统和CUDA的专家.但有一个非常有趣的功能,PyTorch支持的是nn.DataParallelnn.DistributedDataParallel.他们是如何实际实施的?他们如何分离常见的嵌入和同步数据?

这是一个基本的例子DataParallel.

import torch.nn as nn
from torch.autograd.variable import Variable
import numpy as np

class Model(nn.Module):
    def __init__(self):
        super().__init__(
            embedding=nn.Embedding(1000, 10),
            rnn=nn.Linear(10, 10),
        )

    def forward(self, x):
        x = self.embedding(x)
        x = self.rnn(x)
        return x

model = nn.DataParallel(Model())
model.forward(Variable.from_numpy(np.array([1,2,3,4,5,6], dtype=np.int64)).cuda()).cpu()
Run Code Online (Sandbox Code Playgroud)

PyTorch可以拆分输入并将它们发送到许多GPU并将结果合并.

它如何管理并行模型或分布式模型的嵌入和同步?
我在PyTorch的代码中闲逛,但很难知道基础知识是如何工作的.

mr_*_*_mo 1

这是一个很好的问题。
PyTorch DataParallel 范例实际上非常简单,并且实现是开源。请注意,目前不推荐使用他的范例,因为它在主 GPU 上存在瓶颈,并且数据传输效率不高。

该容器通过在批处理维度中分块来跨指定设备分割输入,从而并行化给定 :attr: 的应用程序module(其他对象将在每个设备上复制一次)。在前向传播中,模块在每个设备上复制,每个副本处理一部分输入。在向后传递过程中,每个副本的梯度被累加到原始模块中。

对于 DistributedDataParallel,这更加棘手。这是目前比较先进的方法,而且非常有效(请参见此处)。

该容器通过在批处理维度中分块将输入拆分到指定设备上,从而并行化给定模块的应用程序。该模块在每台机器和每台设备上进行复制,并且每个这样的副本处理一部分输入。在向后传递期间,对每个节点的梯度进行平均。

对于如何平均每个节点的梯度有多种方法。我会推荐这篇论文来真正了解事情是如何运作的。一般来说,在将数据从一个 GPU 传输到另一个 GPU 之间需要在带宽和速度方面进行权衡,我们希望这一部分真正高效。因此,一种可能的方法是将每对 GPU 用一个非常快速的协议连接成一个圆圈,并且仅将部分梯度从一个到另一个,总共,我们传输更少的数据,更有效,并且所有节点都获得所有梯度(或至少是它们的平均值)。在这种情况下仍然会有一个主 GPU,或者至少有一个进程,但现在任何 GPU 上都没有瓶颈,它们都共享相同数量的数据(最多......)。

现在,如果我们不等待所有批次完成计算并开始执行分时操作,其中每个节点在准备好时发送其部分,则可以进一步优化。不要跟我讨论细节,但事实证明,如果我们不等待一切结束,并尽快进行平均,它也可能会加速梯度平均。

请参阅文献以获取有关该领域的更多信息,因为它仍在发展中(截至今天)。

PS 1:通常这些分布式训练在为该任务设置的机器上效果更好,例如在硬件中实现这些协议的 AWS 深度学习实例。

PS 2:免责声明:我真的不知道 PyTorch 开发人员选择实现什么协议以及根据什么选择什么协议。我从事分布式训练,更喜欢遵循 ​​PyTorch 最佳实践,而不是试图超越他们。我建议您也这样做,除非您真的想研究这个领域。

参考:

[1]深度学习模型的分布式训练:分类学视角