Python 使用SciPy接口和Cython直接调用BLAS/LAPACK

Python 使用SciPy接口和Cython直接调用BLAS/LAPACK,python,numpy,cython,blas,intel-mkl,Python,Numpy,Cython,Blas,Intel Mkl,这里有一篇关于这一点的帖子:只需调用Fortran库(BLAS/LAPACK/Intel MKL/OpenBLAS/随NumPy一起安装的任何东西),就可以大大提高速度。经过数小时的工作(因为不推荐使用的SciPy库),我最终编译了它,但没有结果。它比NumPy快2倍。不幸的是,正如另一位用户指出的那样,Fortran例程总是将输出矩阵添加到新计算的结果中,因此它只在第一次运行时匹配NumPy。即A:=alpha*x*y.T+A。因此,这仍然需要快速解决 [更新:对于那些希望使用SCIPY接口的

这里有一篇关于这一点的帖子:只需调用Fortran库(BLAS/LAPACK/Intel MKL/OpenBLAS/随NumPy一起安装的任何东西),就可以大大提高速度。经过数小时的工作(因为不推荐使用的SciPy库),我最终编译了它,但没有结果。它比NumPy快2倍。不幸的是,正如另一位用户指出的那样,Fortran例程总是将输出矩阵添加到新计算的结果中,因此它只在第一次运行时匹配NumPy。即
A:=alpha*x*y.T+A
。因此,这仍然需要快速解决

[更新:对于那些希望使用SCIPY接口的用户,请点击此处,因为他们已经优化了CPDEF语句中对BLAS/LAPACK的调用,只需复制/粘贴到CYTHON脚本
#Python可访问的包装器中进行测试:
还有CYTHON\u LAPACK.pyx上面的链接,但没有CYTHON测试脚本]

测试脚本 #结束测试脚本

PYX文件编译cyblas.PYX(基本上是np.ndarray版本)
导入cython
将numpy作为np导入
cimport numpy作为np
来自cpython cimport PyCapsule\u GetPointer
cimport scipy.linalg.cython_blas
cimport scipy.linalg.cython_lapack
将scipy.linalg作为LA导入
REAL=np.64
ctypedef np.float64\u t REAL\t
ctypedef np.uint64\u t INT\t
cdef int ONE=1
cdef REAL\u t ONEF=1.0
ctypedef void(*dger_ptr)(常数int*M,常数int*N,常数double*alpha,常数double*X,常数int*incX,双*Y,常数int*incY,双*A,常数int*LDA)无
cdef dger_ptr dger=PyCapsule_GetPointer(LA.blas.dger._cpointer,NULL)#A:=alpha*x*y.T+A
cpdef外部产品(x、y、输出):
#cpdef outer_prod(_x,_y):#行上注释并使用此注释将输出矩阵重置为零
cdef REAL_t*x=(np.PyArray_DATA(_x))
cdef int M=_y.shape[0]
cdef int N=x.shape[0]
#cdef np.ndarray[np.float64_t,ndim=2,order='c']_output=np.zeros((M,N))#缓慢修复取消注释以将输出矩阵重置为零
cdef REAL_t*y=(np.PyArray_DATA(_y))
cdef REAL_t*output=(np.PyArray_数据(_output))
诺吉尔:
dger(&M,&N,&ONEF,y,&ONE,x,&ONE,输出,&M)

非常感谢。希望这能为其他人节省一些时间(几乎有效)-事实上,正如我所评论的,它工作1x并匹配NumPy,然后每个后续调用都会再次添加到结果矩阵中。如果我将输出矩阵重置为0并重新运行结果,则匹配NumPy。奇怪……尽管如果取消注释,上面的几行仍会工作,尽管仅在NumPy速度下。替代方法是
memset
d将出现在另一个帖子中…我只是还没有弄清楚如何准确地调用它。

根据
dger(M,N,ALPHA,X INCX,Y,INCY,A,LDA)
执行
A:=alpha*x*y**T+A
。因此
A
应该都是零,才能得到
x
y
的外积。好吧,我的测试脚本不好。我只需要将
int32
随机整数更改为
np.float64
。但我仍然会有奇怪的行为(可能与指针有关?)由于结果似乎在第一次调用后改变了对函数的每次调用,因此它们不匹配!!!根据
dger(M,N,ALPHA,X INCX,Y,INCY,A,LDA)
执行
A:=alpha*x*y**T+A
。所以
A
应该都是零,才能得到
x
y
@user7138814的外积有趣…真奇怪,但我想你回答了我的问题。我想用np.zero初始化的memoryview是一个很好的解决办法,但显然这是必需的预计起飞时间!
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 outer_prod(a,b) #use with fixed version instead of above line, results will automatically update cy_outer
%timeit np.outer(a,b, np_outer)
100 loops, best of 3: 2.83 ms per loop
100 loops, best of 3: 6.58 ms per loop
import cython
import numpy as np
cimport numpy as np

from cpython cimport PyCapsule_GetPointer 
cimport scipy.linalg.cython_blas
cimport scipy.linalg.cython_lapack
import scipy.linalg as LA

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

ctypedef void (*dger_ptr) (const int *M, const int *N, const double *alpha, const double *X, const int *incX, double *Y, const int *incY, double *A, const int * LDA) nogil
cdef dger_ptr dger=<dger_ptr>PyCapsule_GetPointer(LA.blas.dger._cpointer, NULL)  # A := alpha*x*y.T + A

cpdef outer_prod(_x, _y, _output):
#cpdef outer_prod(_x, _y): #comment above line & use this to use the reset output matrix to zeros
    cdef REAL_t *x = <REAL_t *>(np.PyArray_DATA(_x))
    cdef int M = _y.shape[0]
    cdef int N = _x.shape[0]
    #cdef np.ndarray[np.float64_t, ndim=2, order='c'] _output = np.zeros((M,N)) #slow fix to uncomment to reset output matrix to zeros
    cdef REAL_t *y = <REAL_t *>(np.PyArray_DATA(_y))
    cdef REAL_t *output = <REAL_t *>(np.PyArray_DATA(_output))
    with nogil:
        dger(&M, &N, &ONEF, y, &ONE, x, &ONE, output, &M)