Python PyFFTW比SciPy FFT慢?

Python PyFFTW比SciPy FFT慢?,python,scipy,pyfftw,Python,Scipy,Pyfftw,我尝试了用户在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) +

我尝试了用户在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\u 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
如果通过在
C=custom\u fft\u conv\u nthreads(A,B)
之前插入
start\u time=timeit.default\u timer()
来纠正代码,使之符合您的预期:

10.8795630932
8.31241607666

我知道我在做什么。我从timeit.default\u timer()返回的时间中减去了scipy.signal.fftconvolve使用的时间,然后我估计“PyFFTW大约慢7倍”以重现您的评论,我在自定义fft转换之前添加了开始时间。我在循环中测试代码:第一次运行:6.0643529892(Scipy fft卷积)35.0755908489(PyFFTW),第二次和第二次分别是6.10961890221(Scipy fft卷积)5.85012698174(PyFFTW)(所以稍微快一点)。不幸的是,在我的程序中,我使用更大的内核进行了一系列的卷积,因此我无法使用PyFFTW加速。您编写的代码在计算PyFFTW结果时包含了从
fftconvolve
开始的时间。你需要重新初始化它。第二,你无论如何都不应该这样做——这就是时间的意义所在。FFTW的工作原理是尝试各种选项,然后以最快的速度工作——这就是在对象创建阶段所花费的时间。可以使用花费较少时间的标志,我建议您阅读文档。几乎可以肯定的是,您可以使用单个大小(或少量大小)进行卷积,因此您不需要计划每个循环。感谢您的建议@HenryGomersall。我实际上所做的是:
对于范围(N)内的uu:fftconvolve((10001000100),kernel u N)
,其中kernel是(11,11,11);(13,13,13); 等等内核在每次循环运行时都会增长。为了获得线性卷积,plan必须改变其每个循环的大小。所以,总而言之,我不知道如何使用(如果可能的话)以前的卷积计划。哦,在这种情况下很容易。在进行FFT卷积时,必须有一对大小相同(完整)的中间数组
pyfftw
通过使用将数据插入数组正确部分的包装器类来处理此问题(由
shape
参数指定)。您可以手动执行此操作—只需为输出数组的大小创建一个FFTW对象,然后根据需要从不断增长的内核中填充它。如果内核一直在增长,您甚至不需要将前一个内核归零。这是一个简单的复制和运行。