numpy 3D数组的卷积加速循环?

时间:2015-08-15 20:20:36

标签: python arrays for-loop numpy convolution

沿着3d numpy数组的Z向量执行卷积,然后对结果执行其他操作,但现在实现它很慢。 for循环是什么让我放慢速度,或者是卷积?我尝试重塑为1d向量并在1次传递中执行卷积(就像我在Matlab中所做的那样),没有for循环,但它没有提高性能。我的Matlab版本比我在Python中提出的任何东西快50%。代码的相关部分:

if (se < qs || ss > qe)

有没有比for循环更好的方法呢?听说过Cython,但我目前在Python方面的经验有限,我们的目标是找到最简单的解决方案。

1 个答案:

答案 0 :(得分:1)

我认为您已经找到了fftconvolve函数的source code。通常,对于实际输入,它使用numpy.fft.rfftn.irfftn函数来计算N维变换。由于目标是进行多个1-D转换,您基本上可以像这样重写fftconvolve(简化):

from scipy.signal.signaltools import _next_regular

def fftconvolve_1d(in1, in2):

    outlen = in1.shape[-1] + in2.shape[-1] - 1
    n = _next_regular(outlen)

    tr1 = np.fft.rfft(in1, n)
    tr2 = np.fft.rfft(in2, n)
    out = np.fft.irfft(tr1 * tr2, n)

    return out[..., :outlen].copy()

并计算出所需的结果:

result = fftconvolve_1d(data, Gauss)

这可行,因为numpy.fft.rfft.irfft(注意名称中缺少n)转换输入数组的单个轴(默认情况下为最后一个轴)。这比我系统上的OP代码快大约40%。

通过使用不同的FFT后端可以实现进一步的加速。

首先,scipy.fftpack中的函数似乎比它们的Numpy等价物快一些。但是,Scipy变体的输出格式非常笨拙(参见docs),这使得很难进行乘法运算。

另一个可能的后端是通过pyFFTW包装器的FFTW。缺点是转型之前是一个缓慢的规划阶段&#34;并且输入必须是16字节对齐以实现最佳性能。这在pyFFTW tutorial中得到了很好的解释。结果代码可以是例如:

from scipy.signal.signaltools import _next_regular
import pyfftw
pyfftw.interfaces.cache.enable()  # Cache for the "planning"
pyfftw.interfaces.cache.set_keepalive_time(1.0)

def fftwconvolve_1d(in1, in2):

    outlen = in1.shape[-1] + in2.shape[-1] - 1
    n = _next_regular(outlen)

    tr1 = pyfftw.interfaces.numpy_fft.rfft(in1, n)
    tr2 = pyfftw.interfaces.numpy_fft.rfft(in2, n)

    sh = np.broadcast(tr1, tr2).shape
    dt = np.common_type(tr1, tr2)
    pr = pyfftw.n_byte_align_empty(sh, 16, dt)
    np.multiply(tr1, tr2, out=pr)
    out = pyfftw.interfaces.numpy_fft.irfft(pr, n)

    return out[..., :outlen].copy()

使用对齐的输入和缓存&#34;规划&#34;我看到OP的代码加速了近3倍。通过查看Numpy数组的ctypes.data属性中的内存地址来查找内存can be easily checked