- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在编写一个函数,我想使用 Cython 尽可能多地将其转换为 C。为此,我需要使用线性代数运算。这是我的功能。 编辑:我学到的教训是尝试在循环之外处理线性代数,这在很大程度上是我能够做到的。否则,求助于包装 LAPACK/BLAS 或编写我自己的函数。
import numpy as np
from scipy.stats import multivariate_normal as mv
import itertools
def llf(data, rho, mu, sigma, A, V, n):
'''evaluate likelihood by guass-hermite quadrature
Parameters
----------
data : array
N x J matrix, columns are measurements
rho : array
length L vector of weights for mixture of normals
mu : array
L x K vector of means of mixture of normals
sigma : array
K x L*K matrix of variance matrices for mixture of normals
A : array
J x (K + 1) matrix of loadings
V : array
J x J variance matrix of measurement errors
n : int
number of sample points for quadrature
'''
N = data.shape[0]
L, K = mu.shape
# getting weights and sample points for approximating integral
v, w = np.polynomial.hermite.hermgauss(n)
totllf = 0
for i in range(N):
M_i = data[i, :]
totllf_i = 0
for l in range(L):
rho_l = rho[l]
sigma_l = sigma[:, K*l:K*(l+1)]
mu_l = mu[l, :]
chol_l = np.linalg.cholesky(sigma_l)
for ix in itertools.product(*(list(range(n)) for k in range(K))):
wt = np.prod(w[list(ix)])
pt = np.sqrt(2)*chol_l.dot(v[list(ix)]) + mu_l
totllf_i += wt*rho_l*mv.pdf(M_i, A[:, 0] + A[:, 1:].dot(pt), V)
totllf += np.log(totllf_i)
return totllf
为了完成这个,我需要有矩阵乘法、转置、行列式、矩阵求逆和 cholesky 分解的函数。我看过some posts关于使用 BLAS
函数,但我真的不清楚如何使用这些函数。
编辑 2018 年 4 月 29 日
按照建议,我采用了内存 View 方法并在循环之前初始化了所有内容。我的新函数写成
def llf_c(double[:, ::1] data, double[::1] rho, double[:, ::1] mu,
double[:, ::1] sigma, double[:, ::1] A, double[:, ::1] V, int n):
'''evaluate likelihood by guass-hermite quadrature
Parameters
----------
data : array
N x J matrix, columns are measurements
rho : array
length L vector of weights for mixture of normals
mu : array
L x K vector of means of mixture of normals
sigma : array
K x L*K matrix of variance matrices for mixture of normals
A : array
J x (K + 1) matrix of loadings
V : array
J x J variance matrix of measurement errors
n : int
number of sample points for quadrature
'''
cdef Py_ssize_t N = data.shape[0], J = data.shape[1], L = mu.shape[0], K = mu.shape[1]
# initializing indexing variables
cdef Py_ssize_t i, l, j, k
# getting weights and sample points for approximating integral
v_a, w_a = np.polynomial.hermite.hermgauss(n)
cdef double[::1] v = v_a
cdef double[::1] w = w_a
cdef double[::1] v_ix = np.zeros(K, dtype=np.float)
# initializing memory views for cholesky decomposition of sigma matrices
sigma_chol_a = np.zeros((K, L*K), dtype=np.float)
for l in range(L):
sigma_chol_a[:, K*l:K*(l+1)] = np.linalg.cholesky(sigma[:, K*l:K*(l+1)])
cdef double[:, ::1] sigma_chol = sigma_chol_a
# intializing V inverse and determinant
cdef double[:, ::1] V_inv = np.linalg.inv(V)
cdef double V_det = np.linalg.det(V)
# initializing memoryviews for work matrices
cdef double[::1] work_K = np.zeros(K, dtype=np.float)
cdef double[::1] work_J = np.zeros(J, dtype=np.float)
# initializing memoryview for quadrature points
cdef double[::1] pt = np.zeros(K, dtype=np.float)
# initializing memorview for means for multivariate normal
cdef double[::1] loc = np.zeros(J, dtype=np.float)
# initializing values for loop
cdef double[::1] totllf = np.zeros(N, dtype=np.float)
cdef double wt, pdf_init = 1./sqrt(((2*pi)**J)*V_det)
cdef int[:, ::1] ix_vals = np.vstack(itertools.product(*(list(range(n)) for k in range(K)))).astype(np.int32)
cdef Py_ssize_t ix_len = ix_vals.shape[0]
for ix_row in range(ix_len):
ix = ix_vals[ix_row]
# weights and points for quadrature
wt = 1.
for k in range(K):
wt *= w[ix[k]]
v_ix[k] = v[ix[k]]
for l in range(L):
# change of variables
dotmv_c(sigma_chol[:, K*l:K*(l+1)], v_ix, work_K)
for k in range(K):
pt[k] = sqrt(2)*work_K[k]
addvv_c(pt, mu[l, :], pt)
for i in range(N):
# generating demeaned vector for multivariate normal pdf
dotmv_c(A[:, 1:], pt, work_J)
addvv_c(A[:, 0], work_J, work_J)
for j in range(J):
loc[j] = data[i, j] - work_J[j]
# performing matrix products in exponential
# print(wt, rho[l], np.asarray(work_J))
dotvm_c(loc, V_inv, work_J)
totllf[i] += wt*rho[l]*pdf_init*exp(-0.5*dotvv_c(work_J, loc))
return np.log(np.asarray(totllf)).sum()
dotvm_c
、dotmv_c
和addvv_c
是执行向量与矩阵、矩阵与向量的矩阵乘法以及两者的逐元素加法的函数向量。我也在 Cython 中编写了这些,但为简洁起见不包括在内。我不再像在使用 numpy 循环之前处理所有其他线性代数那样包装任何 LAPACK 函数。我还有几个问题。为什么我的循环中仍然有黄色? (见下面的简介)。我认为现在一切都应该在 C 中。此外,如果您对新实现有任何其他建议,请告诉我。
例如,在第 221 行,我在编译时收到此消息:“应键入索引以提高访问效率。”但我以为我输入了索引 k。此外,由于 addvv_c
以黄色显示,我将在下面向您展示它的定义。
cpdef void addvv_c(double[:] a, double[:] b, double[:] out):
'''add two vectors elementwise
'''
cdef Py_ssize_t i, n = a.shape[0]
for i in range(n):
out[i] = a[i] + b[i]
最佳答案
关于您优化的 Cython/BLAS 函数的一些小问题:
ipiv_a = np.zeros(n).astype(np.int32)
cdef int[::1] ipiv = ipiv_a
可以有两个简单的改进:它不必通过一个临时变量,你可以直接创建一个类型为 np.int32
的数组,而不是创建一个不同类型的数组然后类型转换:
cdef int[::1] ipiv = np.zeros(n,dtype=np.int32)
同样,在这两个函数中,您可以通过以下步骤以更少的步骤初始化B
cdef double[:, ::1] B = A.copy()
而不是创建一个零数组并复制
第二个(更重要的)变化是 to use C arrays用于临时变量,例如 Fortran 工作区。我仍然会将返回值之类的东西保留为 numpy 数组,因为引用计数和将它们发送回 Python 的能力非常很有用。
cdef double* work = <double*>malloc(n*n*sizeof(double))
try:
# rest of function
finally:
free(work)
您需要从 libc.stdlib
导入 malloc
和 free
。 try: ... finally:
确保正确释放内存。不要太过头了 - 例如,如果在何处释放 C 数组并不明显,那么只需使用 numpy。
要查看的最后一个选项是没有返回值但修改输入:
cdef void inv_c(double[:,::1] A, double[:,::1] B):
# check that A and B are the right size, then just write into B
# ...
这样做的好处是,如果您需要在具有相同大小输入的循环中调用它,那么您只需为整个循环进行一次分配。您可以将其扩展为也包括工作数组,尽管这可能会稍微复杂一些。
关于python - cython 中没有 python 对象的高效矩阵运算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50034761/
c 不做边界检查。那么cython是如何检查是否编译成c的呢? %%cython --annotate cimport cython @cython.boundscheck(True) cpdef m
可以直接声明用于 Cython 构造函数? 据我了解,这是可能的: # Cython cdef int[3] li = [1, 2, 3] # C++ int[3] li = {1, 2, 3} 但
所以,如果你有一个头文件。 %%file test.h struct mystruct{ int i; int j; }; 然后你将它包装在 Cython 中: cdef extern fr
我正在构建一个独立于平台的 cython 项目,我想根据正在使用的编译器传递编译器参数。我可以猜测基于平台的编译器,或者假设它与用于 Python 的编译器相同,但不能保证匹配。通常我注入(injec
我使用诗歌构建我的 cython 包。我在所有函数和类中都有 NumPy 风格的文档字符串。我现在要做的是添加 Sphinx 自动文档并发布在 Read the Docs。 我已阅读此主题 How d
赛通 libcpp模块包含 priority_queue 的模板,这很好,除了一件事:我不能通过自定义比较器(或者,至少,我不知道如何)。 我需要这个,因为我需要 priority_queue做一个a
以下代码定义了一个简单的 Cython 函数(为方便起见,使用 Ipython 魔法)。 %load_ext cython %%cython def f(float x, float y=2):
我正在尝试使用 cython 进行复数计算。在示例代码中,我想计算复数的复指数函数。问题是我不知道如何将我的整数乘以虚数单位。python的虚数单位1.0j乘以cython执行时报错。 这是我的代码:
在这里停留在一些基本的 Cython 上 - 在 Cython 中定义字符串数组的规范且有效的方法是什么? 具体来说,我想定义一个定长常量数组char . (请注意,此时我不想引入 NumPy。) 在
是否有可能,如果是,如何确定 Cython 中整数数据类型的大小(以位为单位)? 我正在尝试做这样的事情,以获得整数大小: cdef WORD_BITS = 0 IF sizeof(unsigned
我只是想打印 cython 变量的地址,但我无法绕过错误消息: cdef int myvar print &myvar 抛出 Cannot convert 'int *' to Python obje
我有一个 C 头文件,它在宏中定义了一个函数。我需要从 Cython 调用它。有没有办法在 Cython 中使用宏并使其完全扩展?我已经有了 C 类型的参数。 我尝试像使用函数一样使用 cdef,我认
令人惊讶的是,我似乎找不到通过名称获取结构体元素的单个示例(无论是在网络上还是在 cython 示例中)。 所以我收到了一个指向 C 函数结构体的指针,并且想要一一访问这些元素并将它们重新打包到 py
我尝试围绕 C++ 库编写一个 Cython 包装器 http://primesieve.org/ 它包装了一个函数count。到目前为止,它可以正确安装 python setup.py instal
我正在尝试将 cython 模块 data.pyx 导入另一个 cython 模块 user.pyx。一切都编译得很好,但是当我尝试在 python 模块中调用 user.pyx 时,我收到错误“Im
更新:内存 View 获胜。Cython 使用类型化内存 View :0.0253449 特别感谢 lothario,他指出了几个关键的变化。 荒谬。当然现在的问题是,似乎不能对它们做太多算术(加法和
我有一个使用 memoryview 数组的 cython 模块,即... double[:,:] foo 我想使用多处理并行运行这个模块。但是我得到了错误: PicklingError: Can't
我正在尝试使用 Cython 加速 PEP 484 类型的 python 脚本。我想保持一些语义和可读性。 之前,我有一个 Flags = int def difference(f1: Flags,
这个问题已经有答案了: Collapse multiple submodules to one Cython extension (5 个回答) 已关闭 3 年前。 我在一个包中有多个 .py 文件
我已经能够在我的 .pyx 脚本上使用 cython 在 linux 上创建一个 .so 文件。我也可以成功地在我的 python 解释器上进行导入。 我的问题是如何在不使用 cython 的情况下将
我是一名优秀的程序员,十分优秀!