负速度增益使用Numba Vectorize target ='cuda'

时间:2016-10-13 16:43:17

标签: cuda anaconda vectorization numba pycuda

我正在尝试测试使用Python Numba模块的@vectorize装饰器加速与我的实际代码相关的代码片段的有效性。我正在使用CUDAcast#10中提供的代码段here,如下所示:

import numpy as np
from timeit import default_timer as timer
from numba import vectorize


@vectorize(["float32(float32, float32)"], target='cpu')
def VectorAdd(a,b):
        return a + b

def main():
        N = 32000000

        A = np.ones(N, dtype=np.float32)
        B = np.ones(N, dtype=np.float32)
        C = np.zeros(N, dtype=np.float32)


        start = timer()
        C = VectorAdd(A, B)
        vectoradd_time = timer() - start

        print("C[:5] = " + str(C[:5]))
        print("C[-5:] = " + str(C[-5:]))

        print("VectorAdd took %f seconds" % vectoradd_time)

if __name__ == '__main__':
        main()

在CUDAcast的演示中,演示者通过@vectorize装饰器将大阵列方程式发送到gpu,从而获得100倍的加速。但是,当我将@vectorize目标设置为gpu:

@vectorize(["float32(float32, float32)"], target='cuda')

......结果慢了3-4倍。使用target ='cpu',我的运行时间为0.048秒;使用target ='cuda'我的运行时间为0.22秒。我正在使用配备Intel Core i7-4710MQ处理器和NVIDIA Quadro K2100M GPU的DELL Precision笔记本电脑。运行nvprof(NVIDIA分析器工具)的输出表明大部分时间花费在内存处理(预期)上,但即使功能评估在GPU上花费的时间也比整个过程在CPU上花费的时间长。显然这不是我希望的结果,但这是由于我的一些错误还是基于我的硬件和代码这是合理的?

1 个答案:

答案 0 :(得分:1)

这个问题对我来说也很有趣。 我已经尝试过您的代码并获得了类似的结果。 以某种方式调查此问题,我使用cuda.jit编写了CUDA内核并将其添加到您的代码中:

import numpy as np
from timeit import default_timer as timer
from numba import vectorize, cuda

N = 16*50000 #32000000
blockdim = 16, 1
griddim = int(N/blockdim[0]), 1

@cuda.jit("void(float32[:], float32[:])")
def VectorAdd_GPU(a, b):
    i = cuda.grid(1)
    if i < N:
        a[i] += b[i]

@vectorize("float32(float32, float32)", target='cpu')
def VectorAdd(a,b):
    return a + b


A = np.ones(N, dtype=np.float32)
B = np.ones(N, dtype=np.float32)
C = np.zeros(N, dtype=np.float32)

start = timer()
C = VectorAdd(A, B)
vectoradd_time = timer() - start
print("VectorAdd took %f seconds" % vectoradd_time)

start = timer()
d_A = cuda.to_device(A)
d_B = cuda.to_device(B)
VectorAdd_GPU[griddim,blockdim](d_A, d_B)
C = d_A.copy_to_host()
vectoradd_time = timer() - start
print("VectorAdd_GPU took %f seconds" % vectoradd_time)

print("C[:5] = " + str(C[:5]))
print("C[-5:] = " + str(C[-5:]))

在这个&#39;基准&#39;我还考虑了从主机到设备以及从设备到主机复制阵列的时间。在这种情况下,GPU功能比CPU 1慢。

对于上述情况:

CPU - 0.0033; 
GPU - 0.0096; 
Vectorize (target='cuda') - 0.15 (for my PC).

如果没有计算复制时间:

GPU - 0.000245

所以,我所学到的,(1)从主机到设备以及从设备到主机的复制非常耗时。这是显而易见的,众所周知的。 (2)我不知道原因,但@vectorize可以显着减慢GPU的计算速度。 (3)最好使用自编写的内核(当然最小化内存复制)。

顺便说一下,我还通过显式有限差分方案解决了热传导方程,测试了@ cuda.jit,发现在这种情况下,python程序的执行时间与C程序相当,提供了大约100倍的加速。这是因为,幸运的是,在这种情况下,您可以进行多次迭代,而无需在主机和设备之间进行数据交换。

UPD。二手软件&amp;硬件:Win7 64bit,CPU:Intel Core2 Quad 3GHz,GPU:NVIDIA GeForce GTX 580。