我目前正在研究大量关于神经网络分布式训练的资料(使用反向传播进行训练)。越是深入研究这些资料,我越觉得基本上所有分布式神经网络训练算法都是一种结合分布式节点生成的梯度的方法(通常是通过平均来完成),并且考虑到执行环境的限制(例如网络拓扑,节点性能平等,…)。
所有这些基础算法的精髓都集中在利用执行环境限制的假设上,旨在减少整体延迟,从而减少完成训练所需的总时间。
所以,如果我们只是通过某种巧妙的方式使用权重平均来结合分布式训练的梯度,那么整个训练过程(或多或少)相当于对每个分布式节点内训练所得网络的平均值进行平均。
如果我对上述描述的理解是正确的,那么我想尝试手动结合分布式节点生成的权重。
所以我的问题是:如何使用任何主流技术(如tensorflow / caffe / mxnet / …)来生成两个或更多神经网络权重的平均值?
提前感谢
EDIT @隐藏人名
隐藏人名,我明白你的意思:你的意思是,一旦你应用了梯度,新的梯度就会改变,因此不可能进行并行化,因为旧的梯度与新更新的权重没有关系。所以现实世界的算法会评估梯度,平均它们,然后应用它们。
现在,如果你只是展开这个数学运算中的括号,你会注意到你可以本地应用梯度。本质上,平均增量(向量)还是平均NN状态(点)没有区别。请参考下面的图表:
假设NN权重是一个二维向量。
初始状态 = (0, 0)增量 1 = (1, 1)增量 2 = (1,-1)-----------------------平均增量 = (1, 1) * 0.5 + (1, -1) * 0.5 = (1, 0)NN状态 = (0, 0) - (1, 0) = (-1, 0)
现在,如果在节点上本地应用梯度,并且中央节点平均权重而不是增量,可以达到相同的结果:
--------- 中央节点 0 ---------初始状态 = (0, 0)----------------------------------------------- 节点 1 -------------增量 1 = (1, 1)状态 1 = (0, 0) - (1, 1) = (-1, -1)----------------------------------------------- 节点 2 -------------增量 2 = (1,-1)状态 2 = (0, 0) - (1, -1) = (-1, 1)------------------------------------------- 中央节点 0 ---------平均状态 = ((-1, -1) * 0.5 + (-1, 1) * 0.5) = (-1, 0)----------------------------------
所以结果是相同的…
回答:
标题中的问题与正文中的问题不同:) 我会回答这两个问题:
标题问题:“分布式训练是否会生成各个分布式节点内训练的NN的平均值?”
不是。在使用小批量SGD进行模型训练的背景下,分布式训练通常指的是数据并行分布式训练,它将一个小批量记录的梯度计算分布在N个工作节点上,然后产生一个用于更新中央模型权重的平均梯度,以异步或同步的方式进行。历史上,平均是在一个称为参数服务器的单独进程中进行的(在MXNet和TensorFlow中的历史默认值),但现代方法使用了一种更节约网络的、点对点的环形全减法,这种方法由Uber的Horovod扩展推广,最初为TensorFlow开发,但现在也适用于Keras、PyTorch和MXNet。请注意,模型并行分布式训练(在不同设备上托管模型的不同部分)也存在,但数据并行训练在实践中更为常见,可能因为实现起来更简单(分布平均很容易)并且完整模型通常能舒适地适应现代硬件的内存。然而,对于非常大的模型,如Google的GNMT,偶尔会看到模型并行训练。
正文问题:“如何使用任何主流技术生成两个或更多神经网络权重的平均值?”
这取决于每个框架的API,例如:
在TensorFlow中:TensorFlow – 从恢复的模型中平均模型权重
在PyTorch中:如何取两个网络的权重平均值?
在MXNet中(假设已初始化的gluon
nn.Sequential()
模型具有相似的架构的虚拟代码):
# 创建存储模型参数的Parameter字典p1 = net1.collect_params()p2 = net2.collect_params()p3 = net3.collect_params()for k1, k2, k3 in zip(p1, p2, p3): p3[k3].set_data(0.5*(p1[k1].data() + p2[k2].data()))