一、 算法基本思想:
1、 GPU中的一个线程产生一个卷积结果,有多少个结果就使用多少个Block;
2、 矩阵和卷积核存放在共享内存中,卷积结果存放在全局内存中;
3、 支持10000以内任意维度的二维矩阵,卷积核最大支持16x16。
4、 支持任意多幅图像的批处理。
二、 实验平台:
CPU:Intel(R) Xeon(R) E5-2650 0 @2.00GHz 16核 32线程
GPU:NVIDIA Tesla C2070(见下表)
RAM Memory:64G
Operating System:64bit Win7。
尺寸规格 |
9.75英寸PCIe x16规格 |
Tesla GPU的数量 |
1 |
CUDA核心数量 |
448 |
CUDA核心频率 |
1.15 GHz |
双精度浮点性能(峰值) |
515 Gflops |
单精度浮点性能(峰值) |
1.03 Tflops |
专用存储器总容量* Tesla C2050 Tesla C2070 |
3GB GDDR5 6GB GDDR5 |
存储器频率 |
1.5 GHz |
存储器接口 |
384位 |
存储器带宽 |
144 GB/秒 |
功耗 Tesla C2050 |
238W热设计功耗 |
系统接口 |
PCIe x16 Gen2 |
散热解决方案 |
主动式风扇散热器 |
显示器支持 Dual-Link DVI-I 显示器最大分辨率@ 60Hz |
1 2560x1600 |
软件开发工具 |
CUDA C/C++/Fortran、OpenCL以及DirectCompute工具包。 针对Visual Studio的NVIDIA?(英伟达?)Parallel Nsight? |
三、 CPU和GPU耗时比较
说明:在CPU实现中,不做任何优化,卷积操作使用基本的四层循环形式。为了程序了通用性,在GPU内部做了很多的条件测试,比较耗时。这个是初始版,可以做进一步优化,比如一些字节对齐等。
测试时间说明:使用clock()进行测试,精度为0.001秒(1ms),GPU测试的总时间包括函数调度开销、GPU启动开销、设备内存的申请释放开销、数据传输开销和计算开销等,并且测试了数据的预处理和后处理的时间消耗。CPU只有函数调度开销和计算开销。
误差说明:CPU和GPU均使用float型数组存储数据,矩阵和卷积核数据随机初始化,并对CPU和GPU卷积结果作比较,测试卷积的有效性。
初步分析:
A. CPU和GPU卷积结果误差为0,表明GPU实现是有效的。
B. 矩阵和卷积核较小时,CPU性能较好。矩阵和卷积核较大时,GPU性能较高,体现出GPU的并行性,能快速处理大规模、高吞吐量的数据。当数据量不是很大时,GPU耗时主要是启动开销,即设备内存的分配开销。
C. GPU上,一个线程产生一个卷积结果,在线程内部是串行的,卷积核越大,单个卷积结果越耗时。
为了减少访问全局内存的次数,运算前,矩阵和卷积核拷贝到Block内部的共享内存中。
使用二维Block,一个Block内部16x16个线程,产生多少个卷积结果就使用多少个Block,因此固定卷积核,改变矩阵大小,运行时间基本不变,当矩阵过大时,使用的Block数量过多时,运算时间受限于GPU硬件中支持的SM和Block数量。(考虑卷积程序的通用性,数据拷贝时使用了比较多的条件测试和分支操作,性能受一定影响)。
D. CPU上是简单的串行运算,受矩阵和卷积核大小影响较大。
E. 当矩阵两个维度都超过10000时,CPU运算出现指针异常,可能是矩阵较大时(550MB左右),数据存储时不再连续,指针溢出。所以无法测试。
Matrix Size |
Number |
Kernel |
CPU(s) |
CPU2GPU |
GPU-Kernel |
GPU2CPU |
5x4 |
1 |
5x4 |
<1ms |
<1ms |
<1ms |
<1ms |
12x9 |
1 |
5x4 |
<1ms |
<1ms |
<1ms |
<1ms |
18x19 |
1 |
5x4 |
<1ms |
<1ms |
<1ms |
<1ms |
118x29 |
1 |
5x4 |
<1ms |
<1ms |
<1ms |
<1ms |
138x59 |
1 |
5x4 |
<1ms |
<1ms |
<1ms |
<1ms |
158x159 |
1 |
5x4 |
0.003 |
<1ms |
0.001 |
<1ms |
558x559 |
1 |
5x4 |
0.044 |
0.001 |
0.001 |
<1ms |
1128x1159 |
1 |
5x4 |
0.157 |
0.002 |
0.004 |
0.001 |
2128x2159 |
1 |
5x4 |
0.442 |
0.007 |
0.012 |
0.007 |
5128x5159 |
1 |
5x4 |
2.394 |
0.038 |
0.068 |
0.035 |
18128x4159 |
1 |
5x4 |
6.866 |
0.111 |
0.193 |
0.114 |
10128x11159 |
1 |
5x4 |
10.074 |
0.160 |
0.288 |
0.142 |
15.54Gflops |
1.427GBps |
|||||
5x4 |
1 |
14x15 |
~ |
~ |
~ |
~ |
12x9 |
1 |
14x15 |
~ |
~ |
~ |
~ |
18x19 |
1 |
14x15 |
<1ms |
<1ms |
<1ms |
<1ms |
118x29 |
1 |
14x15 |
<1ms |
<1ms |
<1ms |
<1ms |
138x59 |
1 |
14x15 |
<1ms |
0.001 |
<1ms |
<1ms |
158x159 |
1 |
14x15 |
0.024 |
<1ms |
<1ms |
<1ms |
558x559 |
1 |
14x15 |
0.354 |
<1ms |
0.006 |
0.001 |
1128x1159 |
1 |
14x15 |
1.400 |
0.002 |
0.023 |
0.002 |
2128x2159 |
1 |
14x15 |
3.839 |
0.007 |
0.082 |
0.007 |
5128x5159 |
1 |
14x15 |
22.856 |
0.042 |
0.475 |
0.035 |
11128x4159 |
1 |
14x15 |
38.172 |
0.079 |
0.833 |
0.061 |
10128x11159 |
1 |
14x15 |
122.679 |
0.203 |
2.614 |
0.358 |
23.23Gflops |
382.6MBps |
|||||
5x4 |
15 |
14x15 |
~ |
~ |
~ |
~ |
12x9 |
15 |
14x15 |
~ |
~ |
~ |
~ |
18x19 |
15 |
14x15 |
0.001 |
<1ms |
<1ms |
<1ms |
118x29 |
15 |
14x15 |
0.041 |
<1ms |
0.001 |
<1ms |
138x59 |
15 |
14x15 |
0.097 |
<1ms |
0.002 |
<1ms |
158x159 |
15 |
14x15 |
0.372 |
0.001 |
0.007 |
<1ms |
558x559 |
15 |
14x15 |
4.943 |
0.006 |
0.084 |
0.006 |
1128x1159 |
15 |
14x15 |
15.851 |
0.030 |
0.353 |
0.028 |
2128x2159 |
15 |
14x15 |
57.699 |
0.097 |
1.247 |
0.084 |
3158x3059 |
15 |
14x15 |
121.152 |
0. 201 |
2.624 |
0.192 |
5128x5159 |
15 |
14x15 |
指针溢出 |
|||
11128x4159 |
15 |
14x15 |
||||
10128x11159 |
15 |
14x15 |
||||
23.01Gflops |
362.9MBps |
进一步分析:
从上表可知,最高吞吐率为1.427GBps,PCAIE总线的带宽为5GBps,还有一定的空间。单精度浮点数乘法的最高有效计算性能为23.23Gflops,官方文档上标示的最高单精度浮点性能为1Tflops,差别较大,分析原因如下:
A. CPU传输给GPU的数据是一维数组,而在GPU内部是按二维进行运算的,在存取数据是需要做很多的地址计算操作。
B. 由于卷积特有的性质,数据有很多的重复性,将大图像分割成很多小的图像块时,需要考虑边界问题,并且为了保证程序的通用性,支持任意的图像和卷积核大小,以及支持任意多幅图像的批处理,GPU中,将数据拷贝到共享内存之前,做了比较多的条件测试,时间消耗比较大。这个地方可以通过在CPU进行边界扩展等预处理,进一步提高GPU运算性能。
C. 线程内部计算单个卷积结果时,使用了一个二维循环,当卷积核较大时,运算时间呈指数型增长。
总结:
写一个GPU程序简单,写一个高效的GPU程序难,而写一个高效的通用性的GPU程序,更难,需要考虑方方面面的东西。目前版本的程序,仅仅具有简单的通用性,因为使用基本的数据结构保存数据,当数据量达到500MB时,很容易出现问题,而且计算效率也不是很高。
下周工作计划:
(1) 在CPU中做一些数据的预处理,考虑字节对齐,边界填充等,尽量减少GPU内部的条件测试。考虑将单个的卷积操作拆开,实现细粒度并行,提高单个卷积结果的计算效率。
(2) 学习三维Block,将一幅图像放在第一和第二维度上,批处理图像放在第三个维度,减少后处理计算量,增加批处理图像的卷积计算性能。
(3) 考虑反卷积运算的并行化。考虑将CUDA卷积程序与matlab版的CNN结合,进行交叉编译,提高CNN的运算效率。