Python 用Cython优化numpy.dot

Python 用Cython优化numpy.dot,python,numpy,cython,dot-product,Python,Numpy,Cython,Dot Product,我想使用Cython优化以下代码: sim = numpy.dot(v1, v2) / (sqrt(numpy.dot(v1, v1)) * sqrt(numpy.dot(v2, v2))) dist = 1-sim return dist 我已经编写并编译了.pyx文件,当我运行代码时,我没有看到任何性能上的显著改进。根据Cython文档,我必须添加c_类型。Cython生成的HTML文件表明瓶颈是dot产品(当然这是预期的)。这是否意味着我必须为点积定义一个C函数?如果是,我怎么做 编辑

我想使用Cython优化以下代码:

sim = numpy.dot(v1, v2) / (sqrt(numpy.dot(v1, v1)) * sqrt(numpy.dot(v2, v2))) 
dist = 1-sim
return dist
我已经编写并编译了.pyx文件,当我运行代码时,我没有看到任何性能上的显著改进。根据Cython文档,我必须添加c_类型。Cython生成的HTML文件表明瓶颈是dot产品(当然这是预期的)。这是否意味着我必须为点积定义一个C函数?如果是,我怎么做

编辑:

经过一些研究,我得出了以下代码。这种改善只是微不足道的。我不确定我是否可以做些什么来改进它:

from __future__ import division
import numpy as np
import math as m
cimport numpy as np
cimport cython

cdef extern from "math.h":
    double c_sqrt "sqrt"(double)

ctypedef np.float reals #typedef_for easier readding

cdef inline double dot(np.ndarray[reals,ndim = 1] v1, np.ndarray[reals,ndim = 1] v2):
  cdef double result = 0
  cdef int i = 0
  cdef int length = v1.size
  cdef double el1 = 0
  cdef double el2 = 0
  for i in range(length):
    el1 = v1[i]
    el2 = v2[i]
    result += el1*el2
  return result

@cython.cdivision(True)
def distance(np.ndarray[reals,ndim = 1] ex1, np.ndarray[reals,ndim = 1] ex2):
  cdef double dot12 = dot(ex1, ex2)
  cdef double dot11 = dot(ex1, ex1)
  cdef double dot22 = dot(ex2, ex2)
  cdef double sim = dot12 / (c_sqrt(dot11 * dot22))
  cdef double dist = 1-sim    
  return dist 

您可以更改表达式

sim = numpy.dot(v1, v2) / (sqrt(numpy.dot(v1, v1)) * sqrt(numpy.dot(v2, v2))) 


一般来说,如果您从cython内部调用numpy函数,并且很少做其他事情,那么您通常只会看到边际收益(如果有的话)。通常,只有在python级别静态键入使用显式for循环的代码时(而不是在已经调用Numpy C-API的代码中),才能获得巨大的速度提升


您可以尝试使用计数器的所有静态类型、输入numpy数组等编写点积的代码,将wrapparound和boundscheck设置为False,导入
sqrt
函数的clib版本,然后尝试利用并行for循环(
prange
)来使用openmp

嘿,你说得对。我应该注意到这一点。然而,我只是尝试了一下,仍然没有明显的改善!但关键是要设法在cython中运行它,看看最近这个非常类似的问题:这就是我到目前为止发现的。我试试你的建议。谢谢,也许我误解了你的评论。你是说我现在的代码不能用Cython更快,还是说如果我只使用编译好的Cython代码而不使用任何静态类型,那么我就不会有任何收获?请看一下我在问题中修改的代码!我不确定我是否应该这样做。@georgeeracleus我想说的是,你最初的代码从cython内部调用了
np.dot
,它不应该得到任何大的加速。你发布的新代码更像我想象的那样。请注意(1)我不确定您的
dot
实现是否适合内联。(2) 由于要在numpy数组上循环,我建议使用
boundscheck
wrapparound
装饰器,并将它们设置为
False
。(3) 在setup.py文件中,确保使用了优化标志(例如,
-O3
)。不过,一般来说,如果针对BLAS或MKL编译,numpy的
将得到高度优化
sim = numpy.dot(v1, v2) / sqrt(numpy.dot(v1, v1) * numpy.dot(v2, v2))