CDA数据分析师 出品

相信大家在做一些算法经常会被庞大的数据量所造成的超多计算量需要的时间而折磨的痛苦不已,接下来我们围绕四个方法来帮助大家加快一下Python的计算时间,减少大家在算法上的等待时间。今天给大家介绍Numba这一块的内容。

1.简介

所以什么是Numba呢?Numba是Python的即时编译器,也就是说当你调用Python

函数时,你的全部或部分代码都会被计时转换成为机器码进行执行,然后它就会以你的本机机器码速度运行,Numba由Anaconda公司赞助,并得到了许多组织的支持。

使用Numba,你可以加速所有以集中计算的、计算量大的python函数(例如循环)的速度。它还支持numpy库!因此,你也可以在计算中使用numpy,并加快整体计算的速度,因为python中的循环非常慢。你还可以使用python标准库中的数学库的许多功能,例如sqrt等。

2.为什么选择Numba?

所以,为什么要选择Numba?特别是当存在有许多其他编译器,例如cython或任何其他类似的编译器,或类似pypy的东西时。

选择Numba的理由很简单,那就是因为你不需要离开使用Python编写代码的舒适区。是的,你没看错,你不需要为了加速数据的运行速度而改变你的代码,这与从具有类型定义的相似cython代码获得的加速相当。那不是更好么?

你只需要在函数周围添加一个熟悉的Python功能,也就是装饰器(包装器)。目前类的装饰器也在开发之中。

所以,你只需要添加一个装饰器就可以了。例如:

from numba import jit@jitdef function(x): # 循环或数值密集型的计算 return x

它看起来仍然像是纯python代码,不是吗?

3. Numba如何工作?

Numb使用LLVM编译器基础结构,从纯Python代码生成优化的机器码。使用Numba的代码运行速度与C,C ++或Fortran中的类似代码相媲美。

这是代码的编译方式:

首先,获取,优化Python函数并将其转换为Numba的中间表示形式,然后类似于Numpy的类型推断一样进行类型判断(因此python float为float64),然后将其转换为LLVM可解释的代码。然后,该代码被馈送到LLVM的即时编译器以发出机器代码。

你可以根据需要在运行时生成代码或在CPU(默认)或GPU上导入代码。

4.使用基本的Numba功能(只需要@jit!)

小菜一碟!

为了获得最佳的性能,numba建议在你的jit包装器中使用参数nopython = True,但它根本不会使用Python解释器。或者你也可以使用@njit。如果你使用nopython = True的包装器失败并出现错误,则可以使用简单的@jit包装器,该包装器将编译部分代码,对其进行循环,然后将其转换为函数,再编译为机器码,然后将其余部分交给python解释器。

因此,你只需要执行以下操作:

from numba import njit, jit@njit # 或者@jit(nopython=True)def function(a, b): # 循环或数值密集型计算 return result

使用@jit时,请确保你的代码具有Numba可以编译的内容,例如计算密集型循环,使用它支持的库(Numpy)及其支持的函数。否则,它将无法编译任何内容。

首先,numba在首次用作机器代码后还会缓存这些函数。因此,在第一次使用之后,它会变得更快,因为你无需再次编译该代码,因为你使用的参数类型和你之前使用的相同。

而且,如果你的代码是可以并行化运行的,那么也可以将parallel = True作为参数传递,但是必须跟参数nopython = True结合使用。目前,它仅可以在CPU上工作。

你也可以指定你想要的函数签名,但是它不会编译你给他的任何其他类型的参数,比如:

你还可以指定你希望函数具有的函数签名,但是对于提供给它的任何其他类型的参数,它将不会编译。例如:

from numba import jit, int32@jit(int32(int32, int32))def function(a, b): #循环或数值型密集型计算 return result#或者你还没有导入类型的名称#你可以将他们作为字符串传递@jit('int32(int32, int32)')def function(a, b): #循环或数值型密集型计算 return result

现在,你的函数将只接受两个int32并返回一个int32。这样,你可以更好地控制自己的函数。你甚至可以根据需要传递多个)函数签名。

你还可以使用numba提供的其他装饰器:

1. @vectorize:允许将标量参数用作numpy ufunc,

1. @guvectorize:产生NumPy广义ufuncs

1. @stencil:将函数声明为类似模板操作的内核,

1. @jitclass:对于支持jit的类,

1. @cfunc:声明一个用作本机回调的函数(从C / C ++等调用),

1. @overload:注册自己的函数实现以在nopython模式下使用,例如@overload(scipy.special.j0)。

