[CAFFE笔记] Convolutional Layer II

神经网络

上篇.说到CAFFE的牛逼CNN Layer forwarding方法,我们发现它的内存占用是个问题,而且考虑到功耗和速度的关系,不得不说这样的方法并不太适合部署在嵌入式GPU上。

要解决内存占用的问题,我们不可能回到上文提到的第一种简单粗暴的直接计算每个输出点,虽然这样可以节约整个临时矩阵Col Matrix的空间,但这种“naïve”的方法会让计算变得奇慢无比。因此,我们引入一个调节变量“set”用于控制Col Matrix的大小。理论上来说,我们要实现的效果是追求速度快的就调小set,追求内存小功耗低的,就调大set。这样,这个调节变量就可以是闲内存,速度以及功耗间的trade-off。

什么是set?

Set,简而言之就是将Col Matrix按横轴分成的等分数量。如下图。我们将要实现一种改进的算法,将ColMatrix限制在原始Col Matrix的 1/set 大小。

set

这种改进的算法,其实就是多次循环法。每次只计算一个set大小的Col Matrix块,然后生成一部分输出图像。经过多次循环,计算不同部分,最终得到完整的输出图像。如下图。

计算Col Matrix

GEMM 计算输出

现在,我们就要考虑一下这个算法到底有什么提升效果。

对于小网络来说,这样分成多个set不仅不能减少太多内存占用,而且会极大增加forwarding的时间,因为我们需要多次命令GPU执行操作,GPU启动kernel是需要一定时间的。而且对于小网络来说,set越大,每次计算的量就越少,很可能导致GPU的运算单元处于低负荷状态(有大量空闲运算资源)。因此,对于小网络来说,并没有任何优势。

对于中型网络来说,就不一样了。即使分了几个set,但并不会让GPU空闲。GPU仍然满负荷运行。而且前面提到我们可以节约1-1/set的内存,虽然不是很多,但是也还凑合。唯一浪费时间的是GPU多次启动kernel。但我们还可以从GEMM操作中节约时间。因为GEMM操作对小矩阵来说特别快,所以,比起一次算一个大矩阵,把大矩阵分成小矩阵多次算可能会出现速度提升。因此总体上来说,分1-4个set并不会浪费太多时间,还可以节约部分内存。而功耗上并不会有太大变化。另一方面,如果将set设置得很大,无疑会浪费时间,但是功耗和内存都能下降很多。对中型网络来说,具体设置多大的set,取决于对内存,速度以及功耗的需求。

对大型网络来说,即使把set设置得非常大也不会导致浪费太多时间。因为多次启动kernel的时间对于整个forwarding时间来说可以忽略了。但此时因为set比较大而节约的内存却是很大的,几百M甚至上G,这对于移动GPU来说可是福音了。在功耗上,大网络一般都会达到GPU的功耗限制,因此功耗可以说是没有变化。

总的来说,引入set这个变量,可以实现一些trade-off。具体设置成多大,要根据具体需求而定。

分享到 评论