与 CPython 相比,Numba 和 Cython 并没有显着提高性能,也许我使用不正确?
Posted
技术标签:
【中文标题】与 CPython 相比,Numba 和 Cython 并没有显着提高性能,也许我使用不正确?【英文标题】:Numba and Cython aren't improving the performance compared to CPython significantly, maybe I am using it incorrectly? 【发布时间】:2014-06-26 08:37:51 【问题描述】:大编辑:
=================
为了清楚起见,我将删除旧结果并用更新的结果替换它。问题还是一样:我是否正确使用了 Cython 和 Numba,可以对代码进行哪些改进? (我有一个更新、更简单的临时 IPython 笔记本,其中包含所有代码和结果 here)
1)
我想我明白了为什么 Cython、Numba 和 CPython 之间最初没有区别:这是因为我喂了它们
numpy 数组作为输入:
x = np.asarray([x_i*np.random.randint(8,12)/10 for x_i in range(n)])
而不是列表:
x = [x_i*random.randint(8,12)/10 for x_i in range(n)]
使用 Numpy 数组作为数据输入的基准测试
使用 Python 列表作为输入进行基准测试
2)
我用显式循环替换了zip()
函数,然而,它并没有太大的不同。代码是:
CPython
def py_lstsqr(x, y):
""" Computes the least-squares solution to a linear matrix equation. """
len_x = len(x)
x_avg = sum(x)/len_x
y_avg = sum(y)/len(y)
var_x = 0
cov_xy = 0
for i in range(len_x):
temp = (x[i] - x_avg)
var_x += temp**2
cov_xy += temp*(y[i] - y_avg)
slope = cov_xy / var_x
y_interc = y_avg - slope*x_avg
return (slope, y_interc)
赛通
%load_ext cythonmagic
%%cython
def cy_lstsqr(x, y):
""" Computes the least-squares solution to a linear matrix equation. """
cdef double x_avg, y_avg, var_x, cov_xy,\
slope, y_interc, x_i, y_i
cdef int len_x
len_x = len(x)
x_avg = sum(x)/len_x
y_avg = sum(y)/len(y)
var_x = 0
cov_xy = 0
for i in range(len_x):
temp = (x[i] - x_avg)
var_x += temp**2
cov_xy += temp*(y[i] - y_avg)
slope = cov_xy / var_x
y_interc = y_avg - slope*x_avg
return (slope, y_interc)
麻木
from numba import jit
@jit
def numba_lstsqr(x, y):
""" Computes the least-squares solution to a linear matrix equation. """
len_x = len(x)
x_avg = sum(x)/len_x
y_avg = sum(y)/len(y)
var_x = 0
cov_xy = 0
for i in range(len_x):
temp = (x[i] - x_avg)
var_x += temp**2
cov_xy += temp*(y[i] - y_avg)
slope = cov_xy / var_x
y_interc = y_avg - slope*x_avg
return (slope, y_interc)
【问题讨论】:
对于您的第一个示例,我不希望 numba 产生重大收益,因为无论如何您都是在 numpy 中进行所有计算。 从 Numba 页面上的示例中,我希望它可能会加速在 numpy 结构上使用 Python 代码循环的代码,但是您的示例除了调用已经用 C 编写的 numpy 函数之外什么都不做. 我对 Numba 了解不多,但我猜您将无法加快您的第一个示例的速度。第二个示例缺乏加速有点令人惊讶,我们将看看是否有更了解 Numba 的人回复。 顺便说一句,很棒的存储库。 谢谢,但 np.linalg.lstsq 实际上更慢!最快的方法是在 Cython 中实现“经典”方法。我已经完成了基准 Cython vs. numpy (np.linalg.lstsq) vs. scipy (scipy.stats.linregress) here @SebastianRaschka:是的,也许我不清楚。 “你的第一个例子”是指py_mat_lstsqr
和numba_mat_lstsqr
之间的比较(这并不让我感到惊讶)。但我所说的“你的第二个例子”是numba_lstsqr
和py_lstsqr
之间的比较(这让我很惊讶)。谷歌搜索,我看到有人说 Numba 无法推断某些函数中的类型,因此没有加速,但我对 Numba 的了解还不够,不知道这里发生了什么,或者如何改进它。
【参考方案1】:
以下是我认为 Numba 正在发生的事情:
Numba 适用于 Numpy
数组。没有其他的。其他一切都与Numba
无关。
zip
返回 Numba 无法看到的任意项的迭代器。因此,Numba 无法进行太多编译。
使用for i in range(...)
遍历索引可能会产生更好的结果并允许更强大的类型推断。
【讨论】:
谢谢!我将重写它并在本周末重做基准测试。我会告诉你结果的! zip 没有做那么多......我现在替换了它,但真正的问题是我作为输入传递的 numpy 数组。 据我了解,并不是说 Numba 无法看到 Numpy 之外的任何东西,而是它处理此类事情的方式并没有改进。查看 Numba - Tell Those C++ Bullies to Get Lost 了解很多 Numba 的精彩解释。【参考方案2】:使用内置 sum() 可能会导致问题。
这是在 Numba 中运行速度更快的线性回归代码:
@numba.jit
def ols(x, y):
"""Simple OLS for two data sets."""
M = x.size
x_sum = 0.
y_sum = 0.
x_sq_sum = 0.
x_y_sum = 0.
for i in range(M):
x_sum += x[i]
y_sum += y[i]
x_sq_sum += x[i] ** 2
x_y_sum += x[i] * y[i]
slope = (M * x_y_sum - x_sum * y_sum) / (M * x_sq_sum - x_sum**2)
intercept = (y_sum - slope * x_sum) / M
return slope, intercept
【讨论】:
以上是关于与 CPython 相比,Numba 和 Cython 并没有显着提高性能,也许我使用不正确?的主要内容,如果未能解决你的问题,请参考以下文章
与 Python+Numba LLVM/JIT 编译的代码相比,Julia 的性能
与纯 Python 代码相比,Numba njit 编译器会导致计算不同的数字?
如何使 numba @jit 使用所有 cpu 内核(并行化 numba @jit)
一行代码实现Python运行性能增强百倍,性能发动机numba模块介绍