我尝试了以下用户在Stackoverflow上提出的解决方案:henry-gomersall以重复执行以加快基于FFT的卷积的速度,但是获得了不同的结果。
import numpy as np
import pyfftw
import scipy.signal
import timeit
class CustomFFTConvolution(object):
def __init__(self, A, B, threads=1):
shape = (np.array(A.shape) + np.array(B.shape))-1
if np.iscomplexobj(A) and np.iscomplexobj(B):
self.fft_A_obj = pyfftw.builders.fftn(
A, s=shape, threads=threads)
self.fft_B_obj = pyfftw.builders.fftn(
B, s=shape, threads=threads)
self.ifft_obj = pyfftw.builders.ifftn(
self.fft_A_obj.get_output_array(), s=shape,
threads=threads)
else:
self.fft_A_obj = pyfftw.builders.rfftn(
A, s=shape, threads=threads)
self.fft_B_obj = pyfftw.builders.rfftn(
B, s=shape, threads=threads)
self.ifft_obj = pyfftw.builders.irfftn(
self.fft_A_obj.get_output_array(), s=shape,
threads=threads)
def __call__(self, A, B):
fft_padded_A = self.fft_A_obj(A)
fft_padded_B = self.fft_B_obj(B)
return self.ifft_obj(fft_padded_A * fft_padded_B)
N = 200
A = np.random.rand(N, N, N)
B = np.random.rand(N, N, N)
start_time = timeit.default_timer()
C = scipy.signal.fftconvolve(A,B,"same")
print timeit.default_timer() - start_time
custom_fft_conv_nthreads = CustomFFTConvolution(A, B, threads=1)
C = custom_fft_conv_nthreads(A, B)
print timeit.default_timer() - start_time
PyFFTW约为比SciPy FFT慢7倍,这与其他用户的体验不同。该代码有什么问题? Python 2.7.9,PyFFTW 0.9.2。
最佳答案
您没有在做自己认为正在做的事情,而在您认为自己正在做的事情上,您也不应这样做。
您没有做您想做的事,因为上面的代码只定义了start_time
一次(因此,对pyfftw的测试不仅包括耗时的创建CustomFFTConvolution
对象,而且还包括scipy卷积!)。
您不应该做自己认为正在做的事情,因为您应该使用timeit
测试这种事情。
因此,使用某些文件foo.py
:
import numpy as np
import pyfftw
import scipy.signal
class CustomFFTConvolution(object):
def __init__(self, A, B, threads=1):
shape = (np.array(A.shape) + np.array(B.shape))-1
if np.iscomplexobj(A) and np.iscomplexobj(B):
self.fft_A_obj = pyfftw.builders.fftn(
A, s=shape, threads=threads)
self.fft_B_obj = pyfftw.builders.fftn(
B, s=shape, threads=threads)
self.ifft_obj = pyfftw.builders.ifftn(
self.fft_A_obj.get_output_array(), s=shape,
threads=threads)
else:
self.fft_A_obj = pyfftw.builders.rfftn(
A, s=shape, threads=threads)
self.fft_B_obj = pyfftw.builders.rfftn(
B, s=shape, threads=threads)
self.ifft_obj = pyfftw.builders.irfftn(
self.fft_A_obj.get_output_array(), s=shape,
threads=threads)
def __call__(self, A, B):
fft_padded_A = self.fft_A_obj(A)
fft_padded_B = self.fft_B_obj(B)
return self.ifft_obj(fft_padded_A * fft_padded_B)
N = 200
A = np.random.rand(N, N, N)
B = np.random.rand(N, N, N)
在ipython中,您可以获得以下内容:
In [1]: %run foo.py
In [2]: timeit scipy.signal.fftconvolve(A,B,"same")
1 loops, best of 3: 8.38 s per loop
In [3]: custom_fft_conv_nthreads = CustomFFTConvolution(A, B, threads=1)
In [4]: timeit custom_fft_conv_nthreads(A, B)
1 loops, best of 3: 6.9 s per loop
并具有多个线程:
In [5]: custom_fft_conv_nthreads = CustomFFTConvolution(A, B, threads=4)
In [6]: timeit custom_fft_conv_nthreads(A, B)
1 loops, best of 3: 3.81 s per loop
如果通过在
start_time = timeit.default_timer()
之前插入C = custom_fft_conv_nthreads(A, B)
来更正代码以完成您认为的工作,您将获得更接近预期的结果:10.8795630932
8.31241607666