python使用numba库实现gpu加速
????????Numba是一個針對Python的開源JIT編譯器,由Anaconda公司主導開發,可以對Python原生代碼進行CPU和GPU加速。Numba對NumPy數組和函數非常友好。
????????使用Numba非常方便,只需要在Python原生函數上增加一個裝飾器(Decorator)。Numba會將這些函數使用即時編譯JIT方式編譯成機器碼,這些代碼將以近乎機器碼的速度運行。
1.CPU加速:
只用1行代碼即可加速,對loop有奇效
在函數前面加一個@nb.jit? 其他不用變
import numba as nb import numpy as np#把數據導入到data里面 f = open(r'source.txt') data = f.read().split(" ") while '' in data:data.remove('') data = np.array(data, dtype = int)#定義nb_func函數 @nb.jit def cpu_func(out,data):for i in range(1200):for j in range(762):for k in range(128):for n in range(128):order = round((((i * i + (j - k * 6) * (j - k * 6)) ** 0.5 + (i * i + (j - n * 6) * (j - n * 6)) ** 0.5) * 0.05) / 1.54 * 30)if (order < 2000):out[j][i] = out[j][i] + data[k * 2000 + order]#定義一個二維數組存放重建圖像 out = np.zeros([762,1200]) cpu_func(out,data) print(data)耗時大約75s(c++編程在不加速的情況下需要20分鐘)
輸出:
?
2.GPU加速:?
與傳統的Python CPU代碼不同的是:
- 使用from numba import cuda引入cuda庫
- 在GPU函數上添加@cuda.jit裝飾符,表示該函數是一個在GPU設備上運行的函數,GPU函數又被稱為核函數。
- 主函數調用GPU核函數時,需要添加如[1, 2]這樣的執行配置,這個配置是在告知GPU以多大的并行粒度同時進行計算。gpu_func[1, 2]()表示開啟一個block塊,每個block塊開啟2個線程并行地執行gpu_func函數,函數將被并行地執行2次。
- GPU核函數的啟動方式是異步的:啟動GPU函數后,CPU不會等待GPU函數執行完畢才執行下一行代碼。必要時,需要調用cuda.synchronize(),告知CPU等待GPU執行完核函數后,再進行CPU端后續計算。這個過程被稱為同步。
?Thread層次結構:
????????CUDA將核函數所定義的運算稱為線程(Thread),多個線程組成一個塊(Block),多個塊組成網格(Grid)。這樣一個Grid可以定義成千上萬個線程,也就解決了并行執行上萬次操作的問題。例如,把前面的程序改為并行執行8次:可以用2個Block,每個Block中有4個Thread。原來的代碼可以改為gpu_func[2, 4](),其中方括號中第一個數字表示整個Grid有多少個Block,方括號中第二個數字表示一個Block有多少個Thread。
????????CUDA提供了一系列內置變量,以記錄Thread和Block的大小及索引下標。以[2, 4]這樣的配置為例:blockDim.x變量表示Block的大小是4,即每個Block有4個Thread,threadIdx.x變量是一個從0到blockDim.x - 1(4-1=3)的索引下標,記錄這是第幾個Thread;gridDim.x變量表示Grid的大小是2,即每個Grid有2個Block,blockIdx.x變量是一個從0到gridDim.x - 1(2-1=1)的索引下標,記錄這是第幾個Block。
某個Thread在整個Grid中的位置編號為:threadIdx.x + blockIdx.x * blockDim.x。
?將CPU的代碼改進一下就能得到:
import numba as nb import numpy as np from numba import cuda #檢測一下GPU是否可用 print(cuda.gpus)#把數據導入到data里面 f = open(r'source.txt') data = f.read().split(" ") while '' in data:data.remove('') data = np.array(data, dtype = int)@cuda.jit def nb_func(out,data):# j定義為這個thread在所在的block塊中的位置(0 <= j <= 761)j = cuda.threadIdx.x# i定義為這個block塊在gird中的位置(0 <= i <= 1199)i = cuda.blockIdx.xfor k in range(128):for n in range(128):order = round((((i * i + (j - k * 6) * (j - k * 6)) ** 0.5 + (i * i + (j - n * 6) * (j - n * 6)) ** 0.5) * 0.05) / 1.54 * 30)if (order < 2000):out[j][i] = out[j][i] + data[k * 2000 + order]#將data數據拷貝到GPU data_device=cuda.to_device(data)#在GPU里開辟一塊空間存放圖像數組 out_device=cuda.device_array([762,1200])#運行nb_func()函數 nb_func[1200,762](out_device,data_device)#最后將圖像數據從GPU拷貝回CPU out = out_device.copy_to_host() print(out)?最后耗時約25s,其中并行運算的僅耗時0.5s,將數據從GPU拷貝回CPU耗時24.5s
輸出:
?
Reference:初識GPU編程 | Weizheng
總結
以上是生活随笔為你收集整理的python使用numba库实现gpu加速的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: laravel路由
- 下一篇: 如何用私钥登陆linux服务器和cybe