编程语言
首页 > 编程语言> > python – Pycuda Blocks和Grids可以处理大数据

python – Pycuda Blocks和Grids可以处理大数据

作者:互联网

我需要帮助才能知道我的块和网格的大小.
我正在构建一个python应用程序来执行基于scipy的度量计算:Euclidean distance,Manhattan,Pearson,Cosine,加入其他.

该项目是PycudaDistances(https://github.com/vinigracindo/pycudaDistances).

它似乎与小数组一起工作得很好.当我进行更详尽的测试时,不幸的是它没有用.我下载了movielens set(http://www.grouplens.org/node/73).

使用Movielens 100k,我声明了一个有形状的数组(943,1682).也就是说,用户评价了943和1682部电影.不是分类器用户的电影我将值配置为0.

使用更大的阵列算法不再有效.我遇到以下错误:pycuda._driver.LogicError:cuFuncSetBlockShape失败:值无效.

研究这个错误,我找到了一个解释,告诉安德鲁支持512个线程加入并使用更大的块,有必要使用块和网格.

我想要一个帮助,使算法欧几里德距离数组适应从小型到巨型阵列的工作.

def euclidean_distances(X, Y=None, inverse=True):
    X, Y = check_pairwise_arrays(X,Y)
    rows = X.shape[0]
    cols = Y.shape[0]
    solution = numpy.zeros((rows, cols))
    solution = solution.astype(numpy.float32)

    kernel_code_template = """
    #include <math.h>

    __global__ void euclidean(float *x, float *y, float *solution) {

        int idx = threadIdx.x + blockDim.x * blockIdx.x;
        int idy = threadIdx.y + blockDim.y * blockIdx.y;

        float result = 0.0;

        for(int iter = 0; iter < %(NDIM)s; iter++) {

            float x_e = x[%(NDIM)s * idy + iter];
            float y_e = y[%(NDIM)s * idx + iter];
            result += pow((x_e - y_e), 2);
        }
        int pos = idx + %(NCOLS)s * idy;
        solution[pos] = sqrt(result);
    }
    """
    kernel_code = kernel_code_template % {
        'NCOLS': cols,
        'NDIM': X.shape[1]
    }

    mod = SourceModule(kernel_code)

    func = mod.get_function("euclidean")
    func(drv.In(X), drv.In(Y), drv.Out(solution), block=(cols, rows, 1))

    return numpy.divide(1.0, (1.0 + solution)) if inverse else solution

有关详细信息,请参阅:https://github.com/vinigracindo/pycudaDistances/blob/master/distances.py

我感谢任何帮助.
非常感谢你.

解决方法:

要为内核调整执行参数的大小,您需要做两件事(按此顺序):

1.确定块大小

您的块大小主要取决于硬件限制和性能.我建议阅读this answer以获取更多详细信息,但非常简短的总结是您的GPU对每个块可以运行的线程总数有限制,并且它具有有限的寄存器文件,共享和本地内存大小.您选择的块尺寸必须在这些限制范围内,否则内核将无法运行.块大小也会影响内核的性能,您会发现块大小可以提供最佳性能.块大小应始终为warp大小的四倍,在迄今为止发布的所有CUDA兼容硬件上为32.

2.确定网格大小

对于您显示的内核类型,您需要的块数与输入数据量和每个块的尺寸直接相关.

例如,如果您的输入数组大小为943×1682,并且块大小为16×16,则需要59 x 106网格,这将在内核启动时产生944×1696个线程.在这种情况下,输入数据大小不是块大小的倍数,您需要修改内核以确保它不读取越界.一种方法可能是这样的:

__global__ void euclidean(float *x, float *y, float *solution) {
    int idx = threadIdx.x + blockDim.x * blockIdx.x;
    int idy = threadIdx.y + blockDim.y * blockIdx.y;

     if ( ( idx < %(NCOLS)s ) && ( idy < %(NDIM)s ) ) {

        .....
     }
}

启动内核的python代码可能类似于:

bdim = (16, 16, 1)
dx, mx = divmod(cols, bdim[0])
dy, my = divmod(rows, bdim[1])

gdim = ( (dx + (mx>0)) * bdim[0], (dy + (my>0)) * bdim[1]) )
func(drv.In(X), drv.In(Y), drv.Out(solution), block=bdim, grid=gdim)

This question and answer也可能有助于了解此过程的工作原理.

请注意,上述所有代码都是在浏览器中编写的,从未经过测试.需要您自担风险使用它.

另请注意,它基于对代码的简要读取,可能不正确,因为您还没有真正描述过如何在您的问题中调用代码.

标签:python,gpu,cuda,pycuda,euclidean-distance
来源: https://codeday.me/bug/20190713/1450435.html