我是CUDA的新手,我正试图用NUMBA \ CUDA来加速我的代码。 但是,由于我的代码非常慢,我遇到了一些麻烦。示例代码如下所示。
from timeit import default_timer as timer
from numba import jit, guvectorize, int32, int64, float64
from numba import cuda
@cuda.jit
def f_vec_loops(x, ret, maxiter):
nx = len(ret)
ny = len(ret[0])
for k in range(maxiter):
for i in range(nx):
for j in range(ny):
ret[i, j] += x[i, j]
x = 1024
y = 1024
a = np.ones([x, y], dtype='int32')
ret = np.zeros([x, y], dtype='int32')
a_cuda = cuda.to_device(a)
ret_cuda = cuda.to_device(ret)
maxiter = 100
s = timer()
cuda.synchronize()
f_vec_loops(a_cuda, ret_cuda, maxiter)
cuda.synchronize()
print(timer() - s)
s = timer()
trt = ret_cuda.copy_to_host()
print(trt)
print(timer()-s)
is代码的输出是后续的:
24.132136431649194
[[100 100 100 ..., 100 100 100]
[100 100 100 ..., 100 100 100]
[100 100 100 ..., 100 100 100]
...,
[100 100 100 ..., 100 100 100]
[100 100 100 ..., 100 100 100]
[100 100 100 ..., 100 100 100]]
0.03437229066477343
正如您所看到的,与问题的复杂性相关的结果时间是巨大的。我试图隔离单个GPU功能,结果时间非常短:
0.1956893293540045
我实现了取消" cuda.synchronize()",因此在某种程度上必须连接到线程的同步。 但是,我不知道如何解决这个问题。 欢迎任何帮助!
答案 0 :(得分:2)
这里有两个基本错误 - 你的内核是完全串行的,你正在运行一个线程。您通过删除cuda.synchronize()
看到的明显加速只是改变您测量的结果。内核启动API是异步的,因此删除同步调用只是意味着您只测量内核启动时间,而不是总内核执行时间。
您的内核可以通过以下方式进行简单修改:
from timeit import default_timer as timer
from numba import jit, guvectorize, int32, int64, float64
from numba import cuda
import numpy as np
import math
@cuda.jit
def f_vec_loops2(x, ret, maxiter):
nx = len(ret)
ny = len(ret[0])
i, j = cuda.grid(2)
if (i < nx) & (j < ny):
value = 0
for k in range(maxiter):
value += x[i, j]
ret[i, j] = value
@cuda.jit
def f_vec_loops(x, ret, maxiter):
nx = len(ret)
ny = len(ret[0])
for k in range(maxiter):
for i in range(nx):
for j in range(ny):
ret[i, j] += x[i, j]
x = 1024
y = 1024
a = np.ones([x, y], dtype='int32')
ret = np.zeros([x, y], dtype='int32')
a_cuda = cuda.to_device(a)
ret_cuda = cuda.to_device(ret)
maxiter = 100
s = timer()
f_vec_loops(a_cuda, ret_cuda, maxiter)
cuda.synchronize()
print(timer() - s)
threadsperblock = (16, 16)
blockspergrid_x = math.ceil(x / threadsperblock[0])
blockspergrid_y = math.ceil(y / threadsperblock[1])
blockspergrid = (blockspergrid_x, blockspergrid_y)
s = timer()
f_vec_loops2[blockspergrid, threadsperblock](a_cuda, ret_cuda, maxiter)
cuda.synchronize()
print(timer() - s)
s = timer()
trt = ret_cuda.copy_to_host()
print(trt)
print(timer()-s)
跑步时,你会看到类似的东西:
In [2]: %run something.py
24.983618166297674
0.11915503349155188
[[100 100 100 ..., 100 100 100]
[100 100 100 ..., 100 100 100]
[100 100 100 ..., 100 100 100]
...,
[100 100 100 ..., 100 100 100]
[100 100 100 ..., 100 100 100]
[100 100 100 ..., 100 100 100]]
0.002271135337650776
与原始(完全串行)代码相比,它提供了大约200倍的加速。
在CUDA中编写并行代码的基本概念在书籍,教程,博客,Stack Overflow问题以及工具包文档本身中有详细描述。 Numba Python CUDA语言非常忠实地复制了基本CUDA C语言的子集,从CUDA C学习CUDA Python的障碍非常低。您需要做的就是阅读。