Horovod是Uber开源的深度学习工具,吸取Facebook的《一小时训练ImageNet》论文,以及百度的Ring Allreduce的优点,为用户实现分布式训练提供帮助。

Tensorflow为各种深度学习用例提供端到端的支持,从实验性的探索到生产级模型部署到云服务器、移动端APP,自动驾驶等都给予相应的支持。

Uber推出Michelangelo内部机器学习服务平台,可以让机器学习轻松部署到大规模系统中。

背景

随着Uber在Tensorflow的机器学习训练任务越来越多,项目的数据和计算能力需求急剧增加。大部分情况下,模型可以在单个或多个GPU平台的服务器运行,单有些训练集十分庞大,用于训练的时间非常漫长。

Uber开始尝试部署标准分布式Tensorflow。在标准的分布式Tensorflow中引入很多新的概念:工作线程、参数服务器、tf.Server()、tf.ClusterSpec()、tf.train.SyncReplicasOptimizer()、tf.train.replicas_device_setter()等。虽然它们能起到优化作用,但也存在难以诊断的问题。

另一方面,标准的分布式Tensorflow机制无法满足需求。如,使用128个GPU训练,可能会损失一半的计算资源。

上面即是使用标准Tensorflow基准测试套件,在128块Nvida Pascal GPU测试时的效果图。而无论是Inception V3还是ResNET-101都会浪费近一半的GPU算力。

如何充分利用GPU资源,是目前大规模训练的重要课题,Facebook训练ImageNet的论文《Accurate,Large Minibatch SGD:Training ImageNet in 1Hour》介绍了如何使用256块GPU进行ResNet-50网络数据并行训练的方法。

数据并行在分布式训练上包含在多节点上并行分割数据和训练。在同步情况下,不同批次数据的梯度将在不同节点上分别进行计算。

由于Uber面临的模型小到可以在单个GPU或多个GPU的单服务器上运行,因此,可以尝试数据并行的方法。

数据并行的分布式训练方法步骤如下:

  1. 运行训练脚本的多个副本,每个副本读取数据块,定义输入模型,计算模型更新(梯度)
  2. 计算副本梯度的均值
  3. 更新模型
  4. 重复1步骤

标准分布式Tensorflow使用参数服务器来平均梯度,此时每个进程都有一到两个角色:工作线程或参数服务器。

工作线程处理训练数据,计算梯度,并将它们传递到参数服务器上平均。

但是确定工作线程与参数服务器的比例并不容易。而一旦使用参数服务器,它就可能成为网络计算的瓶颈。

如果使用多个参数服务器,通信模式就会变成all-to-all状态,网络可能会很快饱和。

2017年,百度发表《Bringing HPC Techniques to Deep Learning》,提出使用不同的算法来平均梯度,并让这些梯度在所有节点之间交流,称为ring-allreduce。

在ring-allreduce算法中,每个N节点与其他两个节点进行2*(N-1)次通信。在通信过程中,一个节点发送并接收数据缓冲区传来的块。

第一次N-1迭代中,接收的值添加到节点缓冲区;第二次N-1迭代中,接收的值替换缓冲区中的值。

除了网络优化之外,allreduce利用消息传递接口(Message Passing Interface,MPI)的实现,如Open MPI,启动Tensorflow的所有副本。MPI明确建立分布式条件下工作线程互相通信的范式。

Horovod

Uber Tensorflow在Tensorflow ring-allreduce基础上构建

  • 代码转换成Python包Horovod

  • 使用NCCL替换百度的ring-allreduce实现,NCCL是Nvida的集合通信库,提供高度优化的ring-allreduce版本。NCCL 2允许在多个机器之间运行ring-allreduce

  • 支持模型适应单个服务器和多个GPU,原始版本只支持单个GPU模型

results matching ""

    No results matching ""