对于我的工作,我需要在大图像上执行离散傅里叶变换(DFT)。在当前示例中,我需要用于1921 x 512 x 512图像的3D FT(以及512 x 512图像的2D FFT)。现在,我正在使用numpy包和相关函数np.fft.fftn()。下面的代码片段以下列方式示例性地显示了相同尺寸/略小的2D / 3D随机数生成网格上的2D和3D FFT时间:
import sys
import numpy as np
import time
tas = time.time()
a = np.random.rand(512, 512)
tab = time.time()
b = np.random.rand(100, 512, 512)
tbfa = time.time()
fa = np.fft.fft2(a)
tfafb = time.time()
fb = np.fft.fftn(b)
tfbe = time.time()
print "initializing 512 x 512 grid:", tab - tas
print "initializing 100 x 512 x 512 grid:", tbfa - tab
print "2D FFT on 512 x 512 grid:", tfafb - tbfa
print "3D FFT on 100 x 512 x 512 grid:", tfbe - tfafb
输出:
initializing 512 x 512 grid: 0.00305700302124
initializing 100 x 512 x 512 grid: 0.301637887955
2D FFT on 512 x 512 grid: 0.0122730731964
3D FFT on 100 x 512 x 512 grid: 3.88418793678
我遇到的问题是我经常需要这个过程,所以每张图像花费的时间应该很短。在我自己的计算机上测试时(中段笔记本电脑,分配给虚拟机的2GB RAM( - >因此更小的测试网格)),你可以看到3D FFT需要~5 s(数量级)。现在,在工作中,机器更好,集群/网格架构系统和FFT更快。在这两种情况下,2D瞬间完成。
然而,对于1921x512x512,np.fft.fftn()需要约5分钟。因为我猜scipy的实现并不快得多,并且考虑到在相同大小的网格上MATLAB的FFT在~5秒内完成,我的问题是是否有一种方法可以将过程加速到或几乎达到MATLAB时间。我对FFT的了解有限,但显然MATLAB使用的是FFTW算法,而python则没有。有一些合理的机会,有一些pyFFTW包我得到相似的时间?此外,1921年似乎是一个不吉利的选择,只有2个素数因子(17,113),所以我认为这也起了作用。另一方面,512是非常适合的2的幂。如果可能的话,是否可以实现类似MATLAB的时间,而不用零填充到2048?
我在问,因为我必须经常使用FFT(对于这种差异影响巨大的数量!),如果没有可能减少python中的计算时间,我必须切换到其他更快的实现。
答案 0 :(得分:2)
是的,与pyfftw
或numpy.fft
相比,通过接口scipy.fftpack
使用FFTW可能会缩短您的计算时间。这些DFT算法实现的性能可以在this one等基准测试中进行比较:Improving FFT performance in Python中报告了一些有趣的结果
我建议使用以下代码进行测试:
import pyfftw
import numpy
import time
import scipy
f = pyfftw.n_byte_align_empty((127,512,512),16, dtype='complex128')
#f = pyfftw.empty_aligned((33,128,128), dtype='complex128', n=16)
f[:] = numpy.random.randn(*f.shape)
# first call requires more time for plan creation
# by default, pyfftw use FFTW_MEASURE for the plan creation, which means that many 3D dft are computed so as to choose the fastest algorithm.
fftf=pyfftw.interfaces.numpy_fft.fftn(f)
#help(pyfftw.interfaces)
tas = time.time()
fftf=pyfftw.interfaces.numpy_fft.fftn(f) # here the plan is applied, nothing else.
tas = time.time()-tas
print "3D FFT, pyfftw:", tas
f = pyfftw.n_byte_align_empty((127,512,512),16, dtype='complex128')
#f = pyfftw.empty_aligned((33,128,128), dtype='complex128', n=16)
f[:] = numpy.random.randn(*f.shape)
tas = time.time()
fftf=numpy.fft.fftn(f)
tas = time.time()-tas
print "3D FFT, numpy:", tas
tas = time.time()
fftf=scipy.fftpack.fftn(f)
tas = time.time()-tas
print "3D FFT, scipy/fftpack:", tas
# first call requires more time for plan creation
# by default, pyfftw use FFTW_MEASURE for the plan creation, which means that many 3D dft are computed so as to choose the fastest algorithm.
f = pyfftw.n_byte_align_empty((128,512,512),16, dtype='complex128')
fftf=pyfftw.interfaces.numpy_fft.fftn(f)
tas = time.time()
fftf=pyfftw.interfaces.numpy_fft.fftn(f) # here the plan is applied, nothing else.
tas = time.time()-tas
print "3D padded FFT, pyfftw:", tas
对于127 * 512 * 512的大小,在我的小型计算机上,我得到了:
3D FFT, pyfftw: 3.94130897522
3D FFT, numpy: 16.0487070084
3D FFT, scipy/fftpack: 19.001199007
3D padded FFT, pyfftw: 2.55221295357
因此pyfftw
明显快于numpy.fft
和scipy.fftpack
。使用填充更快,但计算的东西是不同的。
最后,pyfftw
在第一次运行时可能看起来较慢,因为它根据documentation使用了标记FFTW_MEASURE
。当且仅当连续计算了许多相同大小的DFT时,这是一件好事。
答案 1 :(得分:0)
您可以尝试从英特尔MKL(数学内核库)进行FFT,该速度比FFTW高faster。 英特尔为Python提供了mkl-fft,它取代了numpy.fft。您需要做的就是键入:
pip install mkl-fft
,然后再次运行程序,无需进行任何更改。
另外,numpy 1.17(即将发布)将具有FFT的新实现:
Pocketfft库替换了基于fftpack的FFT模块
两个实现都具有相同的祖先(Paul的Fortran77 FFTPACK N. Swarztrauber),但pocketfft包含其他修改 在某些情况下可以提高准确性和性能。对于 FFT长度包含较大的素因数,pocketfft使用Bluestein的 算法,它维持O(N log N)的运行时复杂度,而不是 素数长度朝O(N * N)方向恶化。另外,对于 具有接近素数长度的实值FFT已得到改进,并且可以与之媲美 带有复数值FFT。