我想使用python提高卷积的性能,并希望能够对如何最好地提高性能有所了解。
我目前正在使用scipy来执行卷积,使用的代码有点像下面的代码段:
import numpy
import scipy
import scipy.signal
import timeit
a=numpy.array ( [ range(1000000) ] )
a.reshape(1000,1000)
filt=numpy.array( [ [ 1, 1, 1 ], [1, -8, 1], [1,1,1] ] )
def convolve():
global a, filt
scipy.signal.convolve2d ( a, filt, mode="same" )
t=timeit.Timer("convolve()", "from __main__ import convolve")
print "%.2f sec/pass" % (10 * t.timeit(number=10)/100)
我正在处理图像数据,使用灰度(0到255之间的整数值),我目前每卷积约四分之一秒。我的想法是做以下其中一项:
使用corepy,最好使用一些优化 用icc&重新编译numpy ikml。 使用python-cuda。
我想知道是否有人对这些方法有任何经验(通常会获得什么样的收益,如果值得花时间),或者是否有人知道有更好的库来与Numpy进行卷积。< / p>
谢谢!
编辑:
通过使用Numpy在C中重写python循环来加速大约10倍。
答案 0 :(得分:10)
用于进行2d卷积的scipy中的代码有点混乱且未经优化。如果您想了解scipy的低级功能,请参阅http://svn.scipy.org/svn/scipy/trunk/scipy/signal/firfilter.c。
如果您只想处理一个像您所展示的那样的小型常量内核,那么这样的函数可能会起作用:
def specialconvolve(a):
# sorry, you must pad the input yourself
rowconvol = a[1:-1,:] + a[:-2,:] + a[2:,:]
colconvol = rowconvol[:,1:-1] + rowconvol[:,:-2] + rowconvol[:,2:] - 9*a[1:-1,1:-1]
return colconvol
这个函数利用了像上面建议的DarenW这样的内核的可分离性,以及利用更优化的numpy算法例程。通过我的测量,它比convolve2d函数快1000多倍。
答案 1 :(得分:2)
对于特定示例3x3内核,我会观察到
1 1 1
1 -8 1
1 1 1
1 1 1 0 0 0
= 1 1 1 + 0 -9 0
1 1 1 0 0 0
并且其中第一个是可以考虑的 - 它可以通过对每一行进行卷积(111)来进行卷积,然后对每一列进行卷积。然后减去原始数据的九倍。这可能会或可能不会更快,这取决于scipy程序员是否足够智能自动执行此操作。 (我有一段时间没有检查过。)
您可能希望进行更有趣的回合,其中可能会或可能不会考虑因子。
答案 2 :(得分:1)
在使用ctypes说C之前,我建议在C中运行一个独立的卷积,以查看限制的位置。
同样对于CUDA,cython,scipy.weave ......
增加了7feb:convolve33带剪辑的8位数据每个点约需20个时钟周期, 每个mem访问2个时钟周期,在我的mac g4 pcc上使用gcc 4.2。您的里程 会有所不同。
一些细微之处:
顺便说一下,Google theano convolve =&gt; “卷积运算应该模仿scipy.signal.convolve2d,但更快!在开发中”
答案 3 :(得分:0)
卷积的典型优化是使用信号的FFT。原因是:真实空间中的卷积是FFT空间中的乘积。计算FFT,产品和结果的iFFT通常比通常的方式更快。</ p>
答案 4 :(得分:0)
截至2018年,似乎SciPy / Numpy组合已经加速了很多。这是我在笔记本电脑上看到的(戴尔Inspiron 13,i5)。 OpenCV做得最好,但你对模式没有任何控制。
>>> img= np.random.rand(1000,1000)
>>> kernel = np.ones((3,3), dtype=np.float)/9.0
>>> t1= time.time();dst1 = cv2.filter2D(img,-1,kernel);print(time.time()-t1)
0.0235188007355
>>> t1= time.time();dst2 = signal.correlate(img,kernel,mode='valid',method='fft');print(time.time()-t1)
0.140458106995
>>> t1= time.time();dst3 = signal.convolve2d(img,kernel,mode='valid');print(time.time()-t1)
0.0548939704895
>>> t1= time.time();dst4 = signal.correlate2d(img,kernel,mode='valid');print(time.time()-t1)
0.0518119335175
>>> t1= time.time();dst5 = signal.fftconvolve(img,kernel,mode='valid');print(time.time()-t1)
0.13204407692