Advertisement

cuDNN: efficient Primitives for Deep Learning 论文阅读笔记

阅读量:

该论文主要探讨如何在CNN模型中进行GPU加速矩阵运算的优化设计。在传统CNN架构中,计算开销主要集中在卷积层、激活函数以及池化操作这三个关键组件上。

首先,我们看convolution的操作过程:

参数表:

O被视为output feature map的结果,F被视为filter的作用,D0被视为input feature map的一部分. 通过观察公式可知,若采用循环操作,将涉及7次迭代次数,n,k,p,q四组参数能够分别执行,c,r,s变量则代表累加操作中的循环变量.

其次,我们看convolution在GPU上如何实现,文中介绍了三种方法:

第一,在最基础的方法中编译所述公式时会遇到许多特殊情形问题。

第二段:采用快速傅里叶变换(FFT),具体实施方式如何?可参考文献《Fast training of convolutional networks through ffts》(待读)。此方法具有较高的效率优势;然而由于滤波器尺寸需与输入图像一致这一限制因素的存在,在实际应用中会导致内存占用大幅增加。特别地,在卷积神经网络(CNN)的早期层中滤波器尺寸通常远小于输入图像尺寸的情况更为常见。此外,在stride参数大于1的情况下,“FFT”的计算效率也未能显著提升。“Facebook团队近期发布了FBFFT的实现方案”,这方面的研究也可参考《fast convolutional nets with fbfft: a gpu performance evaluation》(待读)。

第三步也是caffe框架实现的核心方法之一。通过将其转化为密集矩阵乘法来实现卷积操作,在此过程中需要将输入数据组织成一个CRS × NPQ大小的矩阵以完成计算。这种处理方式使得内存规模相较于原始输入数据增加了RS倍左右(例如,在AlexNet中的conv1层中)。

Fm: 96 x 363

Dm: 363 x 387200(设double 类型, 需要临时分配内存1GB)

D: 128 x 3 x 227 x 227 = 19787136.

Dm 是D的内存大小的7倍。

具体卷积是如何转换为矩阵的呢?看如下图:

在参考caffe库的代码时发现使用了im2col_gpu以及两个名为caffe_gpu_gemm的功能模块;这些功能模块负责调用cublasSgemm实现矩阵乘法运算。

这种方法使用扩大临时内存方法换取密集矩阵计算的便利。

密集矩阵相乘具有较高的浮点运算与数据传输比(floating-point operations per byte),因此成为值得采用的一种高效计算方式。
随着矩阵尺寸的增长这一比率也随之提升。
观察该方法在不同规模下的表现发现CRS乘机相对较大。
然而该方法存在显著缺陷即所涉参数量(Dm)过大导致必须将其划分为多个块进行处理。
查看caffe代码实现发现每次batch都需要执行N次im2col_gpu及caffe_gpu_gem操作。
由于这种循环依赖模式使得在处理过程中频繁地读取和处理Dm以及D相较于之前的方案而言在内存交通方面表现不佳。
因此本文提出了一种改进方案:
深入分析发现当前的设计模式主要源于逐个读取的方式造成了低效的数据加载和缓存机制。
为了提升整体性能考虑采用并行计算的优势将计算操作连续化以减少数据加载频率并最大化利用硬件资源。
最终通过调整算法参数优化了系统的时空性能并通过实验验证了该改进方案的有效性。

对矩阵A × 矩阵B = 矩阵C,在外部存储器中按块加载矩阵A和矩阵B到缓存区中,并同时计算生成矩阵C中的一小部分区域。这样处理能够有效降低数据传输造成的延迟问题。对于中间结果Dm的处理,则是在内部缓存中完成转换操作,并非依赖外部存储器进行转换操作。

三种方法性能的比较:

全部评论 (0)

还没有任何评论哟~