提高 Python 中的 FFT 性能
Posted
技术标签:
【中文标题】提高 Python 中的 FFT 性能【英文标题】:Improving FFT performance in Python 【发布时间】:2011-09-15 23:24:45 【问题描述】:Python 中最快的 FFT 实现是什么?
似乎 numpy.fft 和 scipy.fftpack 都基于 fftpack,而不是 FFTW。 fftpack 和 FFTW 一样快吗?使用多线程 FFT 或分布式 (MPI) FFT 怎么样?
【问题讨论】:
【参考方案1】:您当然可以使用 Cython 或其他允许您访问外部库的类似工具来封装您想要测试的任何 FFT 实现。
基于 GPU
如果您要测试 FFT 实现,您还可以查看基于 GPU 的代码(如果您可以使用适当的硬件)。有几个:reikna.fft、scikits.cuda。
基于 CPU 的
还有一个基于 CPU 的 python FFTW 包装器pyFFTW。
(也有pyFFTW3,但它不像pyFFTW那样积极维护,并且它不适用于Python3。(source))
我对这些都没有经验。如果速度对您很重要,那么您可能需要为您的特定应用程序进行一些挖掘和基准测试。
【讨论】:
这个答案有点陈旧,但在 Google 上排名很高。 My FFTW 包装器比 pyFFTW3 得到更积极的维护,我喜欢认为它们提供的功能更加完整。【参考方案2】:对于https://gist.github.com/fnielsen/99b981b9da34ae3d5035 上详述的测试,我发现 scipy.fftpack 与我通过pyfftw.interfaces.scipy_fftpack
对 pyfftw 的简单应用相比表现良好,除了长度对应于质数的数据。
第一次调用 pyfftw.interfaces.scipy_fftpack.fft 似乎需要一些设置成本。第二次更快。 Numpy 和 scipy 的带有质数的 fftpack 对于我尝试的数据大小来说表现非常糟糕。在这种情况下,CZT 更快。几个月前在 Scipy 的 Github 上提出了一个关于该问题的问题,请参阅 https://github.com/scipy/scipy/issues/4288
20000 prime=False
padded_fft : 0.003116
numpy_fft : 0.003502
scipy_fft : 0.001538
czt : 0.035041
fftw_fft : 0.004007
------------------------------------------------------------
20011 prime=True
padded_fft : 0.001070
numpy_fft : 1.263672
scipy_fft : 0.875641
czt : 0.033139
fftw_fft : 0.009980
------------------------------------------------------------
21803 prime=True
padded_fft : 0.001076
numpy_fft : 1.510341
scipy_fft : 1.043572
czt : 0.035129
fftw_fft : 0.011463
------------------------------------------------------------
21804 prime=False
padded_fft : 0.001108
numpy_fft : 0.004672
scipy_fft : 0.001620
czt : 0.033854
fftw_fft : 0.005075
------------------------------------------------------------
21997 prime=True
padded_fft : 0.000940
numpy_fft : 1.534876
scipy_fft : 1.058001
czt : 0.034321
fftw_fft : 0.012839
------------------------------------------------------------
32768 prime=False
padded_fft : 0.001222
numpy_fft : 0.002410
scipy_fft : 0.000925
czt : 0.039275
fftw_fft : 0.005714
------------------------------------------------------------
【讨论】:
【参考方案3】:pyFFTW3 包不如 pyFFTW 库,至少在实现方面是这样。由于它们都包装了 FFTW3 库,我猜速度应该是一样的。
https://pypi.python.org/pypi/pyFFTW
【讨论】:
【参考方案4】:FFTW3 似乎是包装精美的最快实现。第一个答案中的 PyFFTW 绑定有效。下面是一些比较执行时间的代码:test_ffts.py
【讨论】:
【参考方案5】:FFTW site 显示 fftpack 的运行速度大约是 FFTW 的 1/3,但这是通过机械翻译的 Fortran 到 C 步骤,然后是 C 编译,我不知道 numpy/scipy 是否使用更直接的Fortran 编译。如果性能对您很重要,您可以考虑将 FFTW 编译成 DLL/共享库并使用 ctypes 访问它,或者构建自定义 C 扩展。
【讨论】:
【参考方案6】:在我工作的地方,一些研究人员编译了这个 Fortran 库,它针对特定问题设置和调用 FFTW。这个 Fortran 库(带有一些子例程的模块)需要来自我的 Python 程序的一些输入数据(二维列表)。
我所做的是为包装 Fortran 库的 Python 创建一个小的 C 扩展,我在其中基本上调用“init”来设置 FFTW 规划器,并使用另一个函数来提供我的 2D 列表(数组)和一个“计算"函数。
创建 C 扩展是一项小任务,针对该特定任务有很多很好的教程。
这种方法的好处是我们得到了速度......很多速度。唯一的缺点是在 C 扩展中,我们必须遍历 Python 列表,并将所有 Python 数据提取到内存缓冲区中。
【讨论】:
使用Cython,可以直接访问内存中的数据,无需复制。以上是关于提高 Python 中的 FFT 性能的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Swift 中的 FFT 与 Python 中的不同?