打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Python加速库NumExpr简介

1. NumExpr是什么?

NumExpr是一个用于numpy类型快速数值表达式计算的第三方Python加速库。有了它, 在数组上操作的表达式(如3xa+4xb)相比在python中执行速度更快,所需内存空间占用更少。
值得一提的是,NumExpr集成了intel的vml(向量数学计算库 vectore math library)技术, 这使得数值型表达式的计算速度得到了进一步提升。

2. Numexpr如何实现高性能?

NumExpr获得比numpy更好的性能的主要原因是避免为中间结果分配内存,这样可以提高缓存利用率,减少内存访问。因此,NumExpr在处理大型数组时相比numpy效果最好。

3. 如何安装NumExpr?

我们可以通过conda或者pip来进行安装,命令如下:

$ conda install -c anaconda numexpr

或者

pip install numexpr

4. 性能评估

我们计算由两个向量a,b 组成的表达式 f 为例,来评估输入不同大小的两个向量下使用NumExpr和Numpy二者的性能差异。其中f表达式如下:

1)导入相关库

import numexpr as ne
from time import time

2)使用Numpy来实现

def timeIt_numpy(a, b, runs, loops):
    output = np.zeros(runs)
    for r in range(runs):
        to = time()
        for _ in range(loops):
            current = 2*a**3 + 3*b**2
        ti = time()
        output[r] = ti - to
    return output

上述代码实现了利用Numpy来计算表达式f的功能,其中:
a,b 代表输入的两个向量
runs 代表我们做几次对比实验
loops 代表每次实验表达式重复执行多少次,以方便我们统计时间
output 代表每次实验(即上述表达式执行loops次)所耗费的时间

3)使用NumExpr来实现

def timeIt_numexpr(a, b, runs, loops):
    output = np.zeros(runs)
    for r in range(runs):
        to = time()
        for _ in range(loops):
            current = ne.evaluate('2*a**3 + 3*b**2')
        ti = time()
        output[r] = ti - to
    return output

上述代码实现了利用NumExpr来计算表达式f的功能,相关参数含义同上。这里需要注意的是,使用NumExpr来计算表达式的值,只需要将表达式写成:

current = ne.evaluate('2*a**3 + 3*b**2')

形式即可,对程序的修改及其简单。

4)主函数

这里为了直观对比输入不同size下的vector,统计两者的时间差异,使用matplotlib来画图显示,代码如下:

import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 1, figsize=(16, 8))

N = 16
runs = 10
loops = 1000
time_numpy = np.zeros((runs, N))
time_numexpr = np.zeros((runs, N))

# Time
for i in range(N):
    a = np.random.rand(2**(i + 1))
    b = np.random.rand(2**(i + 1))
    time_numpy[:,i] = timeIt_numpy(a, b, runs, loops)
    time_numexpr[:,i] = timeIt_numexpr(a, b, runs, loops)

# Plot
x = np.arange(N)
mu = np.mean(time_numpy, axis=0)
ax.plot(mu, label="NumPy")

x = np.arange(N)
mu = np.mean(time_numexpr, axis=0)
ax.plot(mu, label="NumExpr")

ax.set_xlabel('N')
ax.set_xticks(x)
ax.set_xticklabels([f'$2^{{{e + 1}}}$'for e in range(N)])
ax.set_ylabel('time in seconds for each run')

ax.set_title(f'runs = {runs} | loops = {loops}')
ax.legend()
plt.show()

代码含义如下:
N 代表一共输入16组不同大小size的向量,每次实验输入向量的size为[2^1, 2^2 … 2^16]
runs 代表每组向量,进行10次实验
loops 代表表达式执行1000次,方便我们统计表达式执行耗时

耗时对比


上述图像中,横坐标表示输入向量的size,纵坐标表示向量size为N时,执行10次实验的平均耗时,每次实验中表达式执行1000次。
通过上述曲线,我们可以看出:

  • 当输入向量size小于2^12时,使用Numpy和NumExpr,所耗费的时间相差不大
  • 当size大于 2^12时,随着size的增大,NumExpr的加速效果越来越明显。
  • 当size等于2^16时,NumExpr加速效果​超过了10倍。

5. 总结

在代码中使用NumExpr的好处:

  • 对程序的修改简单,当输入尺度较大时,对支持的表达式的提速效果明显
  • 自动化的多线程;

6. 参考

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
这个Excel中,我目前知道张三的名字,想根据张三去取他的体重,应该怎么做呢?
word实用技巧:如何批量隐藏删除或添加数字
wrod里的数学分式怎么输入?
The Elements of Programming Style
数字电路试题
再见pip & conda!管理Python依赖关系的更好的选择:Poetry
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服