Python numpy fftn对于多幅图像的2d fft非常低效

Python numpy fftn对于多幅图像的2d fft非常低效,python,numpy,profiling,fft,Python,Numpy,Profiling,Fft,我想计算几个图像的傅里叶变换。 因此,我对numpy的fft.fftn进行了基准测试,以对抗循环的暴力 这是我用来对这两种方法进行基准测试的代码(在jupyter笔记本中): 将numpy导入为np x=np.random.rand(32,256,256) def迭代fft(arr): k=np.empty_like(arr,dtype=np.complex64) 对于i,枚举中的a(arr): k[i]=np.fft.fft2(a) 返回k k_it=迭代_fft(x) k_np=np.fft

我想计算几个图像的傅里叶变换。 因此,我对
numpy
fft.fftn
进行了基准测试,以对抗循环的暴力

这是我用来对这两种方法进行基准测试的代码(在jupyter笔记本中):

将numpy导入为np
x=np.random.rand(32,256,256)
def迭代fft(arr):
k=np.empty_like(arr,dtype=np.complex64)
对于i,枚举中的a(arr):
k[i]=np.fft.fft2(a)
返回k
k_it=迭代_fft(x)
k_np=np.fft.fftn(x,轴=(1,2))
np.testing.assert\u allclose(k_it.real,k_np.real)
np.testing.assert\u allclose(k_it.imag,k_np.imag)
%%timeit
k_it=迭代_fft(x)
输出:
63.6 ms±1.23 ms/循环(平均±标准偏差为7次运行,每个循环10次)

%%timeit
k_np=np.fft.fftn(x,轴=(1,2))
输出:
122 ms±1.79 ms/循环(7次运行的平均值±标准偏差,每个循环10次)


为什么会有如此巨大的差异?

numpy中的这些例程目前似乎假设最后一个维度总是最小的。如果这是真的,
fftn
会更快,有时会快很多

也就是说,这两种方法在性能上的差异要比您(使用Python 3.7.4和numpy 1.17.2)小得多。例如,
iterate\u fft
需要46毫秒,而
ffn
需要50毫秒。但是如果我将轴翻转到
(256,256,32)
,我分别得到55毫秒和40毫秒。用
(256,256,2)
的形状推得更远,我分别得到21ms和4ms

注意,如果性能确实是一个问题,那么在某些情况下,还有其他FFT库可用。此外,scipy中的完整fftpack与numpy中更有限的代码具有非常不同的性能

请注意,基本上:

x = np.random.rand(32, 256, 256)

a = np.fft.fft(x, n=256, axis=2)
a = np.fft.fft(a, n=256, axis=1)

np.testing.assert_allclose(np.fft.fftn(x, axes=(1, 2)), a)

因此,一位参与
numpy
fft开发的人员在GitHub上提出了一个深层次的问题,结果表明,速度放缓最有可能来自
pocketft
使用的多维数组重新排列


numpy
切换到
scipy
1.4实现时,它将成为一个内存,可以使用我的基准显示它没有这些缺点。

感谢您的回答。我的
numpy
版本是1.16.4(这不是一个很强的要求,我会改变以了解会发生什么),而我的Python版本是3.6.8(我希望保持这样)。我不完全确定我是否理解你在阅读文件时的第一点,你能提供更多细节吗?另外,我对批量为2的结果感到惊讶。批量大小为1时会发生什么情况?似乎
fftn
在性能FFT2时比
FFT2
更快。感谢您推荐其他库,性能对我来说并不是一个真正的问题,我只是感到惊讶。numpy 1.17似乎引入了的使用,这稍微改变了性能。请注意,我的形状更改只是演示了当前代码似乎优化的情况,它所做的与您想要做的不同。考虑到当前的优化,在图像上迭代似乎更适合您的用例。我刚刚用numpy 1.17尝试过这些优化,在首先使用批处理维度进行迭代时也更好。最后,我将尝试使用批次维度进行配置,尤其是批次大小为1的情况。是的,我完全理解你在做什么,我只是不明白是什么特别的优化使得它在小批量的最后一种情况下工作得更好。因此,当批量维度是最后一个维度时,我也有
fftn
以小幅度击败迭代版本。然而,当批大小为2时,无论批维度在哪里(最后一个或第一个),结果都是相同的,如下所示:迭代2.9ms,
fftn
2.5ms。所以利润率远没有你的大。我将上传一个要点来说明这一点。当批量大小为1时,我想我们要支付for循环的成本,因为它是2.2ms vs 1.2ms。另外,我在文档中注意到:>fft2只是fftn,轴的默认值不同。这是我使用的代码(您可以看到批量大小为1的结果,但它很容易适应2或32)。无论如何,我认为这可能显示了
fftn
中的一些低效,对吗?我在
numpy
中打开了一个GitHub,以了解他们对此的看法。