Python 提高Numpy性能

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

我想使用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和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的一半,但算法不同
顺便说一下,google Convalve=>
“卷积运算应该模仿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之一)。