【发布时间】:2019-12-24 23:02:50
【问题描述】:
我正在尝试编写 cuda.jit 矩阵乘法,并限制我的线程块数量,它只能是一个。而且我也知道我的乘法是 X*Xtranspose 的形式。
def matmul_gpu(X, Y):
# Allocate the output matrix in GPU memory using cuda.to_device
#
# invoke the dot kernel with 1 threadBlock with 1024 threads
#
# copy the output matrix from GPU to cpu using copy_to_host()
gpu_mat1 = cuda.to_device(X)
gpu_mat2 = cuda.to_device(Y)
res = np.zeros(shape=(X.shape[0], Y.shape[1]), dtype=np.float32)
gpu_mult_res = cuda.to_device(res)
threads_per_block = 1024
blocks_per_grid = 1
matmul_kernel[blocks_per_grid, threads_per_block](
gpu_mat1, gpu_mat2, gpu_mult_res)
mult_res = gpu_mult_res.copy_to_host()
return mult_res
@cuda.jit
def matmul_kernel(A, B, C):
num_of_threads = cuda.gridsize(1)
tid = cuda.grid(1)
rows_num = A.shape[0]
cols_num = A.shape[1]
step = int(np.math.ceil(num_of_threads / cols_num))
row = int(np.math.floor(tid / cols_num))
col = int(tid % cols_num)
for row_start_idx in range(0, rows_num, step):
if row_start_idx + row < rows_num and col < cols_num:
C[row_start_idx + row, col] += A[row_start_idx + row, tid] * B[tid, col]
对于尺寸为 128,256 或 256,128 的矩阵,它会崩溃,并且它会按照回溯的顺序抛出这些错误。
...
Call to cuMemcpyDtoH results in UNKNOWN_CUDA_ERROR
...
Call to cuMemFree results in UNKNOWN_CUDA_ERROR
它适用于非常大的尺寸,如 1024、2048 和 2048、1024,它适用于相同尺寸的输入,但不同尺寸的输入有时会引发上述错误。 它几乎从不抛出相同尺寸的错误,除了我刚刚注意到的 256*256,所以它应该与这些相关。
调试帮助代码:
# this is the comparison function - keep it as it is, don't change X or Y.
def matmul_comparison():
X = np.random.randn(1000, 1024)
Y = np.random.randn(1024, 1000)
def timer(f):
return min(timeit.Timer(lambda: f(X, Y)).repeat(3, 5))
# print('Python:', timer(matmul_trivial)) we will not consider this since it takes infinite time :)
#print('Numpy:', timer(np.matmul))
#print('Numba:', timer(matmul_numba))
print('CUDA:', timer(matmul_gpu))
if __name__ == '__main__':
os.environ['NUMBAPRO_NVVM'] = '/usr/local/cuda-9.0/nvvm/lib64/libnvvm.so'
os.environ['NUMBAPRO_LIBDEVICE'] = '/usr/local/cuda-9.0/nvvm/libdevice/'
matmul_comparison()
【问题讨论】:
-
使用
cuda-memcheck运行您的代码。在断言事情运行正确之前,您还应该对结果进行数字验证。在寻求调试帮助时,您还应该提供完整的代码。您的代码正在执行非法索引。代码存在几个概念问题。 -
谢谢,我添加了调试代码。我尝试了至少维度 2 的一些简单示例,例如 4*512、512*4 和 1024 线程,我在纸上做了一些计算,对我来说看起来不错,也许我很困惑。非法索引,是的,如果我错了,请纠正,但我应该在 if 语句中执行 tid
-
对于一个非常大的输入,它给了我很好的加速,比 numpy 快 3 倍,比 numba njit 快 13 倍。我不知道对于我只有一个线程块的这种问题是否会好很多。对于中小型输入,cuda.jit 提供与 numpy 相同的性能,两者都比 njit numba 好得多。您如何看待这些结果,是否符合预期,良好?
-
您显示的代码都不能验证数字的正确性。
-
在数值上它是不正确的,我不确定即使我能以某种方式修复它,因为我有 3 个迭代索引,然后我尝试以某种方式使用每个线程来计算更多一笔。我不确定这是否可能。是吗 ?我在想这个问题,我是否需要另一个内循环。
标签: cuda matrix-multiplication jit numba gpu