Numba矩阵向量乘法

时间:2014-01-29 22:34:28

标签: python numpy cuda numba numba-pro

我正在尝试使用numbapro在下面编写一个简单的矩阵向量乘法:

from numbapro import cuda
from numba import *
import numpy as np
import math
from timeit import default_timer as time

n = 100

@cuda.jit('void(float32[:,:], float32[:], float32[:])')
def cu_matrix_vector(A, b, c):
    y, x = cuda.grid(2)
    if y < n:
        c[y] = 0.0

    if x < n and y < n:
        for i in range(n):
            c[y] += A[y, i] * b[i]


A = np.array(np.random.random((n, n)), dtype=np.float32)
B = np.array(np.random.random((n, 1)), dtype=np.float32)
C = np.empty_like(B)

s = time()
dA = cuda.to_device(A)
dB = cuda.to_device(B)
dC = cuda.to_device(C)
cu_matrix_vector(dA, dB, dC)
dC.to_host()

e = time()
tcuda = e - s

但我收到了以下错误:

  

numbapro.cudadrv.error.CudaDriverError:CUDA_ERROR_LAUNCH_FAILED无法复制内存D-&gt; H

我不明白为什么托管副本的设备失败了。请帮忙

1 个答案:

答案 0 :(得分:6)

您的代码存在多个问题。

  1. B和C向量是Nx1 2D矩阵,而不是1D向量,但是内核的类型签名将它们列为“float32 [:]” - 1D向量。它还使用单个索引对它们编制索引,由于访问不对齐而导致GPU上的运行时错误(cuda-memcheck是您的朋友!)
  2. 你的内核假设一个二维网格,但只使用它的一列 - 意味着许多线程进行相同的计算并相互覆盖。
  3. 没有给出执行配置,因此NumbaPro正在启动一个包含1个1个线程的内核。 (nvprof是你的朋友!)
  4. 这是一个有效的代码。请注意,这使用1D网格的1D网格,并在矩阵的列上循环。因此,它针对向量/矩阵中的行数较大的情况进行了优化。针对短矩阵和宽矩阵进行优化的内核需要使用另一种方法(并行缩减)。但我会使用CUBLAS sgemv(也在NumbaPro中公开)。

    from numbapro import cuda
    from numba import *
    import numpy as np
    import math
    from timeit import default_timer as time
    
    m = 100000 
    n = 100
    
    @cuda.jit('void(f4[:,:], f4[:], f4[:])')
    def cu_matrix_vector(A, b, c):
        row = cuda.grid(1)
        if (row < m):
            sum = 0
    
            for i in range(n):
                sum += A[row, i] * b[i]
    
            c[row] = sum
    
    A = np.array(np.random.random((m, n)), dtype=np.float32)
    B = np.array(np.random.random(m), dtype=np.float32)
    C = np.empty_like(B)
    
    s = time()
    dA = cuda.to_device(A)
    dB = cuda.to_device(B)
    dC = cuda.to_device(C)
    
    cu_matrix_vector[(m+511)/512, 512](dA, dB, dC)
    
    dC.to_host()
    
    print C
    
    e = time()
    tcuda = e - s