撰文|袁进辉
天下文治,唯快不破。怎么更快地训练深度学习模型是业界始终关注的焦点,业界玩家或开发专用硬件,或开发软件框架,各显神通。本文将介绍对深度学习计算效率最要害的一些基本定律,这有助于用户了解深度学习引擎的瓶颈在哪里以及如何解决这些挑战。
当然,这些定律在计算机体系结构的教材和文献中都可看到,譬如这本《计算机体系结构:量化钻研办法(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 示意运算强度,即 I beta>pi。在把 Computing Unit 的运算单元减少 s 倍后,实践计算峰值是 s pi,假如该工作的运算强度 I 足够高,使得在实践峰值进步 s 倍之后仍是计算受限型,即 I beta > spi;(2)假如没有应用流水线,Communication Unit 和 Computing Unit 总是程序执行(后文咱们将专门探讨流水线的影响)。让咱们来计算一下工作执行效率进步了几倍。
在实践峰值是 pi 的初始状况下,1 秒钟 Communication Unit 搬运了 beta 字节的数据,Computing Unit 须要(Ibeta)/pi 秒来实现计算。即在 1 +(Ibeta)/pi 秒工夫内实现了 I beta 的计算,那么单位工夫内能够实现(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…