簡體   English   中英

在Cython腳本中使用memset而不是np.zeros來提高速度

[英]Using memset instead of np.zeros in a Cython script for speed gains

我開始研究到Fortran庫(BLAS / LAPACK)的SciPy接口,可以在這里看到: 使用SciPy接口和Cython直接調用BLAS / LAPACK,並提出了一個解決方案,但不得不求助於使用numpy.zeros直接調用Fortran代碼會扼殺任何速度提升。 問題是Fortran代碼需要一個0值的輸出矩陣(它在內存中的矩陣上就地運行)以匹配Numpy版本( np.outer )。

所以我有點困惑,因為Python中的1000x1000零矩陣僅占用8us(使用%timeit或0.008ms),那么為什么添加Cython代碼會殺死運行時,並指出我也在memoryview上創建了它? (基本上,從1000到1000的矩陣乘法,它從3毫秒變為8毫秒左右)。 然后,在SO上搜索之后,我在其他地方找到了使用memset作為最快的數組更改機制的解決方案。 因此,我將整個代碼從引用的文章重寫為較新的memoryview格式,並得到如下所示的內容(Cython cyblas.pyx文件):

import cython
import numpy as np
cimport numpy as np
from libc.string cimport memset #faster than np.zeros

REAL = np.float64
ctypedef np.float64_t REAL_t
ctypedef np.uint64_t  INT_t

cdef int ONE = 1
cdef REAL_t ONEF = <REAL_t>1.0

@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)
cpdef outer_prod(double[::1] _x, double[::1] _y, double[:, ::1] _output):

    cdef int M = _y.shape[0]
    cdef int N = _x.shape[0]
    memset(&_output[0,0], 0, M*N)

    with nogil:
        dger(&M, &N, &ONEF, &_y[0], &ONE, &_x[0], &ONE, &_output[0,0], &M)

測試腳本

import numpy as np;
from cyblas import outer_prod;
a=np.random.randint(0,100, 1000);
b=np.random.randint(0,100, 1000);
a=a.astype(np.float64)
b=b.astype(np.float64)
cy_outer=np.zeros((a.shape[0],b.shape[0]));
np_outer=np.zeros((a.shape[0],b.shape[0]));

%timeit outer_prod(a,b, cy_outer)
%timeit np.outer(a,b, np_outer)

因此,這解決了我的問題:僅將輸出矩陣值重置為125行,但此問題仍然存在(請參見下文)。 我認為將memset length參數設置為M * N會清除內存中的1000 * 1000,但顯然不會。

有誰知道如何使用memset將整個輸出矩陣重置為0? 非常感激。

[更新-修復程序是:它需要#bytes不僅僅是M*N的數組大小,即M*N*variable_bytes作為長度輸入。 此處的邏輯可以通過先前的結果看出:行125是它停止的位置* 8字節= 1000行,因此回答了問題。 指標仍然不是很好:100個循環,每個循環最好3:5.41 ms(cython)100個循環,每個循環最好3:3.95 ms(numpy),但是仍然可以解決。 更改上面的代碼是要添加: cdef variable_bytes = np.dtype(REAL).itemsize #added to get bytes for memset, after REAL is defined, in this case 8 bytes被添加cdef variable_bytes = np.dtype(REAL).itemsize #added to get bytes for memset, after REAL is defined, in this case 8 bytes然后您調用memset: memset(&_output[0,0], 0, M*N*variable_bytes) # gives the same output as np.zeros function我現在看到的唯一加快速度的地方是在大型矩陣上使用prange OpenMP語句,但尚待觀察。

暫無
暫無

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

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