我正在尝试将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()
答案 0 :(得分:2)
一些一般性评论:
cuda-memcheck
工具可以检查各种错误,即使使用numba python CUDA代码也是如此。即使您建议的大小正常工作,您的代码也会引发错误。关于您的代码,一些问题立即出现:
对于典范矩阵乘法,我通常希望从结果(C
)矩阵而不是A
矩阵中得出计算范围。如果您将自己限制在X*Xt
的情况下,那么我认为您可以使用A
。通常情况并非如此。
对我来说很明显你有索引问题。我不会尝试将它们全部整理出来,甚至不会全部识别出来,但是我已经指出了一个问题。由于您选择了网格大小,因此tid
变量的范围是0..1023,对于以下索引模式:B[tid, col]
可能是不正确的({{ 1}}等于1024)。
在我看来,您有可能将多个线程写入B
矩阵中的相同输出位置。 CUDA不会为您解决此问题。您不应该期望有多个线程写入相同的输出位置才能正常工作,除非您已采取步骤通过原子或经典的并行归约来做到这一点。我不想将这两种方法中的任何一种引入这个问题,因此我认为基本方法很麻烦。
还有其他问题。但是,由于上面的考虑3,我不想尝试修改代码,而宁愿从规范的朴素矩阵乘法开始并使用网格步幅循环。
下面是一个包含这些想法的示例:
C