由于这个问题相当广泛,我将尝试阐明一些不同的观点,并触及与
@Daniel's深度解答。
培训
数据并行化与模型并行化
正如@Daniel 所提到的,数据并行性被更频繁地使用并且更容易正确执行。模型并行的主要警告是需要等待部分神经网络和它们之间的同步。
假设您有一个简单的前馈 5 层神经网络,分布在 5 不同的 GPU 上,每一层用于一个设备。在这种情况下,在每次前向传递期间,每个设备都必须等待来自前一层的计算。在这种简单的情况下,在设备之间复制数据和同步将花费更长的时间,而且不会带来任何好处。
另一方面,也有更适合模型并行化的模型,例如Inception networks,见下图:
在这里,您可以看到 4 与前一层的独立路径,这些路径可以并行运行,并且只有 2 同步点(Filter concatenation 和 Previous Layer)。
问题
例如通过图本身的反向传播可以并行化,例如
通过在不同的机器上托管不同的层,因为(我
认为?)autodiff 图始终是一个 DAG。
这并不容易。梯度是根据损失值计算的(通常),你需要知道更深层的梯度来计算更浅层的梯度。如上所述,如果您有独立的路径,它会更容易并且可能会有所帮助,但在单个设备上会更容易。
我相信这也叫梯度累积(?)
不,它实际上是跨多个设备的减少。您可以在PyTorch tutorial 中看到其中的一些内容。梯度累积是当您运行前向传递(在单个或多个设备上)N 次和反向传播(梯度保留在图中并在每次传递期间添加值)时,优化器只需一步即可更改神经网络网络的权重(并清除梯度)。在这种情况下,损失通常除以没有优化器的步数。这用于更可靠的梯度估计,通常在您无法使用大批量时。
跨设备减少如下所示:
这是数据并行化的全部减少,每个设备计算发送到所有其他设备并在那里反向传播的值。
每种策略何时更适合哪种类型的问题或神经网络
网络?
如上所述,如果您有足够的数据并且样本很大,数据并行几乎总是可以的(最多 8k 个样本或更多样本可以一次完成,而无需 非常 大的努力)。
现代库支持哪些模式?
tensorflow 和 pytorch 都支持,大多数现代和维护的库都以一种或另一种方式实现了这些功能
可以结合所有四种 (2x2) 策略
是的,您可以在机器之间和机器内并行化模型和数据。
同步与异步
异步
由@Daniel 简要描述,但值得一提的是更新并非完全独立。这没有什么意义,因为我们基本上会根据批次训练 N 不同的模型。
相反,有一个全局参数空间,其中每个副本都应该异步共享计算的更新(因此前向传递、后向、使用优化器计算更新并将此更新共享给全局参数)。
这种方法有一个问题:不能保证当一个工人向前计算时,另一个工人更新了参数,所以更新是相对于旧的参数集计算的,这被称为陈旧的渐变。因此,收敛可能会受到影响。
其他方法是计算每个工作人员的N 步骤和更新,然后同步它们,尽管它不经常使用。
这部分基于伟大的blogpost,如果您有兴趣一定要阅读它(还有更多关于陈旧和一些解决方案的信息)。
同步
前面主要描述了,有不同的方法,但 PyTorch 从网络收集输出并在它们上反向传播 (torch.nn.parallel.DistributedDataParallel)[https://pytorch.org/docs/stable/nn.html#torch.nn.parallel.DistributedDataParallel ]。顺便提一句。你应该只这样做(不是torch.nn.DataParallel),因为它克服了 Python 的 GIL 问题。
要点
- 几乎总是在加速时使用数据并行化,因为您“仅”必须在每个设备上复制神经网络(通过网络或在单台机器内),在前向传递期间在每个设备上运行部分批处理,连接在一台设备上将它们分成单个批次(同步)并在所述设备上进行反向传播。
- 有多种方法可以进行数据并行化,@Daniel 已经介绍过
- 当模型太大而无法在单台机器上容纳(OpenAI's GPT-3 是一种极端情况)或架构适合此任务时,会进行模型并行化,但 AFAIK 很少会出现这两种情况。
- 模型具有的并行路径(同步点)越多越长,它可能越适合模型并行化
- 重要的是要在相似的时间以相似的负载启动工作器,以免在同步方法中进行同步过程或在异步中避免过时的梯度(尽管在后一种情况下这还不够)。
服务
小型号
由于您追求的是大型模型,因此我不会深入研究小型模型的选择,只是简单提一下。
如果您想通过网络为多个用户提供服务,您需要某种方式来扩展您的架构(通常是像 GCP 或 AWS 这样的云)。您可以使用Kubernetes 和它的 POD 来做到这一点,或者预先分配一些服务器来处理请求,但这种方法效率低下(少量用户和运行服务器会产生毫无意义的成本,而大量用户可能会停止基础设施和处理请求的时间太长)。
其他方法是使用基于无服务器方法的自动缩放。将根据每个请求提供资源,因此它具有很大的扩展能力 + 流量低时您无需付费。你可以看到Azure Functions,因为他们正在改进它以用于 ML/DL 任务,或者torchlambda 用于 PyTorch(免责声明,我是作者)用于较小的模型。
大型模型
如前所述,您可以将 Kubernetes 与您的自定义代码或准备使用的工具一起使用。
在第一种情况下,您可以像训练一样传播模型,但只通过forward。通过这种方式,即使是巨大的模型也可以放在网络上(再次,GPT-3 具有 175B 参数),但需要大量工作。
在第二种情况下,@Daniel 提供了两种可能性。其他值得一提的可能是(阅读各自的文档,因为它们有很多功能):
对于 PyTorch,您可以阅读更多 here,而 tensorflow 通过 Tensorflow EXtended (TFX) 提供许多开箱即用的服务功能。
OP 评论中的问题
是否有任何形式的并行性比机器内部更好?
跨机器
最好的并行性可能是在一台巨型计算机内,以最大程度地减少设备之间的传输。
此外,有不同的后端(至少在 PyTorch 中)可供选择(mpi、gloo、nccl),并非所有后端都支持设备之间直接发送、接收、减少等数据(有些可能支持 CPU 到 CPU,有些可能支持 GPU 到 GPU)。如果设备之间没有直接链接,则必须首先将它们复制到另一个设备并再次复制到目标设备(例如,其他机器上的 GPU -> 主机上的 CPU -> 主机上的 GPU)。见pytorch info。
数据越多,网络越大,并行计算应该越有利可图。如果整个数据集可以放在单个设备上,则不需要并行化。此外,还应考虑互联网传输速度、网络可靠性等因素。这些成本可能超过收益。
一般来说,如果您有大量数据(例如带有 1.000.000 图像的 ImageNet)或大样本(例如图像 2000x2000),请选择数据并行化。如果可能,在一台机器内尽量减少机器间的传输。仅在无法绕过模型的情况下分发模型(例如,它不适合 GPU)。否则不要(在训练 MNIST 时并行化几乎没有意义,因为整个数据集很容易放入 RAM 并且读取速度最快)。
为什么要构建自定义的 ML 专用硬件,例如 TPU?
CPU 不是最适合高度并行计算(例如矩阵乘法)+ CPU 可能会被许多其他任务(例如数据加载)占用,因此使用 GPU 是有意义的。
由于创建 GPU 时考虑了图形(因此是代数转换),它可以承担一些 CPU 职责并且可以专门化(与 CPU 相比,内核更多,但更简单,例如,请参阅 V100)。
现在,TPU 是专门为张量计算(主要是深度学习)量身定制的,起源于 Google,与 GPU 相比仍然在制品。这些适用于某些类型的模型(主要是卷积神经网络),并且在这种情况下可以带来加速。此外,应该使用此设备的最大批次(请参阅here),最好能被128 整除。您可以将其与 NVidia 的 Tensor Cores 技术 (GPU) 进行比较,在该技术中,批次(或层大小)可被 16 或 8(分别为 float16 精度和 int8)整除,以获得良好的利用率(尽管更多更好,取决于内核数量、确切的显卡和许多其他东西,请参阅一些指南here)。
另一方面,TPU 支持仍然不是最好的,尽管有两个主要框架支持它(tensorflow 官方支持,而 PyTorch 支持 torch_xla 包)。
一般来说,GPU 是目前深度学习中一个不错的默认选择,TPU 用于卷积密集型架构,尽管可能会让人有些头疼。此外(再次感谢@Daniel),TPU 更节能,因此在比较单浮点运算成本时应该更便宜。