Numba还具有预先(AOT)编译功能,它生成一个编译后的扩展模块,该模块不依赖于Numba。但:

1. 它只允许使用常规函数(不能使用ufuncs),

1. 你必须指定一个函数签名。你只能指定一个,因为许多指定使用不同的名称。

它还会为你的CPU架构系列生成通用代码。

5. @vectorize包装器

通过使用@vectorize包装器,你可以将对标量进行操作的函数转换为数组,例如,如果你正在使用math仅在标量上运行的python 库,则可以对数组使用。这提供了类似于numpy数组操作(ufuncs)的速度。例如:

@vectorizedef func(a, b): # 对标量进行运算 return result

你还可以将target参数传递给此包装器,该包装器的值可以等于parallel用于并行化代码,cuda用于在cuda / GPU上运行代码的值。

@vectorize(target="parallel")def func(a, b): # 对标量进行运算 return result

假设你的代码具有足够的计算密集性或数组足够大,则使用numpy进行矢量化target = "parallel"或"cuda"通常比numpy实现运行得更快。如果不是这样的话,这将花费大量时间来制作线程和为不同的线程拆分元素,这可能会超过整个过程的实际计算时间。因此,工作应该足够繁重才能加快速度。

6.在GPU上运行函数

你也可以像包装器一样传递@jit来在cuda / GPU上运行函数。为此,你将必须numba库中导入cuda。但是在GPU上运行代码不会像以前那样容易。为了在GPU上的数百个甚至数千个线程上运行函数,它需要完成一些初始计算。你必须声明和管理网格,块和线程的层次结构。但是这并不难。

要在GPU上执行一个函数,你必须定义一个 kernel function(内核函数)或一个device function(设备函数)。首先,让我们看一下kernel function(核函数)。

关于内核函数需要记住的几点:

a)内核在被调用时显式声明其线程层次结构,即块数和每个块的线程数。你可以编译一次内核,然后使用不同的块和网格大小多次调用它。

b)内核无法返回值。因此,你将不得不在原始数组上进行更改,或者传递另一个数组来存储结果。对于计算标量,你将必须传递一个一元数组。

# 定义一个内核函数from numba import cuda@cuda.jitdef func(a, result): # 然后是一些CUDA相关的计算 # 你的计算密集的代码 # 你的答案储存在'result'中

因此,要启动内核,你将必须传递两个东西:

1. 每个块的线程数,

1. 块的数量。

例如:

threadsperblock = 32blockspergrid = (array.size + (threadsperblock - 1)) // threadsperblockfunc[blockspergrid, threadsperblock](array)

每个线程中的内核函数必须知道它在哪个线程中,知道它负责数组的哪个元素。通过Numba,只需一次调用即可轻松获得元素的这些位置。

@cuda.jitdef func(a, result): pos = cuda.grid(1) # 对一维数组 # x, y = cuda.grid(2) # 对二维数组 if pos < a.shape[0]: result[pos] = a[pos] * (some computation)

为了节省将numpy数组复制到特定设备并再次将结果存储在numpy数组中的时间,Numba提供了一些函数来声明和发送数组到特定的设备,如:numba.cuda.device_array,numba.cuda.device_array_like,numba.cuda.to_device,等等,以节省不必要的时间复制到cpu(除非必要)。

另一方面,device function只能从设备内部(通过内核或其他设备函数)好处是,你可以从device function返回一个值。因此,你可以使用此函数的返回值来计算kernel function或device function的一些内容。

from numba import cuda@cuda.jit(device=True)def device_function(a, b): return a + b

Numba 在其cuda库中还具有原子操作,随机数生成器,共享内存实现(以加快数据访问速度)等。

ctypes / cffi / cython互操作性:

· cffi- 在nopython模式下支持CFFI函数的调用。

· ctypes — 在nopython模式下支持ctypes包装器函数的调用…

· Cython导出的函数是可调用的。

下一期我们来看加快Python算法的另一种方法——数据并行化!

(1)获取更多优质内容及精彩资讯,可前往:https://www.cda.cn/?seo

(2)了解更多数据分析师领域的优质课程:

