简单cython-cod的进一步优化

2024-09-29 19:31:38 发布

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

我有一个用cython编写的函数,它通过一个double for循环计算一定的相关性(距离相关性):

%%cython -a
import numpy as np

def distances_Matrix(X):
    return np.array([[np.linalg.norm(xi-xj) for xi in X] for xj in X])

def c_dCov(double[:, :] a, double[:, :] b, int n):
    cdef int i
    cdef int j
    cdef double U       =  0
    cdef double W1      =  n/(n-1)
    cdef double W2      =  2/(n-2)
    cdef double[:] a_M  =  np.mean(a,axis=1)
    cdef double    a_   =  np.mean(a)
    cdef double[:] b_M  =  np.mean(b,axis=1)
    cdef double    b_   =  np.mean(b)

    for i in range(n):
        for j in range(n):
            if i != j:
                U = U + (a[i][j] + W1*(-a_M[i]-a_M[j]+a_)) * (b[i][j] +   W1*(-b_M[i]-b_M[j]+b_))
            else:
                U = U - W2*(W1**2)*(a_M[i] - a_) * (b_M[i] - b_)
    return U/(n*(n-3))

def c_dCor(X,Y):
    n     =  len(X)
    a     =  distances_Matrix(X)
    b     =  distances_Matrix(Y)
    V_XX  =  c_dCov(a,a,n) 
    V_YY  =  c_dCov(b,b,n)
    V_XY  =  c_dCov(a,b,n)
    return V_XY/np.sqrt(V_XX*V_YY)

当我编译这段代码时,我得到了编译器的以下优化报告:

enter image description here

第23行仍然是黄色的,这表示python的交互作用非常显著,我如何使这一行进一步优化?。在

在那一行所做的操作非常简单,只有乘积和和和,因为我确实指定了函数中使用的每个数组和变量的类型,为什么我在那一行得到如此糟糕的性能?在

提前谢谢。在


Tags: 函数inforreturndefnpmeanmatrix
1条回答
网友
1楼 · 发布于 2024-09-29 19:31:38

简而言之:disable bounds checkingc_dCov函数中,在其前面的行上添加以下装饰符:

cimport cython
@cython.boundscheck(False)  # Deactivate bounds checking
def c_dCov(double[:, :] a, double[:, :] b, int n):

或者,可以在代码的顶部添加编译器指令。在你的Cython魔术台词后面你会说:

^{pr2}$

如果有一个setup.py文件,还可以在那里全局关闭边界检查:

from distutils.core import setup
from Cython.Build import cythonize

setup(
    name="foo",
    ext_modules=cythonize('foo.pyx', compiler_directives={'boundscheck': False}),
)

不管是如何完成的,禁用边界检查本身就足以获得以下优化报告:

enter image description here

其他一些optimizations suggested by the Cython docs正在关闭负数索引,并声明保证数组在内存中具有连续布局。通过所有这些优化,c_dCov的签名将变成:

cimport cython
@cython.boundscheck(False)  # Deactivate bounds checking
@cython.wraparound(False)   # Deactivate negative indexing.
def c_dCov(double[:, ::1] a, double[:, ::1] b, int n):

但是只有{}就可以得到更好的优化报告。在

现在我仔细看一下,即使代码片段中没有这些优化,但是在优化报告的代码中确实有boundscheck(False)和{}装饰符。你是不是已经试过了,但没用?你在运行什么版本的Cython?也许你需要升级。在

说明

每次按索引访问数组时,都会进行边界检查。这样,当您有一个形状为(5,5)的数组arr,并且您试图访问arr[19,27]时,程序将发出错误而不是允许您访问越界数据。然而,为了速度,一些语言不做数组访问(如C/C++)的边界检查。Cython允许您选择关闭边界检查以优化性能。使用Cython,可以使用^{} compiler directive全局禁用整个程序的边界检查,也可以使用the ^{} decorator禁用单个函数的边界检查。在

相关问题 更多 >

    热门问题