Parallel processing Python中子数组的快速求和

Parallel processing Python中子数组的快速求和,parallel-processing,gpu,numba,Parallel Processing,Gpu,Numba,我有一个半径为w的数据立方体a,对于该立方体的每个元素,我想在半径为r的立方体中添加元素和所有周围的值,其中r=r: x1=x-r 其他: x1=0 如果x=r: y1=y-r 其他: y1=0 如果y=r: z1=z-r 其他: z1=0 如果z

我有一个半径为w的数据立方体a,对于该立方体的每个元素,我想在半径为r的立方体中添加元素和所有周围的值,其中r 作为一个简单的例子,假设:

a = numpy.ones(shape=(2*w,2*w,2*w),dtype='float32')
kernel = numpy.ones(shape=(2*r,2*r,2*r),dtype='float32')
b = convolve(a,kernel,mode='constant',cval=0)
那么b的值(2r)(2r)(2r)对于所有不在边上的索引

目前我正在使用一个循环来完成这项工作,它非常慢,特别是对于较大的w和r。我尝试了scipy卷积,但在循环中几乎没有加速。我现在正在研究numba的并行计算特性,但无法找出如何重写代码以使用numba。我有一个Nvidia RTX卡,所以CUDA GPU计算也是可能的

欢迎提出建议

这是我目前的代码:

for x in range(0,w*2):
    print(x)
    for y in range(0,w*2):
        for z in range(0,w*2):
            if x >= r:
                x1 = x - r
            else:
                x1 = 0
            if x < w*2-r:
                x2 = x + r
            else:
                x2 = w*2 - 1
            
            if y >= r:
                y1 = y - r
            else:
                y1 = 0
            if y < w*2-r:
                y2 = y + r
            else:
                y2 = w*2 - 1

            if z >= r:
                z1 = z - r
            else:
                z1 = 0
            if z < w*2-r:
                z2 = z + r
            else:
                z2 = w*2 - 1

            b[x][y][z] = numpy.sum(a[x1:x2,y1:y2,z1:z2])

return b
范围(0,w*2)内x的
:
打印(x)
对于范围(0,w*2)内的y:
对于范围(0,w*2)内的z:
如果x>=r:
x1=x-r
其他:
x1=0
如果x=r:
y1=y-r
其他:
y1=0
如果y=r:
z1=z-r
其他:
z1=0
如果z
这是一个非常简单的代码版本,可以与numba一起使用。我发现相对于纯numpy代码,速度提高了10倍。但是,使用FFT卷积算法(例如scipy的fftconvolve)应该能够获得更大的速度提升。你能分享一下你让卷积开始工作的尝试吗

from numba import njit

@njit
def sum_cubes(a,b,w,r):
    for x in range(0,w*2):
        #print(x)
        for y in range(0,w*2):
            for z in range(0,w*2):
                if x >= r:
                    x1 = x - r
                else:
                    x1 = 0
                if x < w*2-r:
                    x2 = x + r
                else:
                    x2 = w*2 - 1

                if y >= r:
                    y1 = y - r
                else:
                    y1 = 0
                if y < w*2-r:
                    y2 = y + r
                else:
                    y2 = w*2 - 1

                if z >= r:
                    z1 = z - r
                else:
                    z1 = 0
                if z < w*2-r:
                    z2 = z + r
                else:
                    z2 = w*2 - 1

                b[x,y,z] = np.sum(a[x1:x2,y1:y2,z1:z2])
    return b
除非你想让立方体偏离中心

假设您确实希望立方体居中,则执行此计算的更快方法是使用scipy的统一过滤器:

from scipy.ndimage import uniform_filter
def sum_cubes_quickly(a,b,w,r):
    b = uniform_filter(a,mode='constant',cval=0,size=2*r+1)*(2*r+1)**3
    return b
对于w=50,r=10的随机生成数据,进行一些快速运行时比较:

  • 原始numpy代码-15.1秒
  • Numba'd numpy代码-8.1秒
  • 均匀滤光片-13.1毫秒

    • 这是一个非常简单的代码版本,可以与numba一起使用。我发现相对于纯numpy代码,速度提高了10倍。但是,使用FFT卷积算法(例如scipy的fftconvolve)应该能够获得更大的速度提升。你能分享一下你让卷积开始工作的尝试吗

      from numba import njit
      
      @njit
      def sum_cubes(a,b,w,r):
          for x in range(0,w*2):
              #print(x)
              for y in range(0,w*2):
                  for z in range(0,w*2):
                      if x >= r:
                          x1 = x - r
                      else:
                          x1 = 0
                      if x < w*2-r:
                          x2 = x + r
                      else:
                          x2 = w*2 - 1
      
                      if y >= r:
                          y1 = y - r
                      else:
                          y1 = 0
                      if y < w*2-r:
                          y2 = y + r
                      else:
                          y2 = w*2 - 1
      
                      if z >= r:
                          z1 = z - r
                      else:
                          z1 = 0
                      if z < w*2-r:
                          z2 = z + r
                      else:
                          z2 = w*2 - 1
      
                      b[x,y,z] = np.sum(a[x1:x2,y1:y2,z1:z2])
          return b
      
      除非你想让立方体偏离中心

      假设您确实希望立方体居中,则执行此计算的更快方法是使用scipy的统一过滤器:

      from scipy.ndimage import uniform_filter
      def sum_cubes_quickly(a,b,w,r):
          b = uniform_filter(a,mode='constant',cval=0,size=2*r+1)*(2*r+1)**3
          return b
      
      对于w=50,r=10的随机生成数据,进行一些快速运行时比较:

      • 原始numpy代码-15.1秒
      • Numba'd numpy代码-8.1秒
      • 均匀滤光片-13.1毫秒

      好的,谢谢。我没有发现njit有任何明显的加速,但可能是因为打印不起作用,所以它似乎挂起了。也许打印是问题所在?对于scipy,我尝试了以下方法:kernel=numpy.ones(shape=(2*r,2*r,2*r),dtype='float32')b=convolve(a,kernel,mode='constant',cval=0)这有意义吗?我将研究fftconvolve。我添加了一个带有scipy.ndimage.filters.convolve的示例,我相信它相当于我的三个嵌套循环。不幸的是,它似乎并没有更快。这是令人惊讶的,因为scipy.ndimage.filters.gaussian_filter非常快,而且做的事情更复杂。是的,均匀_filter解决了这个问题!它把我最小的计算时间从3小时减少到14秒,或者说是750倍的速度!我现在可以解决更大的问题了。好的,谢谢。我没有发现njit有任何明显的加速,但可能是因为打印不起作用,所以它似乎挂起了。也许打印是问题所在?对于scipy,我尝试了以下方法:kernel=numpy.ones(shape=(2*r,2*r,2*r),dtype='float32')b=convolve(a,kernel,mode='constant',cval=0)这有意义吗?我将研究fftconvolve。我添加了一个带有scipy.ndimage.filters.convolve的示例,我相信它相当于我的三个嵌套循环。不幸的是,它似乎并没有更快。这是令人惊讶的,因为scipy.ndimage.filters.gaussian_filter非常快,而且做的事情更复杂。是的,均匀_filter解决了这个问题!它把我最小的计算时间从3小时减少到14秒,或者说是750倍的速度!我现在可以解决更大的问题了。