【问题标题】:strange numpy fft performance奇怪的 numpy fft 性能
【发布时间】:2014-01-16 11:52:42
【问题描述】:

在测试期间,我注意到一些奇怪的事情。

我正在对很多向量进行 FFT,有时 numpy FFT 函数似乎会崩溃。

我对此进行了简要调试,发现某些向量长度触发了该行为。

顺便说一句,我一直在运行一个脚本,令我惊讶的是,它并没有崩溃,只是花了一点时间。

有没有人知道发生了什么,以及如何应对。我已经看到了许多不同的 FFT 大小,下面只是一个例子。

import numpy as np    
import time

a = np.zeros(166400)
start = time.time()
audio_fft = np.fft.fft(a,len(a))                          
print "it took %fs"%(time.time() -start)

a = np.zeros(165039)
start = time.time()
audio_fft = np.fft.fft(a,len(a))                          
print "it took %fs"%(time.time() -start)

a = np.zeros(165038)
start = time.time()
audio_fft = np.fft.fft(a,len(a))                          
print "it took %fs"%(time.time() -start)

a = np.zeros(165036)
start = time.time()
audio_fft = np.fft.fft(a,len(a))                          
print "it took %fs"%(time.time() -start)

a = np.zeros(165035)
start = time.time()
audio_fft = np.fft.fft(a,len(a))                          
print "it took %fs"%(time.time() -start)

a = np.zeros(165034)
start = time.time()
audio_fft = np.fft.fft(a,len(a))                          
print "it took %fs"%(time.time() -start)

a = np.zeros(165037)
start = time.time()
audio_fft = np.fft.fft(a,len(a))                          
print "it took %fs"%(time.time() -start)

print "done"

这个输出:

c:\Users\sol_sf\Desktop\math>fftTest.py
it took 0.029000s
it took 0.101000s
it took 0.176000s
it took 0.220000s
it took 0.671000s
it took 0.065000s
it took 369.132000s
done

c:\Users\sol_sf\Desktop\math>

【问题讨论】:

  • 根据 len(a) 的因式分解,使用了许多不同的算法。如你所知,2 的幂是最快的,所以如果你能垫,那是最好的路线。 en.wikipedia.org/wiki/… 有更多信息。

标签: python numpy fft


【解决方案1】:

分而治之的 FFT 算法,例如 Cooley-Tukey,输入长度的因子越多,效果越好。 2 的幂效果特别好,而素数(如 165037)需要交替的、较慢的实现。如果您可以将输入填充到 2 的幂长度,则可以大大加快慢速 FFT。

【讨论】:

  • 我知道 2 的幂对于 FFts 非常有用,也许我可以理解素数也很慢,但例如 480057 也很慢 - 而且它不是素数?跨度>
  • 我会接受你的回答,因为做 165037 点 FFT 有点愚蠢,最后,你可能是对的。我会做一些重叠并添加并坚持 2 的幂。
  • 虽然您的解释是正确的,但我不认为“primes 需要替代的、较慢的实现”这句话是正确的。 FFT 所做的是将大小为 N = P*Q 的 DFT 划分为大小为 P 的 DFT,大小为 Q 加上 Q 的大小为 P 的修改后的 DFT。这会递归地重复,直到找到一个素数大小的 DFT,然后直接计算。无论最终找到的素数 DFT 的大小是 2(输入是 2 的幂)、3、5 还是 165037,实现可能都是相同的。
  • @Cyrex 480057 = 3 * 165037,如果您阅读了我之前的评论,您就会明白为什么它的性能比165037 差,尽管它不是素数。
【解决方案2】:

我认为数组的幂 2 填充有时有几个缺点:

  1. 如果将数组的长度设为 2 次方,那么对于大数组而言,数据会大量丢失
  2. 如果用零填充数组,则会产生所谓的“边缘效应”

我在topic 中发现,fft 性能取决于数组大小的素数分解。如果数组长度是素数,则会导致计算时间长。所以我建议使用以下代码来减少数组长度以寻找最佳的分解。

from sympy.ntheory import factorint

FACTOR_LIMIT = 100

def bestFFTlength(n):
    while max(factorint(n)) >= FACTOR_LIMIT:
        n -= 1
    return n

a = np.zeros(166400)
audio_fft = np.fft.fft(a,bestFFTlength(len(a)))

【讨论】:

    【解决方案3】:

    解决此问题的一种简单方法(其他答案中未提及)是使用scipy.fftpack.next_fast_len 填充数组。给定一个目标长度,它会为您提供下一个长度 > 由 2、3 和 5 组合而成的目标。

    正如其他答案所指出的,当数组的长度是素数时,FFT 的性能最差。它的效率随着质因子数量的增加(2、3、5 等)而增加。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-24
      • 1970-01-01
      • 2011-05-11
      • 1970-01-01
      • 1970-01-01
      • 2017-06-07
      相关资源
      最近更新 更多