Capuchin: Tensor-based GPU Memor

2020-03-18  本文已影响0人  CPinging

ASPLOS'20的一篇关于GPU显存与DRAM的混合存储优化方案,是比较热并且相对比较有使用价值的文章,简单总结一下放这里。这篇文章出自华科,总结在这里,均是个人理解,若有理解偏差欢迎指正。

整体文章流程

当前GPU内存不够,模型又太大,装不下。DRAM存储量相对GPU显存来说比较大,可以利用起来。并且在之前的一些论文中也发现,其实GPU训练的时候有非常多的内容其实是当前操作不需要的,这些内容没必要仍然存储在GPU显存中。所以需要一些方案将数据在GPU与DRAM之间进行转移,或者干脆直接不要重新算。

背景

背景部分介绍了一些DL的基本概念,内存使用主要包括Feature map+梯度map+卷积工作空间。

其中wb占比比较小所以基本持续存储在GPU显存中。

除此之外,文章还介绍了TensorFlow的两种模式Eager Mode以及Graph Mode。

动机

前文讲到了可以在两个存储中交换数据,交换数据是要有开销的,而这个开销可以计算。下图是一个概念示意图,包括前传与后传两种情况,中间的同步开销意思是要等数据转完再进行第二个操作。文章说这个开销有时候会达到41.3%。

image.png

所以何时释放数据以及何时把数据预取回来就需要仔细思考一下了。

文章抨击了一下之前的工作:说之前的工作其实都是根据层的类型来设计,比如卷积层就肯定计算更复杂,需要的时间更多。所以就非常不准确。为此进行了测试,如下图同样都是卷积层使用的时间就不一样。

when running InceptionV3 on P100 GPU. The minimum and maximum execution time are 474us and 17727us, respectively, which varies as large as 37×. Among these 94 convolution layers, 95.7% of their execution time are less than 3ms while the left four exceed 8ms.

意思是各个层之间的差别还是很大的,就不能一视同仁。

image.png

所以原来的设计方案就产生了一些问题:1 计算能力更强,所以数据转移很难与计算完美并行;2 卷积层这么多如果单纯的就对这种层不操作其实会限制优化深度。

作者根据DL的iteration的特征,发现其实数据Tensor从访问到再次访问是要经历一个比较规律的时间,所以就可以根据这个时间间隔来对这些tensor划分一些优化优先级,比如越是两边的数据越值得去做swap或者recompute(这是一种直观的印象)

image.png

方案设计

设计思路

我们的目标只有两个,那就是尽量的降低开销以及不要改太多代码。

总任务分两个阶段:(1)测试阶段,就是从第一个iteration中获得一些Tensor的特征;(2)执行阶段:根据测试到的特征进行决策然后执行

之后设计了一些方案回答了如下四个问题:

image.png

设计详情

对于swap,降低开销的最好方法是将swap与计算并行化;对于compute,就是要选择最便宜的情况做(说白了就是如果compute更快就用他,不然就用swap)

文章设计了一些指标:

image.png

SwapTime就是从系统发出转移数据的请求开始,到真正转移到CPU上所经历的时间(就是在路上走的时间)

SwapInTIme:举例子就是T3在后面要用到,那么我需要提前把它提前取出来,那么取的这个决定下发的时刻就是SwapInStartTime。

SwapOutTime:就是数据已经从GPU转移到CPU上的那个时刻。

Tensor生成代价

1 对于swap可以计算SwapInStartTime,不过这里文章考虑了一下in-trigger的决策需要考虑当时Memory是否被占用比较严重。如果很严重是不适合生成的,否则会强制刷出去其他的tensor反而会降低效率;所以引入了一种反馈机制,就是如果出现了很急切的情况,那么下一次训练会动态调整把这个intrigger时间提前。

2 重计算方案肯定会占用计算资源,测量也发现其实我的计算资源似乎一直都在被占用,所以干脆按需计算,即需要的时候再算。在计算的时候需要考虑很多,比如需要根据tensor的生命周期对其进行排序;此外Tensor之间有关联关系,所以一个Tensor出现会使得改变后面Tensor的计算时间。

方案选择

swap可以做并行而重计算会徒增性能损耗,所以优先swap。

首先系统会将符合以下两者的Tensor加入被处理列表:(1)Tensor会被处理多次(2)Tensor在内存密集的时候被访问

所以系统先根据FT(FT = SwapInStartTime - SwapOutEndTime)作为依据,如果一个Tensor的FT非常大那么意味着这个Tensor更值得去去swap或者recompute,那就把这个大FT的Tensor放到列表的前面。

如果全部都用swap的方案不合适,那么就用混合方案:
如下图


image.png

针对Tensor,比较哪一个方案开销更小就用哪个。

在重计算中使用了如下指标:

一个Tensor重计算所需的时间越小,且它所需memory越大,那这个Tensor就更有价值去做。

不过我当前tensor重计算时间其实取决于前面的Tensor是否在GPU中,T1到T4,T4需要被计算,如果T2在GPU那就可以从T2开始算,T2 不在就需要从T1开始算。所以每一个重计算队列的数据的更新会影响后面数据的计算时间。

除此之外,由于算T4的时候会把T2到T4的数据都算出来,那我下次如果使用T3还要算,就非常不划算。于是也设计了一些方法让T3留下来,从而不用重复算一些相似的数据。

测试概述

实验环境:

image.png

首先对系统的各个优化做了个性能提升分解测试:

image.png

DS (delayed synchronization) refers to decoupled computation and swapping optimization; ATP (Access Time-based Pro- fling) refers to enabling the measured execution; FA refers feedback-driven adjustment of in-trigger time.

之后测试了一下Graph Mode中的内存减少量:

image.png

数字代表最多能训练的batch size数量。

性能测试:

image.png

X代表原生的TensorFlow,因为只能装下有限的batch size,所以基本只能测到前两个数据。

对于VGG16,先升再降低是因为开始的时候空间被释放所以可以使用快速的卷积函数,而到后面内存又不足了所以卷积函数又为慢速。

在Eager Mode模式中,内存与性能分别为:

image.png image.png
上一篇 下一篇

猜你喜欢

热点阅读