撰文|袁进辉

天下文治,唯快不破。怎么更快地训练深度学习模型是业界始终关注的焦点,业界玩家或开发专用硬件,或开发软件框架,各显神通。本文将介绍对深度学习计算效率最要害的一些基本定律,这有助于用户了解深度学习引擎的瓶颈在哪里以及如何解决这些挑战。

当然,这些定律在计算机体系结构的教材和文献中都可看到,譬如这本《计算机体系结构:量化钻研办法(Computer Architecture: a Quantative Approach)》,但本文的价值在于有针对性地筛选最基本的几条定律,并联合深度学习引擎来了解。

1

对于计算量的假设

在钻研并行计算的定量模型之前,咱们先做一些设定。对于一个具体的深度学习模型训练任务,假如总的计算量V固定不变,那能够粗略认为只有实现V这个量级的计算,深度学习模型就实现训练。

GitHub这个页面(https://github.com/albanie/co...)列举了常见CNN模型解决一张图片所需的计算量,须要留神的是,本页面列出的是前向阶段的计算量,在训练阶段还须要后向阶段的计算,通常后向阶段的计算量是大于前向计算量的。这篇论文(https://openreview.net/pdf?id...)对训练阶段解决一张图片的计算量给出了一个直观的可视化后果:

以ResNet-50为例,训练阶段解决一张224X224x3的图片须要8G-Ops (约80亿次计算),整个ImageNet数据粗放有120万张图片,训练过程须要对整个数据汇合解决90遍(Epochs),粗略预计,训练过程共须要(810^9) (1.210^6) 90 = 0.864*10^18次运算,那么ResNet-50训练过程的总计算量大概是10亿乘以10亿次运算,咱们能够简略地认为,只有实现这些计算量就实现了模型运算。深度学习计算引擎的指标是以最短的工夫实现这个给定的计算量。

2

对于计算安装的假设

本文仅限于下图所示的以处理器为核心的计算安装(Processor-centric computing),以内存为核心的计算(Processing in memory)安装在业界有摸索,但还不是支流。

上图所示的计算安装中Computing Unit能够是通用处理器如CPU, GPGPU, 也能够是专用芯片如TPU等。如果Computing Unit是通用芯片,通常程序和数据都存储在Memory Unit,这也是当初最风行的冯诺依曼结构计算机。

如果Computing Unit是专用芯片,通常只有数据存储在Memory Unit。Communication Unit负责把数据从Memory Unit搬运给Computing Unit,实现数据加载(load),Computing Unit拿到数据后负责实现计算(数据的模式转换),再由Communication Unit把计算结果搬运到Memory Unit实现数据存储(Store)。

Communication Unit的传输能力通常用访存(Memory access)带宽beta示意,即每秒钟能够搬运的字节数,这通常和线缆数和信号的频率相干。Computing Unit的计算能力通常用吞吐率pi示意,即每秒钟能够实现的浮点计算次数(flops),这通常和计算单元上集成的逻辑运算器件个数及时钟频率无关。

深度学习引擎的指标是通过软硬件协同设计使得该计算安装解决数据的能力最强,即用最短的工夫实现给定的计算量。

3

Roofline Model: 刻画理论计算性能的数学模型

一个计算安装执行一个工作时能达到的理论计算性能(每秒钟实现的操作次数)不仅与访存带宽beta以及计算单元的实践峰值pi无关,还和当前任务自身的运算强度(Arithemetic intensity,或Operational intensity)。

工作的运算强度定义为每字节数据须要的浮点计算次数,即Flops per byte。艰深地了解,一个工作运算强度小,示意Computing Unit在Communication Unit搬运的一个字节上须要执行的运算次数少,为了让Computing Unit在这种状况下处于繁忙状态,Communication Unit就要频繁搬运数据;

一个工作运算强度大,示意Computing Unit在Communication Unit搬运的一个字节上须要执行的运算次数多,Communication Unit不须要那么频繁地搬运数据就能使Computing Unit处于繁忙状态。

首先,理论计算性能不会超过计算单元的实践峰值pi。其次,如果访存带宽beta特地小,1秒钟仅能把beta个字节从内存搬运到Computing Unit,令I示意以后计算工作中每个字节须要的操作次数,那么beta I 示意1秒钟内搬运过去的数据理论须要的操作次数,如果beta I < pi,则Computing Unit就不会饱和,也示意Computing Unit的利用率低于100%。

Roofline model 就是一种依据访存带宽,计算单元峰值吞吐率,工作的运算强度三者关系来推断理论计算性能的数学模型。由David Patterson团队在2008年发表在Communications of ACM上(https://en.wikipedia.org/wiki...),是一种简洁优雅的可视化模型:


图1:Roofline Model

图1横轴的自变量示意不同工作的运算强度,即每字节须要的浮点运算次数。纵轴的因变量示意理论可达的计算性能,即每秒钟执行的浮点运算次数。上图展现了两个运算强度别离为I_1和I_2的工作能理论达到的计算性能,I_1的运算强度小于pi/beta,称为访存受限工作,理论计算性能beta * I_1低于实践峰值pi。

I_2的运算强度高于pi/beta,称为计算受限型工作,理论计算性能达到实践峰值pi,访存带宽仅利用了pi/(I_2*beta)。图中斜线的斜率为beta,斜线和实践峰值pi 水平线的交点称为脊点(Ridge point),脊点的横坐标是pi/beta,当工作的运算强度等于pi/beta时,Communication Unit和Computing Unit处于均衡状态,哪一个都不会节约。

回顾深度学习引擎的指标“以最短的工夫实现给定的计算量”,就要最大化零碎的理论可达的计算性能。为了实现这个指标,有几种策略可用。

图1中的I_2是计算受限型工作,能够通过减少Computing Unit的并行度并进而进步实践峰值来进步理论计算性能,譬如在Computing Unit上集成更多的运算逻辑单元(ALU)。具体到深度学习场景,就是减少GPU,从一个GPU减少到几个GPU同时运算。

如图2所示,当在Computing Unit内减少更多的并行度后,实践峰值高于beta * I_2,那么I_2的理论计算性能就更高,只须要更短的工夫就能够。


图2:进步Computing Unit的实践峰值来进步理论计算性能

图1中的I_1是访存受限型的工作,则能够通过改善Communication Unit的传输带宽来进步理论计算性能,进步数据供给能力。如图3所示,斜线的斜率示意Communication Unit的传输带宽,当斜线的斜率增大时,I_1由访存受限型工作变成计算受限型工作,理论计算性能失去进步。


图3:进步Communication Unit的数据供给能力来进步理论计算性能

除了通过改善硬件的传输带宽或者实践峰值来进步理论计算性能外,还能够通过改善工作自身的运算强度来进步理论计算性能。同样的工作能够有多种不同的实现形式,不同实现形式的运算强度也存在差异。运算强度由I_1革新成超过pi/beta后,就变成计算受限型工作,理论计算性能达到pi,超过原来的beta*I_1。

在理论的深度学习引擎里,以上三种伎俩(进步并行度,改善传输带宽,应用运算强度更好的算法实现)都会用到。

4

Amdahl's Law: 如何计算减速比?

图2 的示例通过减少Computing Unit的并行度来进步理论计算性能,到底能把工作的执行工夫缩短多少呢?这就是减速比问题,也就是效率进步了几倍。

为了探讨不便,(1)咱们假如以后的工作是计算受限型,令I示意运算强度,即Ibeta>pi。在把Computing Unit的运算单元减少s倍后,实践计算峰值是s pi,假如该工作的运算强度I足够高,使得在实践峰值进步s倍之后仍是计算受限型,即Ibeta > spi;(2)假如没有应用流水线,Communication Unit和Computing Unit总是程序执行(后文咱们将专门探讨流水线的影响)。让咱们来计算一下工作执行效率进步了几倍。

在实践峰值是pi的初始状况下,1秒钟Communication Unit搬运了beta字节的数据,Computing Unit须要(Ibeta)/pi 秒来实现计算。即在1+(Ibeta)/pi 秒工夫内实现了Ibeta的计算,那么单位工夫内能够实现(Ibeta) / (1 + (Ibeta)/pi) 的计算,假如总计算量是V,则一共须要t1=V(1+(Ibeta)/pi)/(Ibeta) 秒。

通过减少并行度把实践计算峰值进步s倍之后,Communication Unit搬运beta字节的数据仍须要1秒钟,Computing Unit须要(Ibeta)/(spi)秒来实现计算。假如总计算量是V,那么共需t2=V(1+(Ibeta)/(spi))/(Ibeta)秒实现工作。

计算t1/t2即取得减速比:1/(pi/(pi+Ibeta)+(Ibeta)/(s(pi+Ibeta))),很道歉这个公式比拟难看,读者能够本人推导一下,比较简单。

在实践峰值是pi时,搬运数据花了1秒,计算花了(Ibeta)/pi 秒,那么计算工夫占的比例是 (Ibeta)/(pi + Ibeta),咱们令p示意这个比例,等于(Ibeta)/(pi + I*beta)。

把p代入t1/t2的减速比,能够失去减速比为1/(1-p+p/s),这就是赫赫有名的Amdahl's law(
https://en.wikipedia.org/wiki...)。其中p示意原始工作中能够被并行化局部的比例,s示意并行化的倍数,则1/(1-p+p/s)示意取得的减速比。

让咱们用一个简略的数字演算一下,假如Communication Unit搬运数据花了1秒钟,Computing Unit须要用9秒钟来计算,则p=0.9。假如咱们加强Computing Unit的并行度,令其实践峰值进步3倍,即s=3,则Computing Unit只须要3秒钟就能够实现计算,那么减速比是多少呢?利用Amdahl's law能够得悉减速比是2.5倍,减速比2.5小于Computing Unit的并行度倍数3。

咱们尝到了减少Computing Unit并行度的苦头,能不能通过进一步提高并行度s来取得更好的减速比呢?能够。譬如令s=9,那么咱们能够取得5倍减速比,能够看到进步并行度的收益越来越小。

咱们能通过有限进步s来进步减速比吗?能够,不过越来越不划算,试想令s趋于无穷大(即令Computing Unit实践峰值无限大),p/s就趋于0,那么减速比最大是1/(1-p)=10。

只有零碎中存在不可并行的局部(Communication Unit),减速比不可能超过1/(1-p)。

理论状况可能比减速比下限1/(1-p)要更差一些,因为上述剖析假如了运算强度I无穷大,而且在减少Computing Unit并行度时,通常会使得Communication Unit的传输带宽降落,就使得p更小,从而1/(1-p)更大。

这个论断令人很乐观,即便通信开销(1-p)只占0.01,也意味着无论应用多少并行单元,成千上万,咱们最大只能取得100倍的减速比。有没有方法让p尽可能靠近1,也就是1-p趋近于0,从而进步减速比呢?有一枚灵丹妙药:流水线。

5

Pipelining: 灵丹妙药

在推导Amdahl's law时,咱们假如了Communication Unit和Computing Unit串行工作,总是先令Communication Unit搬运数据,Computing Unit再做计算,计算实现再令Communication Unit搬运数据,再计算,如此周而复始。

能不能让Communication Unit和Computing Unit同时工作,一边搬运数据一边计算呢?如果Computing Unit每计算完一份数据,就立即能够开始计算下一批数据,那么p就简直是1,无论并行度s进步多少倍,都能取得线性减速比。让咱们钻研一下什么条件下能够取得线性减速比。


图4:(同图1)Roofline Model

图4中的I_1是通信受限型工作,1秒钟Communication Unit能够搬运beta字节的数据,解决这beta字节Computing Unit须要的计算量是betaI_1次操作,实践计算峰值是pi,一共须要(betaI_1)/pi秒实现计算。

对于通信受限型工作,咱们有betaI_1<pi,所以Computing Unit的计算工夫是小于1秒的。这也就意味着不到1秒的计算却须要花1秒钟的工夫搬运数据,那么计算工夫就无奈掩盖住数据搬运工夫,p最大能够做到(betaI_1)/pi,减速比最大是1/(pi-beta*I_1)。

图4中的I_2是计算受限工作,1秒钟Communication Unit能够搬运beta字节的数据,解决这beta字节Computing Unit须要的计算量是betaI_2次操作,实践计算峰值是pi,一共须要(betaI_2)/pi秒实现计算。对于计算受限型工作,咱们有beta*I_2>pi,所以Computing Unit的计算工夫是大于1秒的。

这也就意味着,每花1秒钟搬运的数据须要好几秒能力计算完,在计算的工夫内有短缺的工夫去搬运下一批数据,也就是计算工夫能掩盖住数据搬运工夫,p最大是1,只有I是无穷大,减速比就能够无穷大。

使得Communication Unit和Computing Unit重叠工作的技术叫流水线(*Pipelinging:
https://en.wikipedia.org/wiki...(computing)*)。是一种无效地进步Computing Unit利用率和进步减速比的技术。

6

并行计算的量化模型对深度学习引擎的启发

上文探讨的各种量化模型对深度学习引擎研发同样实用,譬如对于计算受限型工作,能够通过减少并行度(减少显卡)来减速;即便是应用同样的硬件设施,应用不同的并行办法(数据并行,模型并行或流水线并行)会影响到运算强度I,从而影响理论计算性能;分布式深度学习引擎蕴含大量的通信开销和运行时开销,如何减小或覆盖这些开销对于减速成果至关重要。

在Processor-centric计算安装的视角下了解基于GPU训练深度学习模型,读者能够思考一下怎么设计深度学习引擎来取得更好的减速比。

在单机单卡状况下,只须要做好数据搬运和计算的流水线,就能够做到GPU 100%的利用率。理论计算性能最终取决于底层矩阵计算的效率,也就是cudnn的效率,实践上各种深度学习框架在单卡场景不应该存在性能差距。

如果想在同一台机器外部通过减少GPU来取得减速,与单卡场景相比,减少了GPU之间数据搬运的复杂性,不同的工作切分形式可能会产生不同的运算强度I(譬如对卷积层适宜做数据并行,对全连贯层适宜模型并行)。除了通信开销,运行时的调度开销也会影响减速比。

多机多卡场景,GPU之间数据搬运的复杂性进一步提高,机器之间通过网络搬运数据的带宽个别低于机器外部通过PCIe搬运数据的带宽,这意味着并行度进步了,可数据搬运带宽升高了,代表着Roofline model中斜线的斜率变小了,CNN这种适宜数据并行的场景通常意味着比拟高的运算强度I,而还有一些模型譬如RNN/LSTM,运算强度I就小很多,这也意味着流水线中的通信开销更难以覆盖了。

7

总结

有用过分布式深度学习引擎的读者应该对软件框架的减速比有切身的领会,基本上,卷积神经网络这种适宜数据并行(运算强度I比拟高)的模型通过减少GPU来减速的成果还是比拟令人满意的,然而,还有很大一类神经网络应用模型并行的运算强度才更高一点,而且即便应用模型并行,其运算强度也远低于卷积神经网络,对于这些利用如何通过减少GPU并行度来取得减速是业界尚未解决的难题。

在之前的深度学习评测中,甚至产生了应用多GPU训练RNN速度比单个GPU还要慢的状况(
https://rare-technologies.com...)。无论应用什么技术解决深度学习引擎的效率问题,万变不离其宗,为了进步减速比,都是为了减小运行时开销,抉择适合的并行模式来进步运算强度,通过流水线覆盖通信开销,也都在本文形容的基本定律涵盖的范畴之内。

本文实现于2018年初,文中所举例子已比拟古老,但不影响原理的阐释。

欢送下载体验 OneFlow v0.7.0 最新版本:https://github.com/Oneflow-In...