是时候放弃tensorflow集群投入horovod的怀抱

栏目: 数据库 · 发布时间: 5年前

内容简介:当数据较多或者模型较大时,为提高机器学习模型训练效率,一般采用多GPU的分布式训练。按照并行方式,分布式训练一般分为数据并行和模型并行两种, 模型并行:分布式系统中的不同GPU负责网络模型的不同部分。例如,神经网络模型的不同网络层被分配到不同的GPU,或者同一层内部的不同参数被分配到不同GPU;数据并行:不同的GPU有同一个模型的多个副本,每个GPU分配到不同的数据,然后将所有GPU的计算结果按照某种方式合并。

当数据较多或者模型较大时,为提高机器学习模型训练效率,一般采用多GPU的分布式训练。

按照并行方式,分布式训练一般分为数据并行和模型并行两种, 模型并行:分布式系统中的不同GPU负责网络模型的不同部分。例如,神经网络模型的不同网络层被分配到不同的GPU,或者同一层内部的不同参数被分配到不同GPU;

数据并行:不同的GPU有同一个模型的多个副本,每个GPU分配到不同的数据,然后将所有GPU的计算结果按照某种方式合并。

注意,上述中的不用GPU可以是同一台机上的多个GPU,也可以是不用机上的GPU。

是时候放弃tensorflow集群投入horovod的怀抱

注:图中的Machine其实就是GPU,当然也可以指CPU,但深度学习很少采用CPU训练

当然也有数据并行和模型并行的混合模式。

是时候放弃tensorflow集群投入horovod的怀抱

注:图中的Machine其实就是GPU,当然也可以包含CPU,但深度学习很少采用CPU训练

因为模型并行各个部分存在一定的依赖,规模伸缩性差(意思是不能随意增加GPU的数量),在实际训练中用的不多。而数据并行,则各部分独立,规模伸缩性好,实际训练中更为常用,提速效果也更好。

数据并行会涉及到各个GPU之间同步模型参数,一般分为同步更新和异步更新。同步更新要等到所有GPU的梯度计算完成,再统一计算新权值,然后所有GPU同步新值后,才进行下一轮计算。异步更新,每个GPU梯度计算完后,无需等待其他GPU的梯度计算(有时可以设置需要等待的梯度个数),可立即更新整体权值,然后同步此权值,即可进行下一轮计算。同步更新有等待,异步更新基本没有等待,但异步更新涉及到梯度过时等更复杂问题。

在实际应用中,单机多卡的同步式数据并行是最常用的,在论文中最常见的训练方式是单机八卡。数据再多时,一般就需要多机多卡了。

无论是单机多卡,还是多机多卡,均是分布式训练,在horovod出现之前,使用tensorflow,一般只有官方推荐的集群训练方式。

可是tensorflow的集群训练,用起来并不轻松。

tensorflow集群的缺点

  1. 概念多,学习曲线陡峭

tensorflow的集群采用的是parameter server架构,因此引入了比较多复杂概念,罗列如下

server
client
master
cluster
parameter server
worker
job
task
replica_device_setter
master service
worker service
clone
复制代码

涉及到的函数

tf.train.Server
tf.train.Supervisor
tf.train.SessionManager
tf.train.ClusterSpec
tf.train.replica_device_setter
tf.train.MonitoredTrainingSession
tf.train.MonitoredSession
tf.train.SingularMonitoredSession
tf.train.Scaffold
tf.train.SessionCreator
tf.train.ChiefSessionCreator
tf.train.WorkerSessionCreator
复制代码

我反复研究过多次,还是没有彻底弄清楚,server,client,master,master service,worker service,clone,session之间的关系。 大致是,在client中创建server实例,session与server一一对应,server内含master service和worker service两个服务,master service负责与外界通讯,比如sess.run一般都是告诉server的master service要开始工作了,server的master service通知同一个server的worker service去干活,worker service调动GPU运算,完成后,返回结果给master service,做权值更新,如果是多机多卡的分布式,parameter server与master service之间做梯度传递和权值同步。 stackoverflow.com/questions/3…

  1. 修改的代码量大

如果想把单机单卡的模型,移植到多机多卡,涉及的代码量是以天记的,慢的话甚至需要一周。

  1. 需要多台机子跑不同的脚本

tensorflow集群是采用parameter server架构的,要想跑多机多卡的集群,每个机子都要启动一个client,即跑一个脚本,来启动训练,100个机子,人就要崩溃了。

  1. ps和worker的比例不好选取

tensorflow集群要将服务器分为ps和worker两种job类型,ps设置多少性能最近并没有确定的计算公式。

  1. 性能损失较大

tensorflow的集群性能并不好,当超过一定规模时,性能甚至会掉到理想性能的一半以下。

是时候放弃tensorflow集群投入horovod的怀抱

Horovod

由于tensorflow集群太不友好,业内也一直在尝试新的集群方案。 2017年Facebook发布了《Accurate, large minibatch SGD: Training ImageNet in 1 hour 》验证了大数据并行的高效性,同年百度发表了《Bringing HPC techniques to deep learning 》,验证了全新的梯度同步和权值更新算法的可行性。受这两篇论文的启发,Uber开发了Horovod集群方案。

约定如下: 网络带宽记为:B(单位Mb/s), 模型总参数数据量记为:D(单位Mb), 总服务器数量记为:n, 参数服务器数量记为:n_p(其中有n= n_p+ n_w), worker服务器数量记为:n_w(其中有n= n_p+ n_w) 单服务器计算一次耗时记为:T_0

梯度同步和权值更新算法

1) parameter server架构

tensorflow的集群架构是parameter server架构,数据的传导模型如下图。

是时候放弃tensorflow集群投入horovod的怀抱

则可以计算出,parameter server架构的集群方案,总耗时:

是时候放弃tensorflow集群投入horovod的怀抱

可以看出T与总节点数n基本成线性关系,但不同的参数服务器和woker服务器分配方案,总性能也将不同。 假设,e表示worker服务器占比,即e=n_w/n,则可以计算出最优的e值为:

是时候放弃tensorflow集群投入horovod的怀抱

可以看出,最优worker服务器占比与模型大小、网络带宽、单机运行市场都有关系,并不是一个一眼能最优值得超参数。

2)horovod的ring-allreduce算法

百度2017年发表的《Bringing HPC techniques to deep learning 》中,采用了全新的梯度同步和权值同步算法,叫做ring-allreduce。此种算法各个节点之间只与相邻的两个节点通信,并不需要参数服务器。因此,所有节点都参与计算也参与存储。 一次权重更新,主要包含两个过程, 1)累计梯度 将所有梯度分为n个片段,每次只与相邻节点传递1个片段的梯度,n-1次后,每一片段的梯度都完成了所有节点这一片段梯度的累计,但不用片段的累计值分布在不同节点上。如下图的第2、第3步; 2)将累计后的梯度分发到所有节点 将第一步累计的梯度再次通过n-1次的相互交换后,所有节点的梯度完成同步。如下图的第4、第5步。再平均后,更新权重,就完成了所有节点权重的更新。

是时候放弃tensorflow集群投入horovod的怀抱

可以计算出ring-allreduce算法的总耗时为:

是时候放弃tensorflow集群投入horovod的怀抱

可以看出,总耗时基本与总节点数n成线性关系(n较大时,1/n基本为0)

Horovod的梯度同步和权值同步就采用了ring-allreduce算法。

概念

horovod的数据传递是基于MPI,因此其涉及的概念也是MPI中的概念。以4个服务器,每个服务器4个GPU为例,

  • size 进程数量,也即所有GPU数量,为16
  • rank 进程的唯一ID,0-15
  • local rank 每一个server中的进程的本地唯一ID,0-3
  • allreduce 累加所有数据,并同步到所有节点的操作,如下图
是时候放弃tensorflow集群投入horovod的怀抱
  • allgather 收集所有数据,并同步到所有节点的操作,完成后每个节点都包含所有节点的数据,并且这些数据单独存在。如下图。
是时候放弃tensorflow集群投入horovod的怀抱
  • broadcast 将数据(需要由根节点确认)从一个节点传播到其他所有节点的操作
是时候放弃tensorflow集群投入horovod的怀抱

大概就这么多概念,简单清晰。

将单机单卡改为多机多卡

将一个只支持单机单卡的训练脚本修改为支持多机多卡的训练脚本,以tensorflow为例,只需要做如下改动:

import tensorflow as tf
import horovod.tensorflow as hvd


# Initialize Horovod
hvd.init()

# Pin GPU to be used to process local rank (one GPU per process)
config = tf.ConfigProto()
config.gpu_options.visible_device_list = str(hvd.local_rank())

# Build model...
loss = ...
opt = tf.train.AdagradOptimizer(0.01 * hvd.size())

# Add Horovod Distributed Optimizer
opt = hvd.DistributedOptimizer(opt)

# Add hook to broadcast variables from rank 0 to all other processes during
# initialization.
hooks = [hvd.BroadcastGlobalVariablesHook(0)]

# Make training operation
train_op = opt.minimize(loss)

# Save checkpoints only on worker 0 to prevent other workers from corrupting them.
checkpoint_dir = '/tmp/train_logs' if hvd.rank() == 0 else None

# The MonitoredTrainingSession takes care of session initialization,
# restoring from a checkpoint, saving to a checkpoint, and closing when done
# or an error occurs.
with tf.train.MonitoredTrainingSession(checkpoint_dir=checkpoint_dir,
                                       config=config,
                                       hooks=hooks) as mon_sess:
  while not mon_sess.should_stop():
    # Perform synchronous training.
    mon_sess.run(train_op)
复制代码

可以看出,改动不大,只需添加10行左右的代码,主要分为6步:

1)初始化horovod

hvd.init()
复制代码

2)一个GPU与一个进程绑定

config = tf.ConfigProto()
config.gpu_options.visible_device_list = str(hvd.local_rank())
复制代码

3)根据总GPU数量放大学习率

opt = tf.train.AdagradOptimizer(0.01 * hvd.size())
复制代码

因为BatchSize会根据GPU数量放大,所以学习率也应该放大

4)使用hvd.DistributedOptimizer封装原有的optimizer

opt = hvd.DistributedOptimizer(opt)
复制代码

分布式训练涉及到梯度同步,每一个GPU的梯度计算仍然由原有的optimizer 计算,只是梯度同步由hvd.DistributedOptimizer负责。

5)广播初始变量值到所有进程

hooks = [hvd.BroadcastGlobalVariablesHook(0)]
复制代码

主要为了确保所有进程变量初始值相同

6)只在worker 0上保存checkpoint

checkpoint_dir = '/tmp/train_logs' if hvd.rank() == 0 else None
复制代码

防止checkpoint保存错乱

horovod只是需要改动必要改动的,不涉及parameter server架构的device设置等,繁琐的操作。

起训练

在单机4卡的机上起训练,只需执行以下命令:

horovodrun -np 4 -H localhost:4 python train.py
复制代码

在4机,每机4卡的机子上起训练,只需在一个机子上执行以下命令即可:

horovodrun -np 16 -H server1:4,server2:4,server3:4,server4:4 python train.py
复制代码

注意无论是单机多卡,还是多机多卡,都只需在一个机子上执行一次命令即可,其他机horovod会用MPI启动进程和传递数据。

性能对比

是时候放弃tensorflow集群投入horovod的怀抱

horovod随着规模增大,性能损失远小于tensorflow,基本是线性增加的。

结论

通过tensorflow集群的人,会深刻体会到horovod有多好用,感谢百度、Facebook和Uber让深度学习更美好。

不过,也要注意到,horovod的分布式貌似只支持同步更新式的数据并行,模型并行和异步更新式的数据并行,我没有尝试过,根据ring-allreduce算法可知,应该是不支持的。

是时候放弃tensorflow集群投入horovod的怀抱

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Usability for the Web

Usability for the Web

Tom Brinck、Darren Gergle、Scott D. Wood / Morgan Kaufmann / 2001-10-15 / USD 65.95

Every stage in the design of a new web site is an opportunity to meet or miss deadlines and budgetary goals. Every stage is an opportunity to boost or undercut the site's usability. Thi......一起来看看 《Usability for the Web》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换