arrays - 在 Cython 中调用 numpy 函数确实会减慢速度
问题描述
我正在尝试np.random.choice
在二维 numpy 数组中逐行调用,而无需替换。我正在使用 Cython 来提高速度。该代码的运行速度仅比纯 python 实现快 3 倍,这并不是一个很好的结果。瓶颈是 numpy 函数调用本身。当我将其注释掉并仅提供静态结果时,例如[3, 2, 1, 0]
对每一行说,我得到了 1000 倍的加速(当然,它并没有做任何事情:)
我的问题:在调用 numpy 函数时我做错了什么导致它变得超级慢?从理论上讲,它是 C 与 C 对话,所以它应该很快。我查看了编译后的代码,对 numpy 函数的调用看起来很复杂,其中的语句类似于__Pyx_GOTREF
and__Pyx_PyObject_GetAttrStr
让我相信它在过程中使用了纯 python(糟糕!!)。
我的代码:
# tag: numpy
import numpy as np
# compile-time info for numpy
cimport numpy as np
np.import_array()
# array dtypes
W_DTYPE = np.float
C_DTYPE = np.int
cdef int NUM_SELECTIONS = 4 # FIXME should be function kwarg
#compile-time dtypes
ctypedef np.float_t W_DTYPE_t
ctypedef np.int_t C_DTYPE_t
def allocate_choices(np.ndarray[W_DTYPE_t, ndim=2] round_weights,
np.ndarray[C_DTYPE_t, ndim=1] choice_labels):
"""
For ea. row in `round_weights` select NUM_SELECTIONS=4 items among
corresponding `choice_labels`, without replacement, with corresponding
probabilities in `round_weights`.
Args:
round_weights (np.ndarray): 2-d array of weights, w/
size [n_rounds, n_choices]
choice_labels (np.ndarray): 1-d array of choice labels,
w/ size [n_choices]; choices must be *INTEGERS*
Returns:
choices (np.ndarray): selected items per round, w/ size
[n_rounds, NUM_SELECTIONS]
"""
assert round_weights.dtype == W_DTYPE
assert choice_labels.dtype == C_DTYPE
assert round_weights.shape[1] == choice_labels.shape[0]
# initialize final choices array
cdef int n_rows = round_weights.shape[0]
cdef np.ndarray[C_DTYPE_t, ndim=2] choices = np.zeros([n_rows, NUM_SELECTIONS],
dtype=C_DTYPE)
# Allocate choices, per round
cdef int i, j
cdef bint replace = False
for i in range(n_rows):
choices[i] = np.random.choice(choice_labels,
NUM_SELECTIONS,
replace,
round_weights[i])
return choices
解决方案
在与一些人聊天并检查编译的代码之后对此进行更新:@DavidW 上面的评论说得很好:
“理论上它是 C 与 C 交谈,所以它应该很快” - 不。不对。cimport numpy 提供直接访问的 Numpy 的主要部分只是更快的数组索引。使用正常的 Python 机制调用 Numpy 函数。它们最终可能会在 C 中实现,但从 Cython 的角度来看,这并没有提供捷径。
所以这里的问题是,调用这个 Numpy 函数需要将输入转换回 python 对象,将它们传入,然后让 numpy 做它的事情。我不认为所有 Numpy 函数都是这种情况(从计时实验来看,其中一些我称之为工作很快),但很多都不是“Cythonized”。
推荐阅读
- python - 使用新标量更新 PyVista 绘图仪
- html - 如何在 .md (markdown) 文件中输入多个空格,以便转换后的 html 显示相同数量的空格?
- c# - unity c# 问题无法使用 transform.position 在统一 c# 脚本中获得敌人的完美位置
- debugging - 我可以从 c++ 中 Visual Studio 的调试器进程中排除内存中的特定数据(结构/向量/等)吗?
- java - 如何使用杰克逊从纯字符串反序列化 Map?
- javascript - “this”关键字在 JavaScript 中前面带有 + 是什么意思
- php - 应用程序未注册用户的 DB 存储设备密钥在哪里
- alexa-skills-kit - 如何在 Alexa 技能中将 axios 模块导入 Alexa Node js 代码。我正在使用 alexa 技能
- javascript - 在第一次渲染时,控制台日志上的数据显示为空
- slack - Slack Web 浏览器和应用程序未在 Ubuntu 上加载