Horovod源码剖析(一)

Horovod源码剖析:

核心模块 – operations

  1. horovod/common/operations.h

首先了解一下mpi常见的通信操作

  1. MPI-Scatter:scatter与broadcast类似都是一对多的通信,将一段array 的不同部分发送给所有的进程Horovod源码剖析(一)

  2. MPI-Boardcast:与scatter进行区分,broadcast是将0号进程将相同的信息发送给所有的进程;

  3. MPI-Gather:MPI_Gather和scatter刚好相反,他的作用是从所有的进程中将每个进程的数据集中到根进程中,
    同样根据进程的编号对array元素排序

Horovod源码剖析(一)
4. MPI-Allgather:当数据分布在所有的进程中时,MPI_Allgather将所有的数据聚合到每个进程中。
定义的操作:
Horovod源码剖析(一)
5. MPI-Reduce:所有节点上的值进行规约(求和)
Horovod源码剖析(一)
6. MPI-Allreduce:reduce之后在进行boardcast,
Horovod源码剖析(一)

horovod 定义的通信算子

  1. Allreduce:
  2. Allgather:
  3. Broadcast:
  4. Join:

horovod 的实现

  • 分成三大模块:(1)适配层(2)统一层(3)算子实现层
  1. 适配层
  • python如何调用c++的动态链接库:适配不同的深度学习框架
  1. 统一层:不同框架都需要调用的统一算法,在horovod/common下

horovod 使用步骤:

  1. 初始化horovod,
    hvd.init
  2. 将一个GPU与一个进程worker绑定
    config.gpu_options.visible_device_list = str(hvd.local_rank())
  3. 根据GPU数量放大学习率
    opt = tf.train.AdgradOptimizer(lr*hvd.size())
  4. 使用hvd.DistributedOptimizer封装原有的optimizer
    opt = hvd.DistributedOptimizer(opt)
  • 每一个worker的梯度仍有原来的的optimzer计算,只是梯度同步有hvd.DistributedOptimizer计算

分布式训练策略

  1. 数据并行:
  • 同步模式:要求各个设备的计算能力要均衡,而且要求集群的通信也要均衡,防止一个拖油瓶拖慢整个集群的训练
  • 异步模式:会出现梯度失效的问题,同样是因为各个设备的运算与通信速度不同,导致某些worker的参数比较新,默写worker的参数比较旧
  1. 模型并行:主要是针对大模型,如google的神经翻译系统或者模型本身存在一些可以并行的单元,那么也可以利用模型并行来提升训练速度,比如goolenet的inception模块

分布式通信算法

  1. PS:allreduce操作,随着节点的增多,通信的时延也会提升。
  2. Ring-allreduce:希望减少allreduce产生的单节点带宽受限的问题。在有N块卡的集群中,每张卡都将数据分成mini-batch/N份,不同的卡计算不同的数据块索引。一张卡的最大带宽就是一个节点的数据量,不会随着节点的增多而产生时延的升高。
  • Data Transferred=2(N−1)*K/N,数据传输量不随着GPU节点的增多而提高。
  • 一次迭代的耗时为为K/V_bottleneck,与总数据量和最慢的worker相关。
    GPU节点的增多而提高。
  • 一次迭代的耗时为为K/V_bottleneck,与总数据量和最慢的worker相关。
  • 相对于PS模型,Ring-allreduce更适合数据量比较大的的情形,这样可以使用更多的