选自Baidu Research 机器之心编译 参与:吴攀、黄小天、晏奇 神经网络在过去几年中规模不断扩大,训练需要大量的数据和计算资源。为了提供所需的计算能力,我们可以使用高性能计算(HPC)中常见的技术将模型扩展到几十个 GPU,但该技术在深度学习中未被充分利用。这项技术,Ring Allreduce,还能减少不同 GPU 之间的通信时间,从而允许将更多时间用在有用计算上。在百度的硅谷人工智能实验室(SVAIL),我们已经成功地使用这些技术训练了当前最先进的语音识别模型。我们很高兴以库和 TensorFlow 软件补丁的形式推出 Ring Allreduce 的实现。我们也希望通过发布这些库可以使深度学习社区更有效地扩展他们的模型。 引言 在过去的几年中,神经网络已被证明是解决各种问题的非常有效的工具,并在规模和计算需求上快速增长。在用两个 GPU 运行一周并调节了 6000 万参数之后,用于图像识别的 SuperVision 卷积网络在物体识别方面取得了巨大成功 [1]。在 2016 年,对一个有超过 10 亿个参数的网络在 32 个 GPU 上训练了 3 周之后,研究人员在语言建模方面取得了突破性进展 [2]。在 SVAIL,2014 年我们的 Deep Speech 语音识别系统的第一次迭代约有 1100 万个参数 [5],而一年后的下一次迭代已经增长到 1 亿个参数 [3]。 随着参数数量以及神经网络计算需求的不断增长,在多节点、多 GPU 上进行高效并行的神经网络训练已经变得越发重要,因为等待几个月时间训练大型网络会减慢试验进程,限制进一步开发。在这篇博文中,我们提出了一种来自高性能计算(HPC)领域的技术,并演示如何将其应用于深度学习以在神经网络训练中取得显著的表现。 通信问题 当在多个 GPU 上并行训练一个神经网络,你必须选择如何将不同的运算分布到不同的 GPU 上。本文中,我们将介绍一种被称为数据并行随机梯度下降(data parallel stochastic gradient descent)的技术。在标准随机梯度下降(SGD)中,梯度下降通过使用数据的子集(minibatch)来完成,它们通过进行多次迭代来遍历整个数据集。然而,在数据并行训练中,每个 GPU 都有一个完整的神经网络模型的副本,并且每一次迭代只会被分配 minibatch 样本中的一个子集。对于每次迭代,每个 GPU 在自己处理的数据上将神经网络向前传播,随后再进行误差反向传播(error backpropagation)来计算相对于神经网络参数的损失的梯度。 最后,GPU 通过相互通信来平均不同 GPU 计算的梯度,将平均梯度应用于权重来获取新权重。GPU 在锁步(lock-step)中都进行迭代,并且一旦一个 GPU 完成了自己的迭代,它必须要等待其它所有 GPU 都完成,这样以保证权重可以被适当地更新。这等价于在单块 GPU 上处理 SGD,但是我们通过把数据分配给多个 GPU 来并行运算,从而获得了计算速度的提升。 当你仅仅只有两块 GPU 和数以兆字节(MB)的参数时,直播,这些 GPU 如何通信可能看上去没什么影响。但是,当你的模型有数十亿个参数时,直播,梯度就会占用千兆字(GB)节的空间(因为每个参数都有一个梯度值),并且你还在同时协调几十个 GPU,那么此时 GPU 之间的通信机制就显得非常重要了。 例如,我们考虑一下可能的最直接的通信机制。每个 GPU 都在 minibatch 上的一个子集里计算一个梯度。然后,每个 GPU 都将该子集的梯度发送给同一个 GPU,让这个 GPU 来计算所有梯度的平均值,最后它会将平均值发送回给其它 GPU。
与单个 reducer GPU 之间的数据传输 如果存在越多需要被发送的数据,那么发送的时间就越长;每个通信信道都有一个最大吞吐量(带宽)。例如,一个好的网络连接可以提供 15MB/s 的带宽,一个千兆以太网连接能提供 125MB/s 的带宽。搭载在高性能计算集群(HPC cluster)上的专业网络硬件(比如 InfiniBand)可以在结点之间提供高达数 GB/s 的带宽。 在数据于单个 GPU 上传输的直接机制(straight-forward mechanism)中,这个 GPU 必须接收来自所有其它 GPU 的所有参数,并且它还要将所有参数发回给所有 GPU。于是,系统中存在的 GPU 越多,通信成本就越大。 现在,让我们来评估一下这种通信机制在真实模型上的能力,例如,有一个基于百度语音识别系统 Deep Speech 2 开发的语音识别网络 [3],它有 3 亿个可训练参数,每个参数占 4 字节(Byte),也就是大概 1.2 GB 的数据量。让我们假设你系统上的网络硬件能够支持 1GB/s 的带宽,那也就是说,如此将你的系统在如上所述的两块 GPU 上并行训练,将会让每次迭代都变慢 1.2 秒。如果在 10 个 GPU 上并行训练,将会让每次迭代都变慢 10.8 秒。随着 GPU 数量的增加,处理每次迭代的时间都会线性增长。即便每个迭代会花个几秒钟,这种在通信成本中的快速线性增长也会使接下来的并行处理变得不现实,它大大降低了你训练的效率。 (责任编辑:本港台直播) |