📅  最后修改于: 2020-12-10 04:47:44             🧑  作者: Mango
本章是关于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指定了在CPU或GPU设备中保存张量的位置。在上面的示例中,它位于位置0。MXNet实现了对设备的不可思议的利用,因为所有计算都是延迟而不是瞬时进行的。
虽然命令模式非常有用,但是此模式的缺点之一是它的刚性,即所有的计算都需要与预定义的数据结构一起事先知道。
另一方面,符号模式公开了一个类似于TensorFlow的计算图。通过允许MXNet使用符号或变量而不是固定/预定义的数据结构,它消除了命令性API的缺点。之后,这些符号可以解释为一组操作,如下所示:
import mxnet as mx
x = mx.sym.Variable(“X”)
y = mx.sym.Variable(“Y”)
z = (x+y)
m = z/100
Apache MXNet支持分布式培训。它使我们能够利用多台机器进行更快,更有效的培训。
以下是两种方式,我们可以在多个设备(CPU或GPU设备)上分配训练NN的工作量-
在这种并行性中,每个设备都存储模型的完整副本并与数据集的不同部分一起工作。设备还会集体更新共享模型。我们可以将所有设备定位在一台或多台计算机上。
这是另一种并行性,当模型太大而无法放入设备内存时,它会派上用场。在模型并行性中,为不同的设备分配了学习模型的不同部分的任务。这里要注意的重要一点是,当前Apache MXNet仅在单台计算机上支持模型并行性。
以下给出的概念是理解Apache MXNet中的分布式培训工作的关键-
流程相互通信以完成模型训练。 Apache MXNet具有以下三个过程-
工人节点的工作是对一批训练样本进行训练。 Worker节点将在处理每个批次之前从服务器提取权重。批处理完成后,Worker节点将向服务器发送渐变。
MXNet可以具有多个服务器,用于存储模型的参数并与工作节点通信。
调度程序的作用是设置群集,其中包括等待每个节点已出现的消息以及该节点正在侦听的端口。设置群集后,调度程序将使所有进程了解群集中的每个其他节点。这是因为进程可以相互通信。只有一个调度程序。
KV商店代表键值存储。它是用于多设备培训的关键组件。这很重要,因为通过一台或多台带有参数KVStore的服务器,可以在一台或多台机器上跨设备进行参数通信。让我们借助以下几点来了解KVStore的工作方式-
KVStore中的每个值都由一个键和一个值表示。
网络中的每个参数数组都分配有一个键,并且该参数数组的权重由value表示。
之后,工作节点在处理批处理后推送渐变。他们还会在处理新批次之前提取更新的权重。
KVStore服务器的概念仅在分布式培训期间存在,并且它的分布式模式是通过使用包含单词dist的字符串参数调用mxnet.kvstore.create函数来启用的。
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_sync模式更快,因为它可以花费更多的时间进行收敛,而无需花费任何同步成本。
此模式与dist_sync模式相同。唯一的区别是,当在每个节点上使用多个GPU时, dist_sync_device会聚合梯度并更新GPU上的权重,而dist_sync会聚合梯度并更新CPU内存上的权重。
它减少了GPU与CPU之间的昂贵通信。这就是为什么它比dist_sync更快。缺点是它会增加GPU上的内存使用率。
此模式与dist_sync_device模式相同,但处于异步模式。