Python 提高Numpy性能
我想使用python改进卷积运算的性能,并希望了解如何最好地提高性能 我目前正在使用scipy执行卷积,使用的代码有点像下面的代码片段:Python 提高Numpy性能,python,math,numpy,scipy,convolution,Python,Math,Numpy,Scipy,Convolution,我想使用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
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和ikml重新编译numpy。
使用python cuda
我想知道是否有人对这些方法有任何经验(典型的收益是什么,是否值得花时间),或者是否有人知道使用Numpy执行卷积的更好的库
谢谢
编辑:
通过使用Numpy在C上重新编写python循环,可将速度提高约10倍 卷积的典型优化是使用信号的FFT。原因是:实空间中的卷积是FFT空间中的乘积。与通常的卷积方法相比,计算结果的FFT、乘积和iFFT通常更快。对于特定的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
其中的第一个是可分解的-它可以通过对每行(1)进行卷积,然后对每列进行卷积。然后减去原始数据的九倍。这可能更快,也可能更快,这取决于scipy程序员是否足够聪明,能够自动完成这项工作。(我有一阵子没登记了。)
您可能想做更多有趣的卷积,其中分解可能是可能的,也可能是不可能的 scipy中用于进行2d卷积的代码有点凌乱且未优化。看看你是否想了解一下scipy的底层功能 如果您只想使用一个小的、恒定的内核(如图所示)进行处理,那么这样的函数可能会起作用:
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算术例程。根据我的测量,它比卷积2D函数快1000倍以上 在用ctypes说C之前,我建议在C中运行一个独立的卷积,看看限制在哪里。
同样适用于CUDA、cython、scipy.weave 增加了2月7日:卷积33个8位数据和限幅,每个点需要约20个时钟周期, 在带有gcc 4.2的mac g4 pcc上,每个mem访问2个时钟周期。你的里程数会有所不同 有几个微妙之处:
- 您是否关心0..255的正确剪裁?np.clip()很慢, 西顿等人不知道
- Numpy/scipy可能需要内存来存储大小为A的temp(因此保持2*sizeof(A)<缓存大小)。
但是,如果您的C代码在原地执行运行更新,则这是mem的一半,但算法不同
“卷积运算应该模仿scipy.signal.convalve2d,但速度更快!正在开发中”截至2018年,似乎scipy/Numpy组合的速度加快了很多。这是我在笔记本电脑上看到的(Dell 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
用cuda这样做,速度会非常快。如果cuda在目标环境中工作,它很可能获得最佳性能。。。GPU确实非常快。cuda赢不了的唯一方法是,如果数据传输到GPU和背面开始占据主导地位。我希望视频卡之间的数据传输将成为问题!对已有的库有什么建议吗?傅里叶技巧适用于大卷积核,但对于所示的示例,它只有3x3。简单的方法可能更快-但是如果FFT使用CUDA而简单的方法不使用,不需要说明w/o测量。感谢您指出,我没有想到scipy卷积会如此低效。看起来,尽管我没有仔细检查,但scipy convalve正在执行相当多的内存操作,并且有许多if语句在减慢速度。我会把结果发回来,谢谢大家的评论。是的,卷积2D处理一般情况时效率很低(它处理任意对象-例如,您应该能够使用十进制对象数组进行卷积)。我认为在常见情况下使用特殊的代码路径可以大大加快速度(特别是避免在三重循环中调用函数指针,这很可能是hostpot之一)。