我有一个用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)
编译这段代码时,编译器会收到以下优化报告:
第23行仍然是黄色,表明存在重大的python交互作用,如何使该行进一步优化?。
在那条线上完成的操作非常简单,只是乘积和求和,因为我确实指定了该函数中使用的每个数组和变量的类型,为什么我在那条线上表现不佳?
谢谢。
答案 0 :(得分:1)
简短答案:c_dCov
函数中的disable bounds checking,方法是在其前面的行上添加以下修饰符:
cimport cython
@cython.boundscheck(False) # Deactivate bounds checking
def c_dCov(double[:, :] a, double[:, :] b, int n):
或者,您可以在代码顶部添加一个编译器指令。在您的Cython魔术线之后,您会输入:
%%cython -a
#cython: language_level=3, boundscheck=False
如果您有一个setup.py
文件,则还可以在此处全局禁用边界检查:
from distutils.core import setup
from Cython.Build import cythonize
setup(
name="foo",
ext_modules=cythonize('foo.pyx', compiler_directives={'boundscheck': False}),
)
无论如何完成,仅通过禁用边界检查就足以获取以下优化报告:
另一些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):
但只需要@cython.boundscheck(False)
即可获得更好的优化报告。
现在,尽管您在代码片段中没有进行这些优化,但现在我看起来更近了,但是在优化报告的代码中确实有boundscheck(False)
和wraparound(False)
装饰器。您是否已经尝试过这些并且它们没有起作用?您正在运行什么版本的Cython?也许您需要升级。
每次通过索引访问数组时,都会进行边界检查。这样,当您拥有形状为arr
的数组(5,5)
并尝试访问arr[19,27]
时,程序将吐出一个错误,而不是让您访问边界数据。但是,为了提高速度,某些语言不对数组访问进行边界检查(例如C / C ++)。 Cython使您可以选择关闭边界检查,以优化性能。使用Cython,您可以使用boundscheck
compiler directive禁用整个程序的全局边界检查,或者使用the @cython.boundscheck(False)
decorator禁用单个函数的边界检查。