numba采坑记

最近写了一个项目,能跑通了但是速度感人,听说numba对loop有奇效,而且就一行代码,但坑比较多

numba基本原理

     Python编译分为提前编译和即时编译常用的解释器有CPython、IPython、PyPy、Jython、IronPython,使用最广泛的是CPython,它是通过提前编译,创建一个为你的机器定制的静态库。在执行Python前,Python会生成.pyc文件,这个文件就是字节码,字节码在Python虚拟机程序里对应的是PyCodeObject对象,如果我们不小心修改了字节码,Python下次重新编译该程序时会和其上次生成的字节码文件进行比较,如果不匹配则会将被修改过的字节码文件进行覆盖,以确保每次编译后字节码的准确性。
   简单来说就是在编译代码的过程中,首先会将代码中的函数、类等对象分类处理,然后生成字节码文件。有了字节码文件,通过python的解释器对字节码进行解释,将每一行的字节码解释成CPU可以直接识别的机器码,执行。
   而对于即时编译,编译器在使用时只逐步编译用的部分代码,但这不适合处理短小频繁运行的脚本。而Numba让Python函数编译为机器代码的JIT编译器,它可以加速Python运行。Numba 是一个专用于 numpy 代码的即时编译器, 在运行时由 LLVM 编译器来编译。

安装numba

直接在pycharm的终端pip
在这里插入图片描述

改写函数

把要加速的循环放在函数里面,头上加上:

@jit(nopython=True)
def funn(particle, bu):

接下来提,这个工作量比较大,因为之前我的方法全部封装在各种类里面的,而numba连python自带的dict,list类都不支持,只有全部提出来,numba支持的类。numba支持的函数列表之前的循环的叠加都是放在dict容器里面的,看到一个作者把它说可以把它放在np的数组。
将:

    for j in particle:
        for i in b:
            point_dose_n = point_dose(j[0], j[1], i)
            i = str(i)
            xx = dose_dict[i] + point_dose_n
            dose_dict[i] = xx

调整为:

   xx = dose_array[iz][ix][iy] + point_dose_n
            dose_array[iz][ix][iy] = xx

注意数据类型!!!

把函数都提出来后,并没有解决所有问题,还是在报各种错,而且numba报的错很多指向环境,或者甩出主函数跳出来,这里在这里插入图片描述
这里主函数的输入其实没有问题,是内部数据类型的问题,但只报这个错。

Traceback (most recent call last):
  File "F:/Test_Space/dose_work/6.1777.py", line 212, in <module>
    dose_array=funn(particle1,b5)  #b.shape=(22078, 3)
  File "C:\Anaconda3\envs\detectron2\lib\site-packages\numba\core\dispatcher.py", line 414, in _compile_for_args
    error_rewrite(e, 'typing')
  File "C:\Anaconda3\envs\detectron2\lib\site-packages\numba\core\dispatcher.py", line 357, in error_rewrite
    raise e.with_traceback(None)
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
No implementation of function Function(<built-in function zeros>) found for signature:

debug难度大,因此我使出终极大法,全部注释掉,一行一行跑。
有些变量的计算报错,可以用float包一下就可以解决,但也不一定。例如:在这里插入图片描述
list.append用不了了,我改成了np.vstack((array_a,array_b)),这句过了,但是循环又出问题了,估计是声明变量类型的问题,最后用numba库里面提供的类解决的,代码如下:

from numba.typed import List
coordinates_target=List()
for i in range(0,len(list_file)):
    ...
    ...
    ...
    b3=get_coord(loc,num)
    coordinates_target.extend(b3)

另外,平时在使用numpy时大家都习惯用类似[shape1,shape2]这样的方法来写,但是正规的numpy写法应该使用tuple而不是list,所以类如np.zeros([shape1,shape2])要改成np,zeros((shape1,shape2))。
装饰器中使用了nopython=True,那么dtype就不能是python内置的数据类型,要改为numba中的数据类型。不得不说numba加速for循环真香,我测了大概有几十倍的样子。

总结:

  1. numba 的nopython模式对数据类型的一致性要求很高,在使用较复杂的数据(多维矩阵、浮点数(小数))进行运算时,最好提前做好类型转换和声明的工作,以免产生谷歌都搜不到的错误。
  2. numba支持的numpy类型和函数等可以查阅官方文档
    3.装饰器的signature功能显示指出形参和返回值类型,并在函数调用前做好类型转换,确保形参类型一致。
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值