用BLA实现更快的python内部产品

2024-10-01 02:27:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我发现this useful tutorial使用低级BLAS函数(在Cython中实现)比python中的标准numpy线性代数例程获得更大的速度改进。现在,我已经成功地使向量乘积工作得很好。首先,我将以下内容保存为linalg.pyx

import cython
import numpy as np
cimport numpy as np

from libc.math cimport exp
from libc.string cimport memset

from scipy.linalg.blas import fblas

REAL = np.float64
ctypedef np.float64_t REAL_t

cdef extern from "/home/jlorince/flda/voidptr.h":
    void* PyCObject_AsVoidPtr(object obj)

ctypedef double (*ddot_ptr) (const int *N, const double *X, const int *incX, const double *Y, const int *incY) nogil
cdef ddot_ptr ddot=<ddot_ptr>PyCObject_AsVoidPtr(fblas.ddot._cpointer)  # vector-vector multiplication 

cdef int ONE = 1
def vec_vec(syn0, syn1, size):
    cdef int lSize = size
    f = <REAL_t>ddot(&lSize, <REAL_t *>(np.PyArray_DATA(syn0)), &ONE, <REAL_t *>(np.PyArray_DATA(syn1)), &ONE)
    return f

(voidptr.h的源代码可用here

一旦我编译它,它就可以正常工作,而且绝对比np.inner快:

^{pr2}$

现在,这很好,但只适用于计算两个向量的点/内积(在本例中等价)的情况。我现在需要做的是,实现类似的函数(我希望能提供类似的加速)来处理向量矩阵的乘积。也就是说,当传递1D数组和2D矩阵时,我想复制np.inner的功能:

In [4]: x = np.random.random(5)
In [5]: y = np.random.random((5,5))
In [6]: np.inner(x,y)
Out[6]: array([ 1.42116225,  1.13242989,  1.95690196,  1.87691992,  0.93967486])

这相当于计算1D数组和矩阵的每一行的内积/点积(同样,对于1D数组是等效的):

In [32]: [np.inner(x,row) for row in y]
Out[32]:
[1.4211622497461549, 1.1324298918119025, 1.9569019618096966,1.8769199192990056, 0.93967485730285505]

从我所看到的BLAS文档来看,我认为我需要从以下内容开始(使用dgemv):

ctypedef double (*dgemv_ptr) (const str *TRANS, const int *M, const int *N, const double *ALPHA, const double *A, const int *LDA, const double *X, const int *incX, const double *BETA, const double *Y, const int *incY)
cdef dgemv_ptr dgemv=<dgemv>PyCObject_AsVoidPtr(fblas.dgemv._cpointer)  # matrix vector multiplication

但是我需要帮助(a)定义我可以在Python中使用的实际函数(即,类似于上面的vec-matrix函数),以及(b)知道如何使用它正确地复制np.inner的行为,这正是我所实现的模型所需要的。在

编辑:Here是指向我需要使用的dgemv相关BLAS文档的链接,在这里确认:

In [13]: np.allclose(scipy.linalg.blas.fblas.dgemv(1.0,y,x), np.inner(x,y))
Out[13]: True

但像这样开箱即用实际上比纯的慢np.内部,所以我仍然需要Cython实现的帮助。在

Edit2这是我最近的一次尝试,它可以很好地编译python,但每当我试图运行它时,它就会因分段错误而崩溃:

cdef int ONE = 1
cdef char tr = 'n'
cdef REAL_t ZEROF = <REAL_t>0.0
cdef REAL_t ONEF = <REAL_t>1.0
def mat_vec(mat,vec,mat_rows,mat_cols):
    cdef int m = mat_rows
    cdef int n = mat_cols
    out = <REAL_t>dgemv(&tr, &m, &n, &ONEF, <REAL_t *>(np.PyArray_DATA(mat)), &m, <REAL_t *>(np.PyArray_DATA(vec)), &ONE, &ZEROF, NULL, &ONE)
    return out

编译之后,我尝试运行linalg.mat_vec(y,x,5,5)(使用与上面相同的x和y),但这只是崩溃。我想我已经很接近了,但不知道还有什么可以改变的。。。在


Tags: 函数innponerealintinnerdouble
1条回答
网友
1楼 · 发布于 2024-10-01 02:27:11

根据@Pietro Saccardi:

int dgemv_(char *trans, integer *m, integer *n, doublereal *
           alpha, doublereal *a, integer *lda, doublereal *x, integer *incx, 
           doublereal *beta, doublereal *y, integer *incy)

...

Y      - DOUBLE PRECISION array of DIMENSION at least   
         ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n'   
         and at least   
         ( 1 + ( n - 1 )*abs( INCY ) ) otherwise.   
         Before entry with BETA non-zero, the incremented array Y   
         must contain the vector y. On exit, Y is overwritten by the
         updated vector y.

我怀疑您能否在呼叫中使用NULL作为Y。在

相关问题 更多 >