簡體   English   中英

改善Numpy表現

[英]Improving Numpy Performance

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

用於進行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多倍。

對於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程序員是否足夠智能自動執行此操作。 (我有一段時間沒有檢查過。)

您可能想要進行更有趣的卷積,其中可能會或可能不會考慮因子。

在使用ctypes說C之前,我建議在C中運行一個獨立的卷積,以查看限制的位置。
同樣對於CUDA,cython,scipy.weave ......

增加了7feb:convolve33帶剪輯的8位數據每個點需要大約20個時鍾周期,每個存儲器訪問需要2個時鍾周期,在我的mac g4 pcc上使用gcc 4.2。 你的里程有所不同。

一些細微之處:

  • 你關心正確剪裁到0..255嗎? np.clip()很慢,cython等都不知道。
  • Numpy / scipy可能需要內存大小為A的臨時值(因此保持2 * sizeof(A)<緩存大小)。
    但是,如果您的C代碼在內部進行了正在運行的更新,那么這只是內存的一半,而是一種不同的算法。

順便說一句,谷歌theano convolve =>“一個卷積操作,應該模仿scipy.signal.convolve2d,但更快!在開發中”

卷積的典型優化是使用信號的FFT。 原因是:真實空間中的卷積是FFT空間中的乘積。 計算FFT,產品和結果的iFFT通常比通常的方式更快。

截至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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM