加入收藏 | 设为首页 | 会员中心 | 我要投稿 辽源站长网 (https://www.0437zz.com/)- 云专线、云连接、智能数据、边缘计算、数据安全!
当前位置: 首页 > 教程 > 正文

干货:如何从系统层面优化深度学习计算?

发布时间:2018-06-14 17:48:41 所属栏目:教程 来源:伍鸣
导读:【资讯】编者按:在图像、语音识别、自然语言处理、强化学习等许多技术领域中,深度学习已经被证明是非常有效的,并且在某些问题上已经达到甚至超越了人类的水平。然而,深度学习对于计算能力有着很大的依赖,除了改变模型和算法,是否可以从系统的层面来

  1)Tensor是深度学习计算中最主要的数据结构,大量的计算开销都是花在对Tensor的处理上。Tensor是一种比较简单的数据结构,主要由meta-data和payload两部分组成。Payload就是基本元素的数组,而meta-data就是Tensor的shape信息,也就是维度和每一维的大小。这种简单的数据结构在传输的时候其实不太需要复杂的序列化和反序列化的功能。

  2)在相当多的情况下,Tensor是稠密的,并且其大小也是比较大的,也就是说在传输这样的Tensor的时候并不需要对其进行额外的批处理。

  3)深度学习的训练过程是迭代的。每个迭代处理一个mini-batch。在不同的迭代之间,数据流图和很多Tensor的shape信息并不发生改变,并且其中不少的shape信息是可以在运行时前就静态决定的。

  基于以上几个特点,我们可以对数据流图进行分析,找到那些可以静态决定shape信息的Tensor,以便在运行前,在接收端预先为其分配RDMA可访问的内存空间,并将其相应的可远程访问的地址传送给发送端。这样一来,在运行时,发送端可以通过单边的RDMA请求将Tensor的数据直接传输到接收端,从而完全避免了没有必要的额外内存拷贝,达到零拷贝的通信过程。我们将这种机制在TensorFlow上进行实验, 和基于TCP/IP的gRPC相比,这一方法在一系列典型模型上均取得了多倍的性能改进。甚至和针对RDMA优化过的gRPC相比,我们的方法仍然能够取得超过50%的性能提升。

  另外,我们在分布式深度学习方向上关注的另一个问题是如何自动地对资源无关的数据流图做优化的分布式执行,也就是自动划分数据流图中的计算任务并为其分配相应的计算资源,以使计算效率最优化。Google的Jeff Dean团队在这个方向上已经做了很好的先驱性工作。但局限于模型并行和单机多卡的运行环境,目前这仍然是一个非常重要并且大有可为的方向,需要结合数据并行,分布式及异构环境来综合考虑。

  提升单个计算单元的运算效率

  前面提到过,使用深度学习框架来实现的模型算法,在运行时前会被转换成数据流图。不少具有实际应用价值的模型都非常复杂,由它们所转换出来的数据流图通常是由成千上万的操作节点构成,其中包含了很多运算量非常小的节点,也就是说它们的输入矩阵的大小很小,或者是其计算逻辑的复杂度相对于对输入数据访问的复杂度来说很低。大量这样的操作节点会引入以下一些运行时开销,并且这样的开销会非常显著。

  1)深度学习系统运行时需要根据数据流图中节点的依赖关系来调度节点的执行。调度每个节点的系统开销和操作节点计算量的大小并没有直接关系,因此对于由许多小的操作节点构成的计算流图来说,系统调度所带来的额外开销就会相对比较大;

  2)对于在GPU上运行的计算来说,每个操作节点的实现都对应着一个GPU的内核函数,而这个内核函数的每一次执行需要CPU调用显卡驱动来启动,因此也带来了常数量级的额外开销。这个开销相对于计算量小的内核函数的执行来说是非常明显的;

  3)计算量小的操作节点往往难以挖掘出足够的数据并行性,因此不能充分利用处理器硬件中的计算资源。

  解决这一问题的主要思路是内核融合(Kernel Fusion)。一些手工的优化方法就运用了这一思想,比如NVIDIA基于CuDNN的RNN库函数。它把整个循环神经网络实现成一个GPU的内核函数,因此获得了非常好的性能。然而它的缺点也非常明显,那就是不够灵活和通用,无法应用在其它网络或一些变种的循环神经网络中。而我们更加关注的是如何在深度学习的系统中自动地对任意的网络模型实施优化。

  干货:如何从系统层面优化深度学习计算?

  目前在学术界和工业界已经存在一些系统采用编译的方法生成融合的内核代码,比如TVM、Halide和Taco等。这些系统使用Tensor Algebra作为前端表示方法,每个Tensor Algebra表达式进而可以被编译成相应的内核代码。而Tensor Algebra可以作为更低一层的中间表达被集成到深度学习系统中,也就是说高层的数据流图可以先转换成由Tensor Algebra表达式组成的代码块,再被编译成可执行的代码。然而,这些系统对于可以进行融合的操作节点有很多限制,不能很好地融合多个非pointwise的操作,例如多个矩阵乘操作。然而,我们发现如果打破这一限制从而融合更多操作节点是可以带来更多显著的性能提升的。

  在GPU的运行环境下融合多个非pointwise的操作具有一定的挑战性,因为非pointwise的操作中输入矩阵的每个元素都可能依赖于前一个操作的输出矩阵中的许多不同位置的元素值,所以在这两个操作之间需要插入Barrier同步原语。而在GPU中实现Barrier需要保证该内核的所有线程块在运行时都是保持活动状态的,这意味着我们必须要求融合后的内核采用有限个数的线程块,但同时又能够处理远超过线程块数量的数据块。

  为了解决这一问题,我们尝试采用persistent-thread的线程块模型,也就是说在融合后的内核的整个生命周期启动固定数目的线程块并让它们保持活动状态。我们的优化系统在产生融合的内核代码的过程中类似于解决一个装箱(bin-pack)问题,即把待融合的子数据流图中的每一个操作节点所要处理的数据块分派给适当的活动线程块,从而使得每个线程块的负载尽可能均衡,并且保持操作节点的运算在原数据流图中的并行性。

  为了生成优化的GPU内核函数,一个重要的考虑因素是线程块和数据块的合理划分。然而这又依赖于一些非常复杂的因素,比如操作节点运算中计算和访存复杂度的比率、GPU的shared memory的大小、寄存器文件的大小及分配方法等等。因此一个最优的选择是很难通过静态的方法决定的。幸运的是,深度学习的迭代性以及需要相当多的迭代才能收敛的特性使得我们可以利用早期的迭代过程来收集运行时的动态信息以帮助优化系统做更明智的决定。

  克服设备内存资源限制

(编辑:辽源站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

推荐文章
    热点阅读