Python可以调用Gpu吗_加快Python算法的四个方法:Numba篇相关推荐

  1. python 怎么用gpu运算_使用Python玩转GPU

    问题 随着机器学习对模型运算速度的需求越来越强烈, 一直想进行GPU编程,但一直以来这些都是c++的专利 一想到c++里的各种坑,就提不起劲来,毕竟这样来来回回填坑的投入产出,生产效率就会大打折扣 解 ...

  2. python getattr调用自己模块_在Python中通过getattr获取对象引用的方法

    getattr函数 (1)使用 getattr 函数,可以得到一个直到运行时才知道名称的函数的引用. >>> li = ["Larry", "Curly ...

  3. python前端调用后端模型_【Python】【Flask】前端调用后端方法

    后端代码: @app.route("/test",methods=['POST','GET']) def test(): return "我是测试的" 前端代码 ...

  4. python如何调用参数配置文件_【Python学习笔记七】从配置文件中读取参数

    将一些需要经常更改的参数存放在配置文件中,通过读取配置文件来获取参数,这样修改以及使用起来比较方便 1.首先是配置文件的写法,如下一个environment.ini文件: a:里面"[]&q ...

  5. python opencv gpu加速_让Python下的OpenCV也能GPU加速!part.1

    20200411更新: 经过评论区 @鹤汀凫渚 的指导,我成功的用最简单的方法在python中调用到了GPU加速后的函数,这里把这位朋友的评论贴出来供各位参考: 以下原文: 本文的核心目的就是加速,在 ...

  6. python如何使用gpu加速_如何用云端 GPU 为你的 Python 深度学习加速?

    负荷 下午,我用 Python 深度学习框架 Keras 训练了一个包含3层神经网络的回归模型,预测波士顿地区房价. 这是来自于 "Deep Learning with Python&quo ...

  7. python如何封装成可调用的库_在python中如何以异步的方式调用第三方库提供的同步API...

    在关于asyncio的基本用法中提到,asyncio并不是多线程.在协程中调用同步(阻塞函数),都占用同一线程的CPU时间,即当前线程会被阻塞(即协程只会在等待一个协程时可能出让CPU,如果是普通函数 ...

  8. python调用谷歌地图_使用Python调用谷歌地图并记录运动轨迹进行可视化

    本篇博文主要介绍了如何使用python来调用谷歌地图,并对北京的一个轨迹数据集进行可视化展示.该数据集包含在3年内收集的182个用户的GPS轨迹.我在这个演示中使用了用户001的数据. 博文会给出具体 ...

  9. python调用usb设备_用Python与USB设备通信

    假设您使用Linux和libusb-1.0作为PyUSB的后端库.// Detach a kernel driver from an interface. // If successful, you ...

最新文章

  1. 动画requestAnimationFrame
  2. 检测IAT HOOK思路
  3. 微软:PHP在IIS 7上雄起
  4. java里有没有 0的使用_请问有没有人有零基础Java基础习题?
  5. MODIS三种常见数据辐射定标处理
  6. atitit js 开发工具 ide的代码结构显示(func list) outline总结
  7. VS2018+TensorFlow安装
  8. 了解一下银行科技信息岗
  9. Express框架入门
  10. 【转】大数据【五十八】探索MapReduce过程及分组详解
  11. 使用 Exact Audio Copy 抓取 CD 音轨保存为 FLAC 格式并填入元数据。
  12. 八字算命网站源码技术细节解析:使用PHP和JAVA实现的MVC架构、MySQL数据库设计和功能模块介绍
  13. 用户行为分析的指标及其意义
  14. 【SPI】SPI学习之SPI硬件相关
  15. Teamin群协作如何在微信上更好实现团队协作?
  16. 在Linux下使用Vi进阶编辑器Vim编译C/C++
  17. oracle分页的方法,oracle分页
  18. Fibonacci法的matlab实现
  19. 平衡球游戏开发教程(四)--深入了解WP7游戏底层原理
  20. java版gbc模拟器怎么用,GBA/GBC模拟器VisualBoyAdvance图文使用教程

热门文章

  1. 使用 vue filters过滤器直接显示 几分钟前 几小时前 几天前
  2. 计算机基础知识第十讲,计算机文化基础(第十讲)学习笔记
  3. oracle创建DBLink连接
  4. linux7挂载ntfs分区,刚安装centos7,请教大神如何挂载ntfs的分区
  5. 算法设计与分析第1章 算法概述
  6. usaco Network of Schools
  7. python slice是共享内存吗_在共享内存中使用numpy数组进行多处理
  8. html 逗号用什么替换,字符串用javascript数组中的逗号替换“↵”
  9. 北师大版图形的旋转二教案_北师大2011课标版(闫金铎主编)初中物理八年级下册三、重力公开课优质课课件教案视频...
  10. 硬盘显示容量和实际容量不符合_为啥我买的64G U盘实际只有57G?聊聊存储市场的“不足量”现象...