閱讀1020 返回首頁    go 技術社區[雲棲]


關於Numba你可能不了解的七個方麵

更多深度文章,請關注:https://yq.aliyun.com/cloud


我最喜歡的事情之一是與人們談論GPU計算和Python。 Python的生產力和互動性與GPU的高性能結合是科學和工程中許多問題的殺手。 有幾種使用GPU加速Python的方法,但我最熟悉的是Numba,它是Python函數的即時編譯器。 Numba在標準的Python翻譯器中運行,因此您可以直接以Python語法編寫CUDA內核,並在GPU上執行它們。 NVIDIA開發者博客最近推出了一篇Numba的介紹我建議閱讀那篇文章,對GPU上的Numba有一個簡要的了解

當我和人們談論Numba時,我發現他們很快就在Python中編寫了CUDA內核的基礎知識。 但是我們經常沒有時間使用Numba為GPU程序員提供的一些更先進的功能。 在這篇文章中,我想深入了解一下,並展示了在GPU上使用Numba的幾個往往被忽視方麵。我會快速講述一些主題,但是我會提供鏈接以供閱讀。

1.Numba

Pyculib是圍繞標準CUDA算法的Python包裝器的新名稱。 它包括Python包裝器,用於:


import pyculib.fft
import numba.cuda
import numpy as np
 
@numba.cuda.jit
def apply_mask(frame, mask):
    i, j = numba.cuda.grid(2)
    frame[i, j] *= mask[i, j]
 
# … skipping some array setup here: frame is a 720x1280 numpy array
 
out = np.empty_like(mask, dtype=np.complex64)
gpu_temp = numba.cuda.to_device(out)  # make GPU array
gpu_mask = numba.cuda.to_device(mask)  # make GPU array
 
pyculib.fft.fft(frame.astype(np.complex64), gpu_temp)  # implied host->device
apply_mask[blocks, tpb](gpu_temp, gpu_mask)  # all on device
pyculib.fft.ifft(gpu_temp, out)  # implied device->host

你可以在其文檔中了解有關Pyculib功能的更多信息。 現在Pyculib是開源的,我們正在積極嚐試擴展Pyculib,以包括其他CUDA庫,如cuSOLVER和nvGRAPH。

2.Numba + Jupyter =

將Numba看作“用Python語法編寫CUDA”是很容易的,但是Numba與Python數據科學生態係統中的其他工具的結合可以改變GPU計算的經驗。 我們特別喜歡用Jupyter Notebook(和JupyterLab,下一代筆記本)使用Numba。 圖1所示的Jupyter Notebook提供了一個基於瀏覽器的文檔創建環境,允許將Markdown文本,可執行代碼和圖形和圖像的圖形輸出相結合。Jupyter已經變得非常受歡迎,用於教學,記錄科學分析和交互式原型。 事實上,這篇博文中的所有例子都是在Jupyter筆記本中創建的,你可以在這裏找到。

6e4436c437c29e1c0cd609bec495c41989151944

  • Jupyter在其“魔術”命令集中包含了一個基準測試工具。通過用帶有%timeit的行前綴,Jupyter會自動運行該命令多次,以準確測量運行時間。 (不要忘記在運行內核後同步設備以獲得準確的時間!)


ssh -L 9999:localhost:9999 me@gpu-server.example.com


jupyter notebook --port 9999 --no-browser

3.Numba


__host__ __device__ float clamp(float x, float xmin, float xmax) {
    if (x < xmin){
        return xmin;
    } else if (x > xmin) {
        return xmax;
    } else {
        return x;
    }
}


@numba.jit
def clamp(x, xmin, xmax):
    if x < xmin:
        return xmin
    elif x > xmax:
        return xmax
    else:
        return x


@numba.cuda.jit
def clamp_array(x, xmin, xmax, out):
    # Assuming 1D array
    start = numba.cuda.grid(1)
    stride = numba.cuda.gridsize(1)
    for i in range(start, x.shape[0], stride):
        out[i] = clamp(x[i], xmin, xmax)  # call "CPU" function here

4.Numba


import numba
import math
import numpy as np
 
SQRT_TWOPI = np.float32(math.sqrt(2 * math.pi))
 
@numba.vectorize(['float32(float32, float32, float32)'], target='cuda')
def gaussian(x, x0, sigma):
    return math.exp(-((x - x0) / sigma)**2 / 2) / SQRT_TWOPI / sigma


x = np.linspace(-3, 3, 10000, dtype=np.float32)
g = gaussian(x, 0, 1)  # 1D result
 
x2d = x.reshape((100,100))
g2d = gaussian(x2d, 0, 1) # 2D result

要了解有關ufuncs和Numba的更多信息,請查看有關廣播的NumPy文檔和ufuncs上的Numba文檔

5.Numba

要調用CUDA模擬器,你必須在啟動Python應用程序之前將NUMBA_ENABLE_CUDASIM環境變量設置為1。 這將迫使所有內核通過解釋器代碼路徑。 你可以在CUDA模擬器的Numba文檔中找到更多信息。

