Cython中用于循环调用的快速基本线性代数

时间:2015-07-17 22:23:05

标签: python numpy scipy cython

我正在尝试用cython编程一个函数来进行蒙特卡罗模拟。该函数涉及多个小的线性代数运算,如点积和矩阵求逆。由于该功能被称为成千上万次,所以numpy开销占了很大一部分成本。 三年前,有人问过这个问题:calling dot products and linear algebra operations in Cython? 我试图使用两个答案的建议,但第一个scipy.linalg.blas仍然通过一个python包装器,我没有真正得到任何改进。第二种,使用gsl包装器也相当慢,当向量的尺寸非常大时,往往会冻结我的系统。我还发现了Ceygen软件包,看起来非常有前途,但似乎安装文件在最后一次Cython更新中破了。 另一方面,我看到scipy正在使用一个用于lapack的cython包装器,但它看起来仍然不可用(scipy-cython-lapack) 最后,我还可以为这些操作编写自己的C例程,但它似乎有点重新发明轮子。

总结一下:在Cython中有这种操作的方法吗? (因此我不认为这是重复的)或者您是否找到了一种更好的方法来处理我还没有看到的这类问题?

强制性代码示例: (这只是一个例子,当然它仍然可以改进,但只是为了提出这个想法)

 cimport numpy as np
 import numpy as np

 cpdef double risk(np.ndarray[double, ndim=2, mode='c'] X,
     np.ndarray[double, ndim=1, mode='c'] v1, 
     np.ndarray[double, ndim=1, mode='c'] v2):

     cdef np.ndarray[double, ndim=2, mode='c'] tmp, sumX
     cdef double ret

     tmp = np.exp(X)
     sumX = np.tile(np.sum(tmp, 1).reshape(-1, 1), (1, tmp.shape[0]))
     tmp = tmp / sumX
     ret = np.inner(v1, np.dot(X, v2))
     return ret

谢谢!

tl; dr:如何在cython中使用线性代数?

2 个答案:

答案 0 :(得分:1)

答案you link to仍然是从Cython调用BLAS函数的好方法。它实际上不是一个python包装器,仅仅使用Python,因此获取指向该函数的C指针,这可以在初始化时完成。所以你应该得到基本上类似C的速度。我可能是错的,但我认为即将推出的Scipy 0.16版本将提供一个方便的BLAS Cython API,基于这种方法,它不会改变性能方面。

如果你在重复调用BLAS函数移植到Cython之后没有经历任何加速,那么在numpy中执行此操作的python开销并不重要(例如,如果计算本身是最昂贵的部分)或者你做错了(不必要的记忆副本等)。

我想说这种方法应该比使用GSL更快更容易维护,前提是您使用优化的BLAS(OpenBLAS,ATLAS,MKL等)编译scipy。

答案 1 :(得分:0)

作为einsum补丁的一部分,我编写了函数c代码的Python模拟。当我在Python中解析字符串时,我使用cython来编写产品总和计算。

pyx位于https://github.com/hpaulj/numpy-einsum/blob/master/sop.pyx

您甚至可以通过Python调用来调用compile einsum模块。比较np.dotnp.einsum有很多SO问题,这对于不同的计算更好。

http://docs.cython.org/src/userguide/memoryviews.html

另请参阅cython memoryviews - 您可以使用这些或cython数组,就像使用numpy数组一样。例如,此文档提到您可以使用[None,:]添加维度。这是否意味着您可以通过广播来制作常见的numpy外部产品?