19

我想使用 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 倍。

4

5 回答 5

10

scipy 中用于进行 2d 卷积的代码有点混乱且未优化。如果您想了解 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 倍以上。

于 2010-02-05T04:42:23.583 回答
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

并且其中第一个是可分解的 - 它可以通过对每一行进行卷积 (1 1 1) 进行卷积,然后再对每一列进行卷积。然后减去原始数据的九倍。这可能会也可能不会更快,这取决于 scipy 程序员是否足够聪明地自动执行此操作。(我有一段时间没有检查了。)

您可能想做更多有趣的卷积,其中可能会或可能不会进行因式分解。

于 2010-02-04T07:37:02.133 回答
1

在说 C 和 ctypes 之前,我建议在 C 中运行一个独立的卷积,看看限制在哪里。
同样对于 CUDA、cython、scipy.weave ...

添加了 7feb:在我的带有 gcc 4.2 的 mac g4 pcc 上,convolve33 8-bit data with clipping 每点需要大约 20 个时钟周期,每个 mem 访问需要 2 个时钟周期。您的里程有所不同。

一些微妙之处:

  • 您是否关心正确剪辑到 0..255 ?np.clip() 很慢,cython 等不知道。
  • Numpy/scipy 可能需要 A 大小的临时内存(因此保持 2*sizeof(A) < 缓存大小)。
    但是,如果您的 C 代码执行就地运行更新,那是内存的一半,但算法不同。

顺便说一句,google theano convolve =>“应该模仿 scipy.signal.convolve2d 的卷积运算,但速度更快!正在开发中”

于 2010-02-05T18:30:04.063 回答
0

卷积的典型优化是使用信号的 FFT。原因是:实空间中的卷积是FFT空间中的乘积。计算 FFT、乘积和结果的 iFFT 通常比用通常的方式进行卷积要快。

于 2010-02-04T01:18:44.563 回答
0

截至 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
于 2018-06-07T21:18:34.123 回答