- 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/
我想将一个类对象传递给一个函数。我可以让它工作,但我想知道是否有我可以分配的类型?我有一个我正在尝试做的“最小”示例。 spec = [("a", float64),("b",float64)] @j
我有一个简单的函数来对扑克手牌进行排序(手牌是字符串)。 我用 rA,rB = rank(a),rank(b) 调用它,这是我的实现。没有 @jit(nopython=True) 也能很好地工作,但是
我在这里有一个简单的例子来帮助我理解使用 numba 和 cython。我是 numba 和 cython 的新手。我已经尽力结合所有技巧来使 numba 更快,并且在某种程度上,cython 也是如
我正在使用 numbas @jit 装饰器在 python 中添加两个 numpy 数组。如果我使用 @jit 与 python 相比,性能是如此之高。 然而,即使我传入 @numba.jit(nop
我需要为通用指标构建相异矩阵。由于我需要算法快速运行,所以我在 nopython 模式下使用了 numba 0.35。这是我的代码 import numpy as np from numba impo
Numba Cuda 有 syncthreads() 来同步一个 block 中的所有线程。如何在不退出当前内核的情况下同步网格中的所有 block ? 在 C-Cuda 中有一个 cooperati
有人尝试在Google合作伙伴中使用numba吗?我只是不知道如何在此环境中进行设置。 此刻,我陷入了错误library nvvm not found。 最佳答案 将此代码复制到单元格中。这个对我有用
我想编写一个函数,它既可以作为 jitted 函数运行,也可以作为普通 python 或对象模式 numba 运行,具体取决于 numba 是否能够进行类型推断。我实际上更喜欢普通的 python,但
我有一个非常简单的问题我无法解决。 我正在使用 Numba 和 Cuda。我有一个列表 T=[1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0] 我想要一个包含列表元素的元组,如
我正在测试一些采用 numpy 数组的函数的 numba 性能,并比较: import numpy as np from numba import jit, vectorize, float64 im
我正在使用 Scipy 的 interpolate.interp1d 在 Python3 中插入一维数组。我想将它与 numba 一起使用,但不支持 scipy 和此功能。是否有 numba 支持
我是 Numba 的新手,我正在尝试使用 Numba(版本 0.54.1)在 Python 中实现旧的 Fortran 代码,但是当我添加 parallel = True 时,程序实际上变慢了.我的程
我需要在 Python 中创建一个位数组。到目前为止,我发现可以使用 bitarray 生成非常节省内存的数组。模块。 然而,我的最终目的是使用来自Numba 的@vectorize 装饰器。 . N
我认为这是一个简单的问题,但我发现 numba 文档缺乏关于如何将字符串类型与 numpy 数组和字典一起使用的信息。我有一个我想使用 numba 的函数,它需要一个邮政编码列表,然后是一个映射邮政编
假设我有两个功能 def my_sub1(a): return a + 2 def my_main(a): a += 1 b = mysub1(a) return b
在以下用于逻辑比较的 numba 编译函数中,性能下降的原因可能是什么: from numba import njit t = (True, 'and_', False) #@njit(boolean
我的代码使用如下列表的笛卡尔积: import itertools cartesian_product = itertools.product(list('ABCDEF'), repeat=n) n可
我正在使用 Numba(版本 0.37.0)来优化 GPU 代码。我想使用组合矢量化函数(使用 Numba 的 @vectorize 装饰器)。 导入和数据: import numpy as np f
我想知道在 numba 函数中计算两个列表的交集的最快方法。只是为了澄清:两个列表的交集示例: Input : lst1 = [15, 9, 10, 56, 23, 78, 5, 4, 9] lst2
我正在使用 Numba 非 python 模式和一些 NumPy 函数。 @njit def invert(W, copy=True): ''' Inverts elementwise
我是一名优秀的程序员,十分优秀!