當然,這不是Numba中唯一可用的CUDA調試選項。 Numba還允許使用標準的Python打印函數/語句從GPU(常量字符串和標量)進行有限的打印。 另外,你可以使用nvprof(CUDA命令行剖析器),NVIDIA Visual Profilercuda-memcheck來運行Numba應用程序。 傳遞debug = True到@ numba.cuda.jit裝飾器將允許cuda-memcheck顯示檢測到的內存錯誤的Python源代碼行號。

6.

用於Python的分布式計算係統(如DaskSpark Python API)通過分散許多工作人員的數據並將代碼帶到數據所在的位置來實現高性能。 這需要將代碼序列化並通過網絡進行傳輸的能力。 在Python中,分布式框架通常使用cloudpickle庫(Python pickle模塊的增強版),將對象(包括函數)轉換為字節流。 這些字節可以從用戶輸入的功能的客戶端發送到遠程工作進程,並將它們轉回到可執行功能中。

fc289e38c611dc35f0bd15893cb0f758c30135c0

這裏有一個簡短的例子,這裏有一些啟動本地Dask群集的代碼,並使用dask.distributed futures API執行一個簡單的CUDA內核:


@numba.cuda.jit
def gpu_cos(x, out):
    # Assuming 1D array
    start = numba.cuda.grid(1)
    stride = numba.cuda.gridsize(1)
    for i in range(start, x.shape[0], stride):
        out[i] = math.cos(x[i])
        
def do_cos(x):
    out = numba.cuda.device_array_like(x)
    gpu_cos[64, 64](x, out)
    return out.copy_to_host()
 
# check if works locally first
test_x = np.random.uniform(-10, 10, 1000).astype(np.float32)
result = do_cos(test_x)
 
# now try remote
from dask.distributed import Client
client = Client() # starts a local cluster
 
future = client.submit(do_cos, test_x)
gpu_result = future.result()

雖然此示例執行的工作量很小,但它顯示了使用分布式係統的Numba的一般模式。 提交到集群的函數是一個常規的Python函數,它內部調用一個CUDA函數。 包裝器函數提供了一個分配GPU內存並確定CUDA內核啟動配置的地方,分布式框架無法實現。 當do_cos提交到群集時,cloudpickle還會檢測到對gpu_cos函數的依賴性並將其序列化。 這確保do_cos具有在遠程工作器上運行所需的一切。 通常在使用Dask時,我們傾向於更高級別的API來構建計算圖,如dask.delayed,但是對於一些迭代算法,直接使用 future是最直接的方法。

7.Numba

在2017年的GTC 大會上,與H2OMapDBlazingDBGraphistryGunrock合作的Anaconda公司(Numba開發的主要讚助商)宣布成立GPU開放分析計劃(簡稱“GOAI”)。我們都認識到需要在應用程序和庫之間進行GPU數據交換,因為數據科學工作負載越來越需要多種工具的組合。GPU計算已經無處不在,所以我們不能再把GPU當作一個隱藏的實現細節。現在是更多應用程序和庫公開允許直接在組件之間傳遞GPU內存的接口的時候了。想要對GOAI的深入了解,請查看GOAI項目中的NVIDIA Developer Blog文章。

團隊成員自2017年3月起就一直在工作,最近還與Apache Arrow項目的Wes McKinney合作,共同創建了可以在應用程序和庫之間共享的GPU DataFrame。 GPU DataFrame實現使用Arrow格式來表示GPU上的表格數據,我們希望將來將大部分實現直接轉移到Arrow代碼庫中。作為該軟件堆棧的一部分,Numba開發人員已經創建了PyGDF,這是一個用於使用Pandas API子集來操作GPU DataFrames的Python庫。該庫支持過濾,排序,列數學運算,縮減,加入,按組合運算,以及與其他進程零拷貝共享GPU DataFrames。為了實現這一點,PyGDF使用Numba to JIT編譯CUDA內核以進行自定義分組,縮減和過濾操作。此外,PyGDF列可以傳遞給Numba CUDA函數,以執行不能表示為DataFrame操作的自定義轉換。

到目前為止,GOAI已經取得了很大的進展,但為時尚早,我們還有更多的工作要做。 還有一些令人興奮的未來! 要了解GOAI活動的信息,請加入GOAI Google Group

Numba

此外,如果你想提問或獲取Numba的幫助,最好的地方是Numba Users Google Group


本文由北郵@愛可可-愛生活老師推薦,阿裏雲雲棲社區組織翻譯。

文章原標題《Seven Things You Might Not Know about Numba》,作者:Stanley SeibertAnaconda社區創新總監,曾是Mobi的首席數據科學家。譯者:董昭男,審校:

文章為簡譯,更為詳細的內容,請查看原文


最後更新:2017-10-09 22:35:03

  上一篇:go  負載均衡進階:SLB常見問題解決方法
  下一篇:go  數據庫DevOps:我們如何提供安全、穩定、高效的研發全自助數據庫服務-iDB/DMS企業版