- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我在这里有一个简单的例子来帮助我理解使用 numba 和 cython。我是 numba 和 cython 的新手。我已经尽力结合所有技巧来使 numba 更快,并且在某种程度上,cython 也是如此,但我的 numpy 代码几乎比 numba 快 2 倍(对于 float64),如果使用 float32,则快 2 倍以上。不确定我在这里缺少什么。
我在想也许问题不再是编码,而是更多关于编译器之类的,我不太熟悉。
我浏览了很多关于 numpy、numba 和 cython 的 stackoverflow 帖子,但没有找到直接的答案。
numpy 版本:
def py_expsum(x):
return np.sum( np.exp(x) )
@numba.jit( nopython=True)
def nb_expsum(x):
nx, ny = x.shape
val = 0.0
for ix in range(nx):
for iy in range(ny):
val += np.exp(x[ix, iy])
return val
import numpy as np
import cython
from libc.math cimport exp
@cython.boundscheck(False)
@cython.wraparound(False)
cpdef double cy_expsum2 ( double[:,:] x, int nx, int ny ):
cdef:
double val = 0.0
int ix, iy
for ix in range(nx):
for iy in range(ny):
val += exp(x[ix, iy])
return val
float64 / float32
1. numpy : 0.56 sec / 0.23 sec
2. numba : 0.93 sec / 0.74 sec
3. cython: 0.83 sec
最佳答案
正如我们将看到的,行为取决于使用的 numpy-distribution。
这个答案将集中在 Anacoda-distribution 与 Intel 的 VML(矢量数学库),考虑到另一个硬件和 numpy 版本,millage 可能会有所不同。
还将展示如何通过 Cython 或 numexpr
使用 VML。 ,以防万一不使用 Anacoda-distribution,它会在引擎盖下插入 VML 以进行一些 numpy 操作。
对于以下维度,我可以重现您的结果
N,M=2*10**4, 10**3
a=np.random.rand(N, M)
%timeit py_expsum(a) # 87ms
%timeit nb_expsum(a) # 672ms
%timeit nb_expsum2(a) # 412ms
exp
- 函数,正如我们将看到的,它是一项 CPU 密集型任务。
top
-statistics 显示,numpy 的版本是并行执行的,但 numba 的情况并非如此。但是,在我只有两个处理器的 VM 上,仅靠并行化无法解释因子 7 的巨大差异(如 DavidW 的版本
nb_expsum2
所示)。
perf
分析代码两个版本都显示以下内容:
nb_expsum
Overhead Command Shared Object Symbol
62,56% python libm-2.23.so [.] __ieee754_exp_avx
16,16% python libm-2.23.so [.] __GI___exp
5,25% python perf-28936.map [.] 0x00007f1658d53213
2,21% python mtrand.cpython-37m-x86_64-linux-gnu.so [.] rk_random
py_expsum
31,84% python libmkl_vml_avx.so [.] mkl_vml_kernel_dExp_E9HAynn ▒
9,47% python libiomp5.so [.] _INTERNAL_25_______src_kmp_barrier_cpp_38a91946::__kmp_wait_te▒
6,21% python [unknown] [k] 0xffffffff8140290c ▒
5,27% python mtrand.cpython-37m-x86_64-linux-gnu.so [.] rk_random
lm.so
) 中的版本那件事)。可以通过使用并行化稍微平整地面,但 mkl 的矢量化版本仍然优于 numba 和 cython。
exp
(至于其他超越函数)有两个维度需要考虑:
x
-value,需要不同的时间来计算exp(x)
.通常有三种不同类型的输入导致不同的计算时间:非常小、正常和非常大(具有非有限结果)<= 8192 = 2^13
numpy 使用 exp 的非并行 glibc 版本(也使用相同的 numba 和 cython)。 vdExp
来自英特尔的 VML(如评论中部分建议的那样),因为它计算
exp(x)
单独,而 VML 对整个数组进行操作。
vdExp
在适合缓存的一部分数据上,但也不太小(开销)。 %%cython -L=<path_mkl_libs> --link-args=-Wl,-rpath=<path_mkl_libs> --link-args=-Wl,--no-as-needed -l=mkl_intel_ilp64 -l=mkl_core -l=mkl_gnu_thread -l=iomp5
# path to mkl can be found via np.show_config()
# which libraries needed: https://software.intel.com/en-us/articles/intel-mkl-link-line-advisor
# another option would be to wrap mkl.h:
cdef extern from *:
"""
// MKL_INT is 64bit integer for mkl-ilp64
// see https://software.intel.com/en-us/mkl-developer-reference-c-c-datatypes-specific-to-intel-mkl
#define MKL_INT long long int
void vdExp(MKL_INT n, const double *x, double *y);
"""
void vdExp(long long int n, const double *x, double *y)
def cy_expsum(const double[:,:] v):
cdef:
double[1024] w;
int n = v.size
int current = 0;
double res = 0.0
int size = 0
int i = 0
while current<n:
size = n-current
if size>1024:
size = 1024
vdExp(size, &v[0,0]+current, w)
for i in range(size):
res+=w[i]
current+=size
return res
numexpr
会做,它也使用英特尔的 vml 作为后端:
import numexpr as ne
def ne_expsum(x):
return ne.evaluate("sum(exp(x))")
import numpy as np
def py_expsum(x):
return np.sum(np.exp(x))
import numba as nb
@nb.jit( nopython=True)
def nb_expsum(x):
nx, ny = x.shape
val = 0.0
for ix in range(nx):
for iy in range(ny):
val += np.exp( x[ix, iy] )
return val
@nb.jit( nopython=True, parallel=True)
def nb_expsum2(x):
nx, ny = x.shape
val = 0.0
for ix in range(nx):
for iy in nb.prange(ny):
val += np.exp( x[ix, iy] )
return val
import perfplot
factor = 1.0 # 0.0 or 1e4
perfplot.show(
setup=lambda n: factor*np.random.rand(1,n),
n_range=[2**k for k in range(0,27)],
kernels=[
py_expsum,
nb_expsum,
nb_expsum2,
],
logx=True,
logy=True,
xlabel='len(x)'
)
关于python - numpy 比 numba 和 cython 快,如何改进 numba 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56920713/
作为脚本的输出,我有 numpy masked array和标准numpy array .如何在运行脚本时轻松检查数组是否为掩码(具有 data 、 mask 属性)? 最佳答案 您可以通过 isin
我的问题 假设我有 a = np.array([ np.array([1,2]), np.array([3,4]), np.array([5,6]), np.array([7,8]), np.arra
numpy 是否有用于矩阵模幂运算的内置实现? (正如 user2357112 所指出的,我实际上是在寻找元素明智的模块化减少) 对常规数字进行模幂运算的一种方法是使用平方求幂 (https://en
我已经在 Numpy 中实现了这个梯度下降: def gradientDescent(X, y, theta, alpha, iterations): m = len(y) for i
我有一个使用 Numpy 在 CentOS7 上运行的项目。 问题是安装此依赖项需要花费大量时间。 因此,我尝试 yum install pip install 之前的 numpy 库它。 所以我跑:
处理我想要旋转的数据。请注意,我仅限于 numpy,无法使用 pandas。原始数据如下所示: data = [ [ 1, a, [, ] ], [ 1, b, [, ] ], [ 2,
numpy.random.seed(7) 在不同的机器学习和数据分析教程中,我看到这个种子集有不同的数字。选择特定的种子编号真的有区别吗?或者任何数字都可以吗?选择种子数的目标是相同实验的可重复性。
我需要读取存储在内存映射文件中的巨大 numpy 数组的部分内容,处理数据并对数组的另一部分重复。整个 numpy 数组占用大约 50 GB,我的机器有 8 GB RAM。 我最初使用 numpy.m
处理我想要旋转的数据。请注意,我仅限于 numpy,无法使用 pandas。原始数据如下所示: data = [ [ 1, a, [, ] ], [ 1, b, [, ] ], [ 2,
似乎 numpy.empty() 可以做的任何事情都可以使用 numpy.ndarray() 轻松完成,例如: >>> np.empty(shape=(2, 2), dtype=np.dtype('d
我在大型 numpy 数组中有许多不同的形式,我想使用 numpy 和 scipy 计算它们之间的边到边欧氏距离。 注意:我进行了搜索,这与堆栈中之前的其他问题不同,因为我想获得数组中标记 block
我有一个大小为 (2x3) 的 numpy 对象数组。我们称之为M1。在M1中有6个numpy数组。M1 给定行中的数组形状相同,但与 M1 任何其他行中的数组形状不同。 也就是说, M1 = [ [
如何使用爱因斯坦表示法编写以下点积? import numpy as np LHS = np.ones((5,20,2)) RHS = np.ones((20,2)) np.sum([ np.
假设我有 np.array of a = [0, 1, 1, 0, 0, 1] 和 b = [1, 1, 0, 0, 0, 1] 我想要一个新矩阵 c 使得如果 a[i] = 0 和 b[i] = 0
我有一个形状为 (32,5) 的 numpy 数组 batch。批处理的每个元素都包含一个 numpy 数组 batch_elem = [s,_,_,_,_] 其中 s = [img,val1,val
尝试为基于文本的多标签分类问题训练单层神经网络。 model= Sequential() model.add(Dense(20, input_dim=400, kernel_initializer='
首先是一个简单的例子 import numpy as np a = np.ones((2,2)) b = 2*np.ones((2,2)) c = 3*np.ones((2,2)) d = 4*np.
我正在尝试平均二维 numpy 数组。所以,我使用了 numpy.mean 但结果是空数组。 import numpy as np ws1 = np.array(ws1) ws1_I8 = np.ar
import numpy as np x = np.array([[1,2 ,3], [9,8,7]]) y = np.array([[2,1 ,0], [1,0,2]]) x[y] 预期输出: ar
我有两个数组 A (4000,4000),其中只有对角线填充了数据,而 B (4000,5) 填充了数据。有没有比 numpy.dot(a,b) 函数更快的方法来乘(点)这些数组? 到目前为止,我发现
我是一名优秀的程序员,十分优秀!