我发现他们的加速速度> 200x(> 1000 Gflops).
ftp://ftp.u-aizu.ac.jp/u-aizu/doc/Tech-Report/2012/2012-002.pdf
我不知道我做错了什么,或者只是因为我的GPU(nvidia GTX 275).或者,如果是因为一些pyOpenCl开销.但是我也确信将GPU的结果复制到RAM需要多长时间,它只是矩阵乘法时间的10%左右.
#define BLOCK_SIZE 22 __kernel void matrixMul( __global float* Cij, __global float* Aik, __global float* Bkj, __const int ni, __const int nj, __const int nk ){ // WARRNING : interchange of i and j dimension lower the performance >2x on my nV GT275 GPU int gj = get_global_id(0); int gi = get_global_id(1); int bj = get_group_id(0); int bi = get_group_id(1); // Block index int tj = get_local_id(0); int ti = get_local_id(1); // Thread index int oj = bi*BLOCK_SIZE; int oi = bj*BLOCK_SIZE; float Csub =0; __local float As [BLOCK_SIZE][BLOCK_SIZE]; __local float Bs [BLOCK_SIZE][BLOCK_SIZE]; for (int ok = 0; ok < nk; ok += BLOCK_SIZE ) { As[ti][tj] = Aik[ nk*(gi ) + tj + ok ]; // A[i][k] Bs[ti][tj] = Bkj[ nj*(ti+ok) + gj ]; // B[k][j] barrier(CLK_LOCAL_MEM_FENCE); for (int k = 0; k < BLOCK_SIZE; ++k) Csub += As[ti][k] * Bs[k][tj]; barrier(CLK_LOCAL_MEM_FENCE); } Cij[ nj * ( gi ) + gj ] = Csub;
}
注意 – 奇怪的BLOCK_SIZE = 22是最大的BLOCK_SIZE,它适合我的GPU上的最大work_group_size,即512.在此代码中必须保持条件BLOCK_SIZE ^ 2< max work_group_size. 22 = INT(SQRT(512)).我也尝试过BLOCK_SIZE = 16或8但是它的速度比较慢. 我也尝试过简单的matrixMul(不使用本地内存),但它甚至比numpy.dot()慢10倍.
我在这里复制了代码
http://gpgpu-computing4.blogspot.cz/2009/10/matrix-multiplication-3-opencl.html
他们说即使是简单的版本(没有本地内存)也应该比CPU快200倍?我并不感到不安.
在我的案例中,表现的依赖性是:
N = 220 numpy 3.680 [Gflops] GPU 16.428 [Gflops] speedUp 4.464 N = 330 numpy 4.752 [Gflops] GPU 29.487 [Gflops] speedUp 6.205 N = 440 numpy 4.914 [Gflops] GPU 37.096 [Gflops] speedUp 7.548 N = 550 numpy 3.849 [Gflops] GPU 47.019 [Gflops] speedUp 12.217 N = 660 numpy 5.251 [Gflops] GPU 49.999 [Gflops] speedUp 9.522 N = 770 numpy 4.565 [Gflops] GPU 48.567 [Gflops] speedUp 10.638 N = 880 numpy 5.452 [Gflops] GPU 44.444 [Gflops] speedUp 8.152 N = 990 numpy 4.976 [Gflops] GPU 42.187 [Gflops] speedUp 8.478 N = 1100 numpy 5.324 [Gflops] GPU 83.187 [Gflops] speedUp 15.625 N = 1210 numpy 5.401 [Gflops] GPU 57.147 [Gflops] speedUp 10.581 N = 1320 numpy 5.450 [Gflops] GPU 48.936 [Gflops] speedUp 8.979
注 – “Gflops”数字是以N ^ 3 /时间获得的,它确实包括将结果从GPU复制到主存储器所需的时间,但这次只占总时间的百分之几,特别是对于N> 1000
也许更多的画面是时间在secons:
N = 220 numpy 0.003 [s] GPU 0.001 [s] load 0.001 [s] speedUp 5.000 N = 330 numpy 0.008 [s] GPU 0.001 [s] load 0.001 [s] speedUp 7.683 N = 440 numpy 0.017 [s] GPU 0.002 [s] load 0.001 [s] speedUp 7.565 N = 550 numpy 0.043 [s] GPU 0.004 [s] load 0.001 [s] speedUp 11.957 N = 660 numpy 0.055 [s] GPU 0.006 [s] load 0.002 [s] speedUp 9.298 N = 770 numpy 0.100 [s] GPU 0.009 [s] load 0.003 [s] speedUp 10.638 N = 880 numpy 0.125 [s] GPU 0.010 [s] load 0.000 [s] speedUp 12.097 N = 990 numpy 0.195 [s] GPU 0.015 [s] load 0.000 [s] speedUp 12.581 N = 1100 numpy 0.250 [s] GPU 0.031 [s] load 0.000 [s] speedUp 8.065 N = 1210 numpy 0.328 [s] GPU 0.031 [s] load 0.000 [s] speedUp 10.581 N = 1320 numpy 0.422 [s] GPU 0.047 [s] load 0.000 [s] speedUp 8.979
我在想,也许可以通过使用获得一些速度提升
async_work_group_copy或甚至read_imageui将块复制到本地内存.但是我不明白为什么当我使用基本相同的代码而不是那些说他们有200倍加速的人时,我有这么大的差异?
4 GHz的Intel 2600K可以做4 GHz *(8 AVX)*(2 ILP)*(4核)= 256 SP GFLOPs / s.对于DP,它是一半:128 DP GFLOPs / s.几周后出现的Haswell将使这两者都加倍.英特尔MKL库在GEMM中的效率优于80%.我自己的GEMM代码在我的i7-2700上获得了70%,所以你用numpy引用的5 GFlops / s是微小的,不公平的比较.
我不知道GTX 275的功能是什么,但我猜它会超过50 GFLOPs / s.
您引用的文章比较了AMD 7970.它们获得了848(90%效率)DP GFlops / s和2646(70%效率)SP GFlops / s.这比CPU的性能提高了10倍而不是200倍!
编辑:
你对FLOP的计算是错误的应该是2.0 * n ^ 3.这仍然是近似的,但它渐近正确.让我解释.
考虑一个3D点产品.它是x1 * x2 y1 * y2 z1 * z2.这是3次乘法和两次加法.因此,N维点积是n次乘法和(n-1)次加法.矩阵乘积相当于n×n点积,即n * n * n次乘法和n * n *(n-1)次加法.这大约是2.0 * n ^ 3 FLOPS.所以你应该把你所有的Gflops / s数加倍.
编辑:
您可能想要考虑内核时间.自从我使用OpenCL以来已经有一段时间了,但是使用C绑定我做了类似的事情
queue = cl::CommandQueue(context, devices[device], CL_QUEUE_PROFILING_ENABLE|CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE, &err); //other code...run kernel time_end = clevent.getProfilingInfo<CL_PROFILING_COMMAND_END>(); time_start = clevent.getProfilingInfo<CL_PROFILING_COMMAND_START>();