📜  如何在Python使用快速傅立叶变换(FFT)执行更快的卷积?

📅  最后修改于: 2022-05-13 01:54:33.956000             🧑  作者: Mango

如何在Python使用快速傅立叶变换(FFT)执行更快的卷积?

卷积是信号处理中最重要的数学运算之一。这个简单的数学运算出现在许多科学和工业应用中,从它在十亿层大型 CNN 中的使用到简单的图像去噪。卷积本质上既可以是模拟的,也可以是离散的,但是由于现代计算机的数字性质,离散卷积是我们随处可见的!

两个一维向量的离散卷积a[n]     b[n]     , y[n]     被定义为

y[n] = a[n] * b[n] = \sum^{\infty}_{k=-\infty} a[k]b[n-k]

由于需要两个向量相乘,离散卷积使用乘法的时间复杂度(假设向量的长度为n     ) 是O(n^2)     .这就是快速傅立叶变换 (FFT) 的用武之地。使用 FFT,我们可以将这种复杂性从O(n^2)     O(nlog(n))

使用 FFT 进行卷积背后的直觉

最基本的信号处理结果之一表明,时域中的卷积等效于频域中的乘法。为了执行卷积,我们可以将两个信号都转换为它们的频域表示,然后将逆傅立叶变换为 Hadamard 乘积(或点积)以获得卷积答案。工作流程可以总结为以下方式



FFT 工作流程的图示

安装:

出于本文的目的,我们将使用Python库numpy 和 scipy 中的一些内置函数您可以使用 pip 包管理器来安装它们。

pip install scipy numpy

Python的FFT卷积

为了使用 FFT 计算卷积,我们将使用Python中 scipy.signal 库中的 fftconvolve()函数。

下面是实现:

Python
from scipy import signal
  
a = [1, 2, 3]
b = [4, 5, 6]
  
y = signal.fftconvolve(a, b, mode = 'full')
print('The convoluted sequence is ', y)


Python
import numpy as np
from scipy import signal
  
a = np.random.randn(10**5)
b = np.random.randn(10**5)
  
print('Time required for normal discrete convolution:')
%timeit np.convolve(a, b)
  
print('Time required for FFT convolution:')
%timeit signal.fftconvolve(a, b)


输出

The convoluted sequence is  [ 4. 13. 28. 27. 18.]

FFT卷积与普通离散卷积的性能对比

  • 为了计算两个向量的正常线性卷积,我们将使用np.convolve函数。
  • Jupyter notebooks 的%timeit魔法函数用于计算给定向量的 2 个函数中的每一个所需的总时间。

下面是实现:

Python

import numpy as np
from scipy import signal
  
a = np.random.randn(10**5)
b = np.random.randn(10**5)
  
print('Time required for normal discrete convolution:')
%timeit np.convolve(a, b)
  
print('Time required for FFT convolution:')
%timeit signal.fftconvolve(a, b)

输出:

Time required for normal discrete convolution:
1.1 s ± 245 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Time required for FFT convolution:
17.3 ms ± 8.19 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

可以看到FFT卷积产生的输出比普通离散卷积产生的输出快1000倍!