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