pycharm怎么用numpy,python numba_如何用numba加速python?

 2023-11-18 阅读 24 评论 0

摘要:我把寫好的markdown導入進來,但是沒想到知乎的排版如此感人。如果對知乎排版不滿想要看高清清爽版,請移步微信公眾號原文 如何用numba加速python?同時歡迎關注前言說道現在最流行的語言,就不得不提python。可是python雖然容易上手,但速度卻

我把寫好的markdown導入進來,但是沒想到知乎的排版如此感人。如果對知乎排版不滿想要看高清清爽版,請移步微信公眾號原文 如何用numba加速python?同時歡迎關注

前言

說道現在最流行的語言,就不得不提python。可是python雖然容易上手,但速度卻有點感人。如何用簡單的方法讓python加速到近乎可以媲美C的速度呢?今天來就來談談numba這個寶貝。對你沒看錯,不是numpy,就是numba。

目錄

用函數編程

Numba的優勢

pycharm怎么用numpy。如何使用numba

? 只用1行代碼即可加速,對loop有奇效

? 兼容常用的科學計算包,可以創建ufunc

? 會自動調整精度,保證準確性

拓展

? 更多numba的加速選項

python用gpu、? Numba的精度問題

附錄

用函數編程

在面對一個計算project的時候,我們最容易想到的就是直接碼代碼,最后寫出一個超長的程序。這樣一來,一旦出錯往往就需要花很多時間定位問題。

有一個簡單的辦法解決這個問題,就是定義各種各樣的函數,把任務分解成很多小部分。因為每個函數都不是特別復雜,并且在寫好的時候就可以隨時檢查,因此簡潔的主程序一旦出問題就很容易定位并解決。面向對象編程的思想就是基于函數。

寫好函數之后,還可以使用裝飾器(decorator)讓它變得強大。裝飾器本身是一個函數,不過是函數的函數,目的是增加函數的功能。比如首先定義一個輸出當前時間的函數,再定義一個規定時間格式的函數,把后一個函數作用在前一個函數上,就是一個裝飾器,作用是用特定格式輸出當前時間。

python 編譯,Numba的優勢

1.簡單,往往只要1行代碼就有驚喜;

2.對循環(loop)有奇效,而往往在科學計算中限制python速度的就是loop;

3.兼容常用的科學計算包,如numpy、cmath等;

4.可以創建ufunc;

5.會自動調整精度,保證準確性。

python編程、如何使用numba

針對上面提到的numba的優勢,我來進行逐一介紹。首先導入numba

import numba as nb

只用1行代碼即可加速,對loop有奇效

因為numba內置的函數本身是個裝飾器,所以只要在自己定義好的函數前面加個@nb.jit()就行,簡單上手。下面以一個求和函數為例

# 用numba加速的求和函數

python中no module named numpy。@nb.jit()

def nb_sum(a):

Sum = 0

for i in range(len(a)):

Sum += a[i]

return Sum

python numpy,# 沒用numba加速的求和函數

def py_sum(a):

Sum = 0

for i in range(len(a)):

Sum += a[i]

return Sum

python加速for循環?來測試一下速度

import numpy as np

a = np.linspace(0,100,100) # 創建一個長度為100的數組

%timeit np.sum(a) # numpy自帶的求和函數

%timeit sum(a) # python自帶的求和函數

%timeit nb_sum(a) # numba加速的求和函數

python用GPU為自己加速,%timeit py_sum(a) # 沒加速的求和函數

結果如下

# np.sum(a)

7.1 μs ± 537 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

# sum(a)

27.7 μs ± 2.64 μs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

numpy 加速。# nb_sum(a)

1.05 μs ± 27.6 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

# py_sum(a)

43.7 μs ± 1.71 μs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

可以看出,numba甚至比號稱最接近C語言速度運行的numpy還要快6倍以上。但大家都知道,numpy往往對大的數組更加友好,那我們來測試一個更長的數組

a = np.linspace(0,100,10**6) # 創建一個長度為100萬的數組

python 加速循環的執行,測試結果如下

# np.sum(a)

2.51 ms ± 246 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# sum(a)

249 ms ± 19.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

# nb_sum(a)

python命令行運行py文件、3.01 ms ± 59.7 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# py_sum(a)

592 ms ± 42 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

可見即便是用很長的loop來計算,numba的表現也絲毫不亞于numpy。在這里,我們可以看到numba相對于numpy一個非常明顯的優勢:numba可以把各種具有很大loop的函數加到很快的速度,但numpy的加速只適用于numpy自帶的函數。

但要注意的是,numba對沒有循環或者只有非常小循環的函數加速效果并不明顯,用不用都一樣。(偷偷告訴你,numba的loop甚至常常比numpy的矩陣運算還要快)

兼容常用的科學計算包,可以創建ufunc

python和c語言哪個簡單。上一部分我們比較了numba和numpy的表現,可以說numba非常亮眼了。但numpy還有一個非常強大的功能——ufunc (universal functions),它可以讓一個函數同時處理很多數據。比如要求一個數組每一個元素的三角函數,只需要

np.sin(a) # 這里的a仍然是上面有100萬個元素的數組

而不需要寫個循環一個一個求。可如果不用numpy但又想要很快的速度,那應該怎么求呢?我們可以用從math庫里導入sin,然后寫個loop再用numba加速。除了這個方法,在這里我還想說numba另一個強大的功能,矢量化(vectorize)。像上面的jit一樣,只要添加一行vectorize就可以讓普通函數變成ufunc

from math import sin

@nb.vectorize()

def nb_vec_sin(a):

python的numba加速?return sin(a)

來比較一下用各種方式寫出的三角函數

# 用numba加速的loop

13.5 ms ± 405 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# nb_vec_sin(a)

14.2 ms ± 55.2 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)

python加速方法,# np.sin(a)

5.75 ms ± 85 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)

可以看出,用vectorize改寫的三角函數具有了和np.sin()一樣的同時處理數組每個元素的功能,而且表現也不必numpy差。當遇到numpy沒有的數學函數時(比如sech),用numba矢量化不失為一個好的選擇。除了math中的sin,它支持的其他函數列表可以在documentation中找到(鏈接見附錄)。

其實numpy也有矢量化的功能,只不過比numba差遠了。

會自動調整精度,保證準確性

上面我們用的測試數組數字范圍只是從0到100的。可如果數字很大,那么就很容易出現overflow的問題,比如

python cuda編程。a = np.arange(10**6) # a的最小值為0,最大值為10**6-1

你猜猜用python自帶的sum,我們自己寫的py_sum,np.sum和nb_sum給出的結果一不一樣呢?你會發現

# np.sum(a)

1783293664

# sum(a)

1783293664

# nb_sum(a)

499999500000

# py_sum(a)

1783293664

numba的結果和其他三個都不一樣,肯定錯了呀,還用問么?

且慢!其實在運行的時候,我并沒有告訴你sum和py_sum都報錯了“RuntimeWarning: overflow encountered in long_scalars”。但奇怪的是np.sum并沒有報錯。

在上面的四個函數里,其實numba表現的最好,因為它自動調整了整數類型。如果你用nb.typeof()查看,你會發現numba給出的結果是int64,而其他三個都是int32。不得不說,numba不僅快還在精度方面表現很好!

拓展

在本文的最后一部分,我想談兩個問題。

更多numba的加速選項

除了上面提到的jit和vectorize,其實numba還支持很多加速類型。常見的比如

? @nb.jit(nopython=True,fastmath=True) 犧牲一丟丟數學精度來提高速度

? @nb.jit(nopython=True,parallel=True) 自動進行并行計算

切記一定要用nopython。默認都是True的,但有時候如果定義的函數中遇到numba支持不良好的部分,它就會自動關閉nopython模式。沒有nopython的numba就好像沒有武器的士兵,雖然好過沒兵,但確實沒什么戰斗力。因此,在使用jit時候要明確寫出nopython=True。如果遇到問題,就找到這些支持不良好的部分,然后改寫。畢竟numba對loop非常友好,改寫這些部分應當是非常容易的。

其實如何選擇這些模式會對函數有最佳的加速效果,是一個玄學。我前段時間向一位精通numba的prof請教,他給我的建議是,多試試就知道有沒有用了。。。另外,numba還支持多個用GPU加速的包,比如CUDA。

Numba的精度問題

精度方面,在上面我也談到numba會自動轉換數據類型以適應計算。但是在個別時候,這種自動轉變類型可能會引起一些計算誤差。通常這個誤差是非常小的,幾乎不會造成任何影響。但如果你所處理的問題會積累誤差,比如求解非線性方程,那么在非常多的計算之后誤差可能就是肉眼可見了。如果你發現有這樣的問題,記得在jit中指定輸入輸出的數據類型。numba具有C所有的數據類型,比如對上面的求和函數,只需要把@nb.jit()改為@nb.jit(nb.int64(nb.int32[:]))即可。nb.int64是說輸出的數字為int64類型,nb.int32是說輸入的數據類型為int32,而[:]是說輸入的是數組。

附錄

Numba documentation鏈接

速度比較:C, Julia, Python, Numba, Cython和LU Factorization

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/4/176657.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息