Python 如何加速numpy代码
我有以下代码。原则上它需要2^6*1000=64000次迭代,这是一个相当小的数字。然而,它需要在我的计算机上运行9秒,我想至少运行n=15Python 如何加速numpy代码,python,performance,numpy,cython,Python,Performance,Numpy,Cython,我有以下代码。原则上它需要2^6*1000=64000次迭代,这是一个相当小的数字。然而,它需要在我的计算机上运行9秒,我想至少运行n=15 from __future__ import division import numpy as np import itertools n=6 iters = 1000 firstzero = 0 bothzero = 0 for S in itertools.product([-1,1], repeat = n+1): for i in xra
from __future__ import division
import numpy as np
import itertools
n=6
iters = 1000
firstzero = 0
bothzero = 0
for S in itertools.product([-1,1], repeat = n+1):
for i in xrange(iters):
F = np.random.choice(np.array([-1,0,0,1], dtype=np.int8), size = n)
while np.all(F ==0):
F = np.random.choice(np.array([-1,0,0,1], dtype=np.int8), size = n)
FS = np.convolve(F,S, 'valid')
if (FS[0] == 0):
firstzero += 1
if np.all(FS==0):
bothzero += 1
print "firstzero", firstzero
print "bothzero", bothzero
有没有可能把速度提高很多,或者我应该用C重写它
分析表明它将大部分时间花在
258003 0.418 0.000 3.058 0.000 fromnumeric.py:1842(all)
130003 1.245 0.000 2.907 0.000 {method 'choice' of 'mtrand.RandomState' objects}
388006 2.488 0.000 2.488 0.000 {method 'reduce' of 'numpy.ufunc' objects}
128000 0.731 0.000 2.215 0.000 numeric.py:873(convolve)
258003 0.255 0.000 2.015 0.000 {method 'all' of 'numpy.ndarray' objects}
258003 0.301 0.000 1.760 0.000 _methods.py:35(_all)
130003 0.470 0.000 1.663 0.000 fromnumeric.py:2249(prod)
644044 1.483 0.000 1.483 0.000 {numpy.core.multiarray.array}
130003 0.164 0.000 1.193 0.000 _methods.py:27(_prod)
258003 0.283 0.000 0.624 0.000 numeric.py:462(asanyarray)
通过一次生成所有随机选择,我很容易获得35-40%的加速:
for S in itertools.product([-1,1], repeat = n+1):
Fx = np.random.choice(np.array([-1,0,0,1], dtype=np.int8), size=(iters,n))
for F in Fx:
这取代了xrange(iters)中i的循环
为了超越这一点,我怀疑您可以使用scipy.signal.fftconvolve对卷积本身进行矢量化(np.convolve仅支持1D输入)。我没有尝试这个,部分是因为我写这篇文章时scipy.org是离线的,但我希望这能让你继续下去。主要思想是减少Python中的循环,尽可能用矢量化操作替换它们。几乎完全矢量化的代码速度要快得多(16.9%),假设您的代码名为f()
:
计时结果:
In [164]:
%timeit f()
firstzero 27171
bothzero 12151
firstzero 27206
bothzero 12024
firstzero 27272
bothzero 12135
firstzero 27173
bothzero 12079
1 loops, best of 3: 14.6 s per loop
In [165]:
%timeit g()
firstzero 27182
bothzero 11952
firstzero 27365
bothzero 12174
firstzero 27318
bothzero 12173
firstzero 27377
bothzero 12072
1 loops, best of 3: 2.47 s per loop
你能解释一下这段代码在做什么吗?@MrE它是计算两个随机数组的卷积的次数,一个比另一个长,具有特定的概率分布,第一个位置有0,或者两个位置都有0。只是一个注释。通过改进代码,您只能获得线性加速。除非你能获得99%的速度提升,否则你不会走得很远,除非你跳过O(2^n)复杂度n=15
将始终以低于2^15/2^6=2^9
的速度工作,因此要保持在同一时间内,您实际上需要将速度提高到系数512。@32是的。我怀疑,如果用C语言正确编码,比如用一个比我更好的编码员,目前的速度可能会快512倍。它并不是每次迭代都做很多事情。@user2179021我真的怀疑它=)。在我看来,通过改变语言/工具,你最多可以得到10个。请注意,您已经在使用专门的工具,程序不会在代码中花费时间。正如约翰所建议的,也许使用不同的工具才是最好的选择。但我认为你可能必须将其并行化,以获得更大的因素和更大的问题规模。。。你仍然会撞上O(2^n)墙,而不是迟早。但我祝你好运。也许n=15到20可以在合理的时间内计算。谢谢。我不太懂scipy.signal.fftconvolve。你是在建议做二维卷积吗?那几乎不行。你看,必须排除np.all(F==0)
的行Fx
必须以大于(iters,n)
@user2179021卷积的大小生成,通过FFT进行的卷积可放大,以获得比常规卷积更好的更大阵列大小。详情请参见本页:太好了。非常感谢。不客气。我想先尝试矢量化,而不是c
或fortran
或其他。numpy
或scipy
中的很多东西都已经在引擎盖下了,因此,矢量化在至少一半的时间内都是必需的。
In [164]:
%timeit f()
firstzero 27171
bothzero 12151
firstzero 27206
bothzero 12024
firstzero 27272
bothzero 12135
firstzero 27173
bothzero 12079
1 loops, best of 3: 14.6 s per loop
In [165]:
%timeit g()
firstzero 27182
bothzero 11952
firstzero 27365
bothzero 12174
firstzero 27318
bothzero 12173
firstzero 27377
bothzero 12072
1 loops, best of 3: 2.47 s per loop