【问题标题】:Optimizing numpy.dot with Cython使用 Cython 优化 numpy.dot
【发布时间】:2012-05-28 17:15:34
【问题描述】:

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

sim = numpy.dot(v1, v2) / (sqrt(numpy.dot(v1, v1)) * sqrt(numpy.dot(v2, v2))) 
dist = 1-sim
return dist

我已经编写并编译了 .pyx 文件,当我运行代码时,我没有看到任何显着的性能改进。根据 Cython 文档,我必须添加 c_types。 Cython 生成的 HTML 文件表明瓶颈是点积(这当然是意料之中的)。这是否意味着我必须为点积定义一个 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 

【问题讨论】:

标签: python numpy cython dot-product


【解决方案1】:

作为一般说明,如果您从 cython 中调用 numpy 函数并且几乎不做其他事情,那么您通常只会看到边际收益(如果有的话)。如果您静态键入在 python 级别使用显式 for 循环的代码(而不是在已经调用 Numpy C-API 的东西中),您通常只会获得巨大的加速。

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

【讨论】:

  • 这就是我目前发现的。我会试试你的建议。谢谢
  • 也许我误解了你的评论。您是否建议不能使用 Cython 使我的代码变得更快,或者您的意思是如果我只使用编译后的 Cython 代码而不使用任何静态类型,那么我不会有任何收获?请看一下我在问题中修改后的代码!我不确定我是否应该这样做。
  • @GeorgeEracleous 我想说的是,您在 cython 中调用 np.dot 的原始代码预计不会获得任何形式的大幅加速。您发布的新代码更像是我想象中的尝试。请注意 (1) 我不确定您的 dot 实现是否适合内联。 (2) 由于您正在循环一个 numpy 数组,我建议使用 boundscheckwraparound 装饰器并将它们设置为 False。 (3) 在你的 setup.py 文件中,确保你使用了优化标志(例如-O3)。
  • 一般来说,如果针对 BLAS 或 MKL 编译,numpy 的 dot 将得到高度优化
【解决方案2】:

你可以改变表达方式

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

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

【讨论】:

  • 嘿,你是对的。我应该注意到这一点。但是,我刚刚尝试过,仍然没有明显的改善!但关键是设法在 cython anw 中运行它
猜你喜欢
  • 2011-07-16
  • 2016-11-02
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 2020-04-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多