前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >利用numba給Python代码加速 [1]

利用numba給Python代码加速 [1]

作者头像
用户6021899
发布2022-01-10 08:08:22
1.4K0
发布2022-01-10 08:08:22
举报
  • 什么是Nopython 模式?

Numba @jit 装饰器有两种编译模式, Nopython 模式和Object 模式。nopython编译模式的行为本质上是编译修饰后的函数,使其完全运行而不需要Python解释器的参与。这是使用Numba jit装饰器的推荐和最佳实践方法,因为它可以获得最佳性能。@jit(nopython=True) 等效于@njit()。

代码语言:javascript
复制
# -*- coding: utf-8 -*-
from numba import jit
import numpy as np
from time import time


@jit(nopython=True) # Set "nopython" mode for best performance, equivalent to @njit
def go_fast(a): # Function is compiled to machine code when called the first time
    trace = 0.0
    for i in range(a.shape[0]):   # Numba likes loops
        trace += np.tanh(a[i, i]) # Numba likes NumPy functions
    return a + trace              # Numba likes NumPy 广播


N = 100
x = np.arange(N**2).reshape(N, N)
since = time()
r = go_fast(x)
print("time elapsed: ", time() - since)
print(r)

如果在nopython模式下编译失败,Numba可以使用对象模式进行编译。如果没有设置nopython=True,这是@jit装饰器的一种回退模式。在这种模式下,Numba将识别可以编译的循环,并将这些循环编译成在机器代码中运行的函数,它将在Python解释器中运行其余的代码(速度变慢)。为获得最佳性能,请避免使用此模式!

  • nogil

每当Numba将Python代码优化为只在本机类型和变量(非Python对象)上工作的本机代码时,就不再需要Python的全局解释器锁(GIL)。如果您传递了nogil=True,则在输入此类编译函数时,Numba将释放GIL。

使用释放GIL运行的代码可与执行Python或Numba代码的其他线程(同一个编译函数或另一个编译函数)同时运行,允许您利用多核系统。如果函数是在对象模式下编译的,则这是不可能的。

当使用nogil=True时,您必须警惕多线程编程的常见陷阱(一致性、同步、竞争条件等)。

代码语言:javascript
复制
@njit(nogil=True)
def f(x, y):
    return x + y
  • cache

为了避免每次调用Python程序时都要进行编译,可以指示Numba将函数编译的结果写入基于文件的缓存中。这是通过传递cache=True来完成的。

代码语言:javascript
复制
@njit(cache=True)
def f(x, y):
    return x + y
  • parallel

为已知具有并行语义的函数中的操作启用自动并行化(和相关优化)。有关支持的操作的列表,请参阅Automatic parallelization with @jit。此功能通过传递parallel=True启用,必须与nopython=True一起使用

代码语言:javascript
复制
@jit(nopython=True, parallel=True)
def f(x, y):
    return x + y
  • 懒惰编译 使用@jit装饰器的推荐方法是让Numba决定何时以及如何优化
代码语言:javascript
复制
from numba import jit

@jit
def f(x, y):
    # A somewhat trivial example
    return x + y

在此模式下,编译将推迟到第一次函数执行。Numba将在调用时推断参数类型,并基于此信息生成优化代码。Numba还可以根据输入类型编译单独的专门化。例如,使用整数或复数调用上面的f()函数将生成不同的代码路径:

代码语言:javascript
复制
>>>f(1, 2)
3
>>>f(2**31, 2**31 + 1)
4294967297
>>> f(1j, 2)
(2+1j)
  • 积极编译

你可以告诉numba你期望的函数签名(参数类型和返回值类型):

代码语言:javascript
复制
from numba import jit, int32

@jit(int32(int32, int32)) #输入是两个四字节整数,输出也是四字节整数
def f(x, y):
    # A somewhat trivial example
    return x + y
代码语言:javascript
复制
int32(int32,int32)是函数的签名。在这种情况下,相应的专门化
将由@jit decorator编译,不允许其他专门化。如果您希望对编译器选
择的类型进行精确控制(例如,使用单精度浮点),这将非常有用(通
常会更快)。但是要注意溢出的风险。


>>>f(2**31, 2**31 + 1)
1 #溢出,高位丢失
如果省略返回类型,例如通过写入(int32,int32)而不是
int32(int32,int32),Numba将尝试为您推断它。函数签名也可以是
字符串,您可以将其中几个作为列表传递。


常用的数据类型有:
  • int8, uint8, int16, uint16, int32, uint32, int64,

uint64,各种长度整数。图像处理中unit8很常用。

  • float32 ,float64, 单精度浮点数,双精度浮点数
  • complex64 ,complex128, 单精度复数,双精度复数
  • void, 对应python中返回Nothing。
  • intc and uintc 等效于C中的 int 和uint
  • 各种数组类型,如float32[:]表示一维单精度浮点数组,

uint8[:,:] 表示二维无符号8位整数数组(常用于图像数组)

  • 元组, 如nb.types.UniTuple(nb.float32, 3) 表示3个

元素的元组,元素的类型是float32

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-01-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python可视化编程机器学习OpenCV 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档