Python高性能計算庫——Numba
更多深度文章,請關注雲計算頻道:https://yq.aliyun.com/cloud
SciPy2017會議的視頻,偶然發現關於Numba的來曆--講述了那些C++橫行者因為對Gil ForsythLorena BarbaPython代碼中獲得了令人難以置信的表現,所以我覺得應該要寫一些關於Numba庫的介紹性文章,也可能會在將來添加一係列小的更多類似教程的文章。
1.那麼到底什麼是Numba?
NumbaPython代碼編譯為本地機器指令,而不會強製大幅度的改變普通的Python代碼(稍後再做說明)。翻譯/魔術是使用LLVM
Numba最初是由Continuum Analytics內部開發,此公司也開發了著名的Anacondamath-heavy(密集數學?重型數學?)和array-oriented(麵向數組)的功能,它們在本地Python中相當緩慢。想象一下,在Python中編寫一個模塊,必須一個元素接著一個元素的循環遍曆一個非常大的數組來執行一些計算,而不能使用向量操作來重寫。這是很不好的主意,是吧?所以“通常”這類庫函數是用C / C ++或Fortran編寫的,編譯後,在Python中作為外部庫使用。Numba這類函數也可以寫在普通的Python模塊中,而且運行速度的差別正在逐漸縮小。
2.怎麼才能get到Numba呢?
Numba的推薦方法是使用conda包管理
conda install numba
pipNumba,但是最新版本的發布才一天之久。但是,隻要你能夠使用condaCUDA工具包,也許你想讓你的Python代碼GPU就緒(當然,這也是有可能的!)。
3.如何使用Numba呢?
“普通”的Python函數,然後給函數定義添加一個裝飾(如果你不是很熟悉裝飾器,讀一下關於thisthat@jitnumpy通用功能@vectorizeCUDA GPU上執行的代碼@cuda2d數組的求和函數,以下是代碼:
from numba import jit
from numpy import arange
# jit decorator tells Numba to compile this function.# The argument types will be inferred by Numba when function is called.
@jit
def sum2d(arr):
M, N = arr.shape
result = 0.0
for i in range(M):
for j in range(N):
result += arr[i,j]
return result
a = arange(9).reshape(3,3)
print(sum2d(a))
Numba裝飾器被添加到函數定義中,並且voilá這個函數將運行得很快。但是,這裏帶來了很有趣的注意事項:你隻能使用Numpy和標準庫裏的函數來加快Numba速度,甚至不需要開了他們所有的特性。他們有一個相當好的herePython的功能和here Numpy功能。現在支持的功能可能還不太多,但我想告訴你,這就夠了!請記住,Numba不是要加快你的數據庫查詢或如何強化圖像處理功能。他們的目標是加快麵向數組的計算,我們可以使用它們庫中提供的函數來解決。
4.示例和速度比較
Python用戶永遠不會使用上述代碼實現sum功能,而是調用numpy.sum
Python本來就是很慢的!這就是為什麼大多數模塊都是在Fortran或C/C ++中實現的。如前所述:Python在對於這種麵向數組的計算來說是慢的。但是Numba允許我們在Python中做同樣的事情,而且沒有太多的性能損失。我認為至少對於模型的理解和發展,這可能會很方便。(所以我最近創建了一個名為“RRMPG ”的項目——降雨徑流建模遊樂場
Okay,現在我們來看看我們get到了什麼。我們將使用最簡單的模塊之一,由MB Fiering在1967年出於教育目的開發的ABC模型,並將Python代碼的速度與Numba優化後Python代碼和Fortran實現進行比較。請注意這個模型不是我們在現實中使用的(正如名稱所示),但是我認為這可能是一個不錯的想法來舉例。
ABC模塊是一個三個參數模塊(a,b,c,習慣性命名),它隻接收下雨量為輸入,隻有一個存儲。土壤水分蒸發蒸騰損失總量(參數b),另一部分通過土壤滲透到地下水儲存(參數a),最後一個參數c代表地下水總量,離開地下變成河流。Python中的代碼,使用Numpy數組可能會像如下所示:
import numpy as np
def abc_model_py(a, b, c, rain):
# initialize array for the stream discharge of each time step
outflow = np.zeros((rain.size), dtype=np.float64)
# placeholder, in which we save the storage content of the previous and
# current timestep
state_in = 0
state_out = 0
for i in range(rain.size):
# Update the storage
state_out = (1 - c) * state_in + a * rain[i]
# Calculate the stream discharge
outflow[i] = (1 - a - b) * rain[i] + c * state_out
state_in = state_out
return outflow
Numba來實現相同的功能。
@jit
def abc_model_numba(a, b, c, rain):
outflow = np.zeros((rain.size), dtype=np.float64)
state_in = 0
state_out = 0
for i in range(rain.size):
state_out = (1 - c) * state_in + a * rain[i]
outflow[i] = (1 - a - b) * rain[i] + c * state_out
state_in = state_out
return outflow
fortran實現的時間(詳見here
py_time = %timeit -r 5 -n 10 -o abc_model_py(0.2, 0.6, 0.1, rain)
>> 6.75 s ± 11.6 ms per loop (mean ± std. dev. of 5 runs, 10 loops each)
# Measure the execution time of the Numba implementation
numba_time = %timeit -r 5 -n 10 -o abc_model_numba(0.2, 0.6, 0.1, rain)
>> 30.6 ms ± 498 µs per loop (mean ± std. dev. of 5 runs, 10 loops each)
# Measure the execution time of the Fortran implementation
fortran_time = %timeit -r 5 -n 10 -o abc_model_fortran(0.2, 0.6, 0.1, rain)
>> 31.9 ms ± 757 µs per loop (mean ± std. dev. of 5 runs, 10 loops each)
# Compare the pure Python vs Numba optimized time
py_time.best / numba_time.best
>> 222.1521754580626
# Compare the time of the fastes numba and fortran run
numba_time.best / fortran_time.best
>> 0.9627960721576471
Python代碼快222倍,甚至比Fortran也快很多。在計算能力決定未來的時代,Numba一定會被更多人接受。
Numba庫。我想在將來我會編寫一係列小的Numba文章/教程,並提供更多的技術信息,讓更多的人使用Numba 庫。而本文僅作為一個開始。
本文由北郵@愛可可-愛生活 老師推薦,阿裏雲雲棲社區組織翻譯。
文章原標題《Introduction to the Numba library》
作者:Flaire
譯者:一隻高冷的貓,審校:袁虎。
文章為簡譯,更為詳細的內容,請查看原文
最後更新:2017-09-17 00:03:13