正确使用pyfftw在numpy上加速
我正在尝试从Matlab到numpy的飞跃,但我迫切需要fft的速度。现在我知道pyfftw,但我不知道我是否正确使用了它。我的方法有点像正确使用pyfftw在numpy上加速,numpy,pyfftw,Numpy,Pyfftw,我正在尝试从Matlab到numpy的飞跃,但我迫切需要fft的速度。现在我知道pyfftw,但我不知道我是否正确使用了它。我的方法有点像 import numpy as np import pyfftw import timeit pyfftw.interfaces.cache.enable() def wrapper(func, *args): def wrapped(): return func(*args) return wrapped def my
import numpy as np
import pyfftw
import timeit
pyfftw.interfaces.cache.enable()
def wrapper(func, *args):
def wrapped():
return func(*args)
return wrapped
def my_fft(v):
global a
global fft_object
a[:] = v
return fft_object()
def init_cond(X):
return my_fft(2.*np.cosh(X)**(-2))
def init_cond_py(X):
return np.fft.fft(2.*np.cosh(X)**(-2))
K = 2**16
Llx = 10.
KT = 2*K
dx = Llx/np.float64(K)
X = np.arange(-Llx,Llx,dx)
global a
global b
global fft_object
a = pyfftw.n_byte_align_empty(KT, 16, 'complex128')
b = pyfftw.n_byte_align_empty(KT, 16, 'complex128')
fft_object = pyfftw.FFTW(a,b)
wrapped = wrapper(init_cond, X)
print min(timeit.repeat(wrapped,repeat=100,number=1))
wrapped_two = wrapper(init_cond_py, X)
print min(timeit.repeat(wrapped_two,repeat=100,number=1))
我很欣赏通过pyfftw调用scipy和numpy fft有构建器函数和标准接口。但这些都表现得非常缓慢。通过首先创建fft_对象的实例,然后全局使用它,我能够获得与numpy的fft调用一样快或稍快的速度
话虽如此,我工作的前提是,智慧被隐含地储存着。这是真的吗?我需要把它说清楚吗?如果是,最好的方法是什么
而且,我认为它是完全不透明的。我用得对吗?它是否像我所说的那样储存智慧?提前感谢您可能提供的任何帮助 在交互式(ipython)会话中,我认为以下是您想要做的事情(timeit由ipython很好地处理):
你看过报纸了吗?你还不明白什么
我建议使用来构造FFTW对象。玩各种设置,最重要的是线程数
智慧不是默认存储的。你需要这样做
所有的globals
都是不必要的-您想要更改的对象是可变的,因此您可以很好地处理它们<代码>fft_对象始终指向同一个对象,因此如果不是全局对象,就没有问题。理想情况下,您只是不希望该循环覆盖ii
。我建议研究一下如何构造数组,以便在一次调用中完成所有操作
编辑:
[编辑:我只是粗略地看了一下你的代码,写了下面的一段,很明显,由于它是一个递归更新,向量化不是一个明显的方法,没有一些严重的技巧。不过,我在底部对你的实现有一些评论]
我怀疑您的问题是对如何最好地使用Python(或者实际上是Matlab)之类的语言进行数值处理的更根本的误解。其核心宗旨是尽可能多地矢量化。我的意思是,将python调用汇总为尽可能少的调用。不幸的是,我看不出如何使用您的示例实现这一点(尽管我只考虑了2分钟)。如果这仍然是失败的,想一想——尽管要确保你真的想走这条路(也就是说,你已经用尽了其他的选择)
关于全球人:不要那样做。如果您想创建一个状态为的对象,在您的情况下可以使用类(这就是它们的用途)或者闭包。全局代码几乎从来都不是你想要的(我想在我所有的python写作中,我至少有一个合法的用法,那就是在pyfftw的缓存代码中)。我建议你读书。Matlab是一种蹩脚的语言——其众多原因之一是其蹩脚的范围界定工具,这往往会导致坏习惯
仅当要全局修改引用时才需要全局。我建议阅读更多关于python中的变量以及哪些变量的内容
FFTW
对象带有您需要的所有数组,因此您无需单独传递它们。无论是设置还是返回值,使用调用接口几乎不会带来任何开销(特别是在禁用规范化的情况下)——如果您处于该优化级别,我强烈怀疑您已经达到了极限(我要警告的是,对于许多非常小的FFT来说,这可能并不完全正确,但在这一点上,您需要重新考虑将对FFTW的调用矢量化的算法)。如果您发现每次更新数组(使用调用接口)都会产生大量开销,这是一个bug,您应该提交它(我会非常惊讶)
总之,不要担心每次调用时都会更新数组。这几乎肯定不是您的瓶颈,但请确保您知道规范化,并在需要时禁用它(与原始访问update\u arrays()
和execute()
方法相比,它可能会稍微降低速度)
您的代码不使用缓存。缓存仅在您使用接口
代码时使用,并减少了在内部创建新FFTW对象时的Python开销。由于您自己处理FFTW对象,因此没有理由使用缓存
builders
代码是获取FFTW对象的一个约束较少的接口。我现在几乎总是使用构建器(从头开始创建FFTW对象要方便得多)。想要直接创建FFTW对象的情况非常罕见,我想知道它们是什么
关于算法实现的评论:
我不熟悉您正在实现的算法。但是,我对您目前编写的算法有一些评论。
你在每个循环中都在计算nl_eval(wp)
,但据我所知,这与上一个循环中的nl_eval(w)
是一样的,所以你不需要计算两次(但这附带一个警告,当你到处都有全局变量时,很难看到发生了什么,所以我可能遗漏了一些东西)
不要为my\u fft
或my\u ifft
中的副本操心。只需执行fft\u对象(u)
(在我的机器上,正向情况下为2.29毫秒,而在我的机器上为1.67毫秒)。内部数组更新例程使副本变得不必要。此外,正如您编写的那样,您复制了两次:c[:]
意味着“复制到数组中c
”,而要复制到c
中的数组是v.copy()
,即v
的一个副本(总共两个副本)
更明智的做法(可能是必要的)是将输出复制到保留数组中(因为这样可以避免在调用FFTW对象时破坏临时结果),不过要确保保留数组
In [1]: import numpy as np
In [2]: import pyfftw
In [3]: K = 2**16
In [4]: Llx = 10.
In [5]: KT = 2*K
In [6]: dx = Llx/np.float64(K)
In [7]: X = np.arange(-Llx,Llx,dx)
In [8]: a = pyfftw.n_byte_align_empty(KT, 16, 'complex128')
In [9]: b = pyfftw.n_byte_align_empty(KT, 16, 'complex128')
In [10]: fft_object = pyfftw.FFTW(a,b)
In [11]: a[:] = 2.*np.cosh(X)**(-2)
In [12]: timeit np.fft.fft(a)
100 loops, best of 3: 4.96 ms per loop
In [13]: timeit fft_object(a)
100 loops, best of 3: 1.56 ms per loop
In [14]: np.allclose(fft_object(a), np.fft.fft(a))
Out[14]: True