当前位置: 移动技术网 > IT编程>数据库>MSSQL > 多GPU分布式训练详解

多GPU分布式训练详解

2020年07月14日  | 移动技术网IT编程  | 我要评论

总的来说,分布式训练分为这几类:

  • 按照并行方式来分:模型并行 vs 数据并行

  • 按照更新方式来分:同步更新 vs 异步更新

模型并行 vs 数据并行

假设我们有n张GPU:

  • 模型并行:不同的GPU输入相同的数据,运行模型的不同部分,比如多层网络的不同层;
  • 数据并行:不同的GPU输入不同的数据,运行相同的完整的模型。

当模型非常大,一张GPU已经存不下的时候,可以使用模型并行,把模型的不同部分交给不同的机器负责,但是这样会带来很大的通信开销,而且模型并行各个部分存在一定的依赖,规模伸缩性差。因此,通常一张可以放下一个模型的时候,会采用数据并行的方式,各部分独立,伸缩性好。

同步更新 vs 异步更新

对于数据并行来说,由于每个GPU负责一部分数据,那就涉及到如果更新参数的问题,分为同步更新和异步更新两种方式。

  • 同步更新:每个batch所有GPU计算完成后,再统一计算新权值,然后所有GPU同步新值后,再进行下一轮计算。

  • 异步更新:每个GPU计算完梯度后,无需等待其他更新,立即更新整体权值并同步。

一般我们使用的都是数据并行+同步更新。因此本文主要讲解数据并行+同步更的细节。

分别以单机单卡和单机4卡,batchsize=64为例。

在单机单卡的模式下,一次性输入一个batch的数据进行forward。在得到网络的output后,由output和target进行loss的计算。但要注意,这里的loss要对bacth中的样本量(batchsize)取平均。

在单机4卡的模式下,因为batchsize=64。因此分配给每块GPU的size为16。各块GPU上模型一致并共享参数,只是数据输入不同。4块GPU分别进行forward,各GPU上loss的计算依旧要根据本卡上的样本量(size=16)取平均。在梯度计算上,我看到过两个版本,一种是将多卡loss收集到主GPU上再次按卡数进行平均。随后再进行梯度回传并更新参数,将更新后的参数分发给其他GPU。另外一种是各GPU先分别进行梯度回传,再将梯度gather到主GPU上取平均,随后更新参数并分发给其他GPU。两种方法最终的结果实际上是一致的,只是步骤不同。因此这里不再深究。

​ 从上面的分析可以看出,无论是单卡训练还是多卡训练,最终用来计算梯度的loss值,是要对样本量取平均的。因此在借助Pytorch累加梯度的特性,变相增加batchsize的过程中,需要将loss除以累加迭代的次数。

那么问题来了,单机单卡、单机多卡、借助梯度累加变相增加batchsize三者是否完全等价???

​ 除去训练速度以及不同GPU随机种子设定不同导致的细微差别,单从forward、backward、parameter update三方面来看,是没有什么差别的。

​ 但是,有个东西叫Bach Normalization。大家都知道,这神器对模型训练大有脾益,有了他不但减小了对dropout的依赖,更削弱了参数初始化的影响。可是,这玩意儿是基于batch来计算的。在单卡,多卡、变相增大batchsize的情况下,Bach Normalization单次处理的数据量可就不一样了。

​ 单卡时,每次处理的数据量等于batchsize。而在多卡情况下,由于数据分发,每次处理的数据量等于batchsize/卡数。在变相增大batchsize的情况下,每次处理的数据量与不进行这种操作是相等的,也就是说采用这种方法,其loss计算和梯度计算与增大的batchsize是一致的。但是在Bach Normalization上依旧是从前那个少年!

本文地址:https://blog.csdn.net/qq_35398033/article/details/107303236

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网