沿着3d numpy数组的Z向量执行卷积,然后对结果执行其他操作,但现在实现它很慢。 for循环是什么让我放慢速度,或者是卷积?我尝试重塑为1d向量并在1次传递中执行卷积(就像我在Matlab中所做的那样),没有for循环,但它没有提高性能。我的Matlab版本比我在Python中提出的任何东西快50%。代码的相关部分:
if (se < qs || ss > qe)
有没有比for循环更好的方法呢?听说过Cython,但我目前在Python方面的经验有限,我们的目标是找到最简单的解决方案。
答案 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。