使用 Cupy 的 GPU FFT 卷积

Posted

技术标签:

【中文标题】使用 Cupy 的 GPU FFT 卷积【英文标题】:GPU FFT Convolution using Cupy 【发布时间】:2020-01-06 13:38:38 【问题描述】:

我正在尝试使用 Cupy 在 GPU 上执行 FFT 卷积操作。

使用 scipy.signal.fftconvolve 的源代码,我想出了以下基于 Numpy 的函数,效果很好:

import numpy as np

def FFTConvolve(in1, in2):

    if in1.ndim == in2.ndim == 0:  # scalar inputs
        return in1 * in2
    elif not in1.ndim == in2.ndim:
        raise ValueError("Dimensions do not match.")
    elif in1.size == 0 or in2.size == 0:  # empty arrays
        return array([])

    s1 = np.asarray(in1.shape)
    s2 = np.asarray(in2.shape)

    shape = s1 + s2 - 1

    fsize = 2 ** np.ceil(np.log2(shape)).astype(int) 
    fslice = tuple([slice(0, int(sz)) for sz in shape])

    ret = np.fft.ifft(np.fft.fft(in1, fsize) * np.fft.fft(in2, fsize))[fslice].copy()

    return ret

我很天真地为 Cupy 编写了如下程序:

import cupy as cp

def FFTConvolve(in1, in2):

     if in1.ndim == in2.ndim == 0:  # scalar inputs
          return in1 * in2
     elif not in1.ndim == in2.ndim:
          raise ValueError("Dimensions do not match.")
     elif in1.size == 0 or in2.size == 0:  # empty arrays
          return array([])

     in1 = cp.asarray(in1)
     in2 = cp.asarray(in2)

     s1 = cp.asarray(in1.shape)
     s2 = cp.asarray(in2.shape)

     shape = s1 + s2 - 1

     fsize = 2 ** cp.ceil(cp.log2(shape)).astype(int) 
     fslice = tuple([slice(0, int(sz)) for sz in shape])

     ret = cp.fft.ifftn(cp.fft.fftn(in1, fsize) * cp.fft.fftn(in2, fsize))[fslice].copy()

     return ret

后者在enter code here 行上给了我以下错误:

TypeError: 'cupy.core.core.ndarray' object cannot be interpreted as an integer

cupy.fft.ftt 的 documentation 声明它接受元组作为范围,但由于某种原因将其读取为 cupy.ndarray。

有人能指点我正确的方向吗?

【问题讨论】:

“范围”是什么意思?如果您的意思是s,那么您似乎将cupy.ndarray 传递为fsize 我已按照您的建议进行了更正。 【参考方案1】:

解决方案是使用cp.asnumpy() 命令:

def FFTConvolve(in1, in2):

    if in1.ndim == in2.ndim == 0:  # scalar inputs
        return in1 * in2
    elif not in1.ndim == in2.ndim:
        raise ValueError("Dimensions do not match.")
    elif in1.size == 0 or in2.size == 0:  # empty arrays
        return array([])

    s1 = np.asarray(in1.shape)
    s2 = np.asarray(in2.shape)

    shape = s1 + s2 - 1

    fsize = 2 ** np.ceil(np.log2(shape)).astype(int) 
    fslice = tuple([slice(0, int(sz)) for sz in shape])

    ret = cp.fft.ifftn(cp.fft.fftn(in1, np.asarray(fsize)) * cp.fft.fftn(in2, np.asarray(fsize)))[fslice].copy()
    return ret

【讨论】:

您能否澄清cp.asnumpy() 与此代码一起使用的位置?我没有看到它在这里调用,并且按原样运行代码会产生以下错误:ValueError: non-scalar numpy.ndarray cannot be used for fill

以上是关于使用 Cupy 的 GPU FFT 卷积的主要内容,如果未能解决你的问题,请参考以下文章

为啥同时使用 numba.cuda 和 CuPy 从 GPU 传输数据这么慢?

只有使用 cupy 的 GPU 到 CPU 传输速度非常慢

使用 cupy 从 GPU 上的另一个矩阵创建距离矩阵

AMD GPU 上的 CuPy 导致 ImportError

用完 GPU Ram 的大型 cupy 阵列

如何指示 CuPy 在 GPU 中同时运行多个相同的作业?