2012-10-13 61 views
2

我想加快我正在使用很多的功能,我雖然關於使用cython。但是,在嘗試了所有可以在文檔中找到的可能的cython優化之後,cython代碼比python + numpy函數慢大約6倍。令人失望!Cython化函數意外慢

這是我的測試代碼:(forward1是Python功能,forward2是用Cython功能)

#geometry.py 
def forward1(points, rotation, translation): 
    '''points are in columns''' 
    return np.dot(rotation, points - translation[:, np.newaxis]) 

#geometry.pyx 
import numpy as np 
cimport numpy as np 
cimport cython 

@cython.boundscheck(False) 
@cython.wraparound(False) 
@cython.nonecheck(False) 
cdef np.float64_t[:,:] forward2(np.float64_t[:,:] points, np.float64_t[:,:] rotation, np.float64_t[:] translation): 
    '''points are in columns''' 
    cdef unsigned int I, J 
    I = points.shape[0] 
    J = points.shape[1] 
    cdef np.float64_t[:,:] tmp = np.empty((I, J), dtype=np.float64) 
    cdef unsigned int i 
    for i in range(J): 
     tmp[0, i] = points[0, i] - translation[0]   
     tmp[1, i] = points[1, i] - translation[1]   
    cdef np.float64_t[:,:] result = np.dot(rotation, tmp) 
    return result 

def test_forward2(points, rotation, translation): 
    import timeit 
    cdef np.float64_t[:,:] points2 = points 
    cdef np.float64_t[:,:] rotation2 = rotation 
    cdef np.float64_t[:] translation2 = translation 
    t = timeit.Timer(lambda: forward2(points2, rotation2, translation2)) 
    print min(t.repeat(3, 10)) 

,然後我計時:

t = timeit.Timer(lambda: forward1(points, rotation, translation)) 
print min(t.repeat(3, 10)) 
0.000368164520751 

test_forward2(points, rotation, translation) 
0.0023365181969 

有什麼我可以做使其更快的cython代碼?

如果在cython中無法加快forward1,我希望使用編織加快速度嗎?

編輯:

只是爲了記錄在案,我試圖加速功能的另一件事是在FORTRAN爲了傳遞點,我點存儲在列,有相當一部分他們。我還將本地tmp定義爲fortran命令。我認爲函數的減法部分應該更快,但numpy.dot似乎需要一個C順序輸出(無論如何解決這個問題?),所以總的來說,這也沒有加速。我也嘗試轉置這些點,以便減法部分在C順序中更快,但似乎點積仍然是最昂貴的部分。

此外,我注意到,numpy.dot不能使用memoryviews作爲out參數,即使它是C順序,這是一個錯誤嗎?

+0

輸出什麼'numpy'已經使用'C'和'爲計算fortran'庫。通常你不需要做任何事情來獲得加速。 – none

回答

4

只是看看你的代碼,它看起來像一些東西(減去數組和點積),numpy已經非常優化了。

Cython對於加速numpy通常執行得不好的情況非常有用(例如迭代是用python編寫的迭代算法),但是在這種情況下,內部循環已經由BLAS庫執行。

如果你想加快速度,我看的第一個地方是BLAS/LAPACK/ATLAS/etc庫numpy鏈接的目的地。使用「經過優化的」線性代數庫(例如ATLAS或Intel的MKL)會在這種情況下產生很大(在某些情況下大於10倍)的差異。

要了解您目前使用看看的numpy.show_config()

+0

好的,謝謝,我明白了。我已經運行numpy.show_config(),但我不知道如何解釋結果:
'mkl_info: libraries = ['mkl_lapack95','mkl_blas95','mkl_intel_c',...] library_dirs = ['C :/ Program Files(x86)/Intel/Compiler/11.1/070/mkl/ia32/lib'] define_macros = [('SCIPY_MKL_H',None)] include_dirs = ['C:/ Program Files(x86)/ Intel /Compiler/11.1/070/mkl/include']' 我得到了類似的結構lapack_opt_info,blas_opt_info,lapack_mkl_info和blas_mkl_info 這是否意味着我的numpy版本與MKL鏈接?或[('SCIPY_MKL_H',None)]意味着它沒有? – martinako

+0

只是爲了記錄,我的numpy版本是'1.6.2',我安裝了EPD免費分配在Windows7框 – martinako

+0

是的,你的numpy是再次鏈接MKL。那麼我的建議不會對你有太大的幫助。MKL大概是儘可能優化的。 –