




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第關于Python的GPU編程實例近鄰表計算的講解GPU加速是現代工業各種場景中非常常用的一種技術,這得益于GPU計算的高度并行化。在Python中存在有多種GPU并行優化的解決方案,包括之前的博客中提到的cupy、pycuda和numba.cuda,都是GPU加速的標志性Python庫。這里我們重點推numba.cuda這一解決方案,因為cupy的優勢在于實現好了的眾多的函數,在算法實現的靈活性上還比較欠缺;而pycuda雖然提供了很好的靈活性和相當高的性能,但是這要求我們必須在Python的代碼中插入C代碼,這顯然是非常不Pythonic的解決方案。因此我們可以選擇numba.cuda這一解決方案,只要在Python函數前方加一個numba.cuda.jit的修飾器,就可以在Python中用最Python的編程語法,實現GPU的加速效果。
加速場景
我們需要先了解的是,GPU在什么樣的計算場景下能夠實現加速的效果,很顯然的是,并不是所有的計算過程都能在GPU上表現出加速的效果。前面說道,GPU的加速作用,是源自于高度的并行化,所謂的并行,就要求進程之前互不干擾或者依賴。如果說一個進程的計算過程或者結果,依賴于另一個進程中的計算結果,那么就無法實現完全的并行,只能使用串行的技術。這里為了展示GPU加速的效果,我們就引入一個在分子動力學模擬領域中常見的問題:近鄰表的計算。
近鄰表計算的問題是這樣描述的:給定一堆數量為n的原子系統,每一個原子的三維坐標都是已知的,給定一個截斷常數d0,當兩個原子之間的距離di,j=d0時,則認為這兩個原子是相鄰近的原子。那么最終我們需要給出一個0-1矩陣Ai,j,當Ai,j=0時,表示i,j兩個原子互不相鄰,反之則相鄰。那么對于這個問題場景,我們就可以并行化的遍歷n×n的空間,直接輸出An×n大小的近鄰表。這個計算場景是一個非常適合用GPU來加速的計算,以下我們先看一下不用GPU加速時的常規實現方案:
#cuda_neighbor_list.py
fromnumbaimportjit
fromnumbaimportcuda
importnumpyasnp
defneighbor_list(crd,neighbors,data_length,cutoff):
"""CPUbasedneighborlistcalculation.
foriinrange(data_length):
forjinrange(i+1,data_length):
ifnp.linalg.norm(crd[i]-crd[j])=cutoff:
neighbors[i][j]=1
neighbors[j][i]=1
returnneighbors
if__name__=='__main__':
np.random.seed(1)
atoms=2**2
cutoff=0.5
crd=np.random.random((atoms,3))
adjacent=np.zeros((atoms,atoms))
adjacent=neighbor_list(crd,adjacent,atoms,cutoff)
print(adjacent)
這是最常規的一種CPU上的實現方案,遍歷所有的原子,計算原子間距,然后填充近鄰表。這里我們還使用到了numba.jit即時編譯的功能,這個功能是在執行到相關函數時再對其進行編譯的方法,在矢量化的計算中有可能使用到芯片廠商所提供的SIMD的一些優化。當然,這里都是CPU層面的執行和優化,執行結果如下:
$python3cuda_neighbor_list.py
[[0.0.0.0.]
[0.0.1.0.]
[0.1.0.1.]
[0.0.1.0.]]
這個輸出的結果就是一個0-1近鄰表。
基于Numba的GPU加速
對于上述的近鄰表計算的場景,我們很容易的想到這個neighbor_list函數可以用GPU的函數來進行改造。對于每一個di,j我們都可以啟動一個線程去執行計算,類似于CPU上的SIMD技術,GPU中的這項優化稱為SIMT。而在Python中改造成GPU函數的方法也非常簡單,只需要把函數前的修飾器改一下,去掉函數內部的for循環,就基本完成了,比如下面這個改造的近鄰表計算的案例:
#cuda_neighbor_list.py
fromnumbaimportjit
fromnumbaimportcuda
importnumpyasnp
defneighbor_list(crd,neighbors,data_length,cutoff):
"""CPUbasedneighborlistcalculation.
foriinrange(data_length):
forjinrange(i+1,data_length):
ifnp.linalg.norm(crd[i]-crd[j])=cutoff:
neighbors[i][j]=1
neighbors[j][i]=1
returnneighbors
@cuda.jit
defcuda_neighbor_list(crd,neighbors,cutoff):
"""GPUbasedneighborlistcalculation.
i,j=cuda.grid(2)
dis=((crd[i][0]-crd[j][0])**2+\
(crd[i][1]-crd[j][1])**2+\
(crd[i][2]-crd[j][2])**2)**0.5
neighbors[i][j]=dis=cutoff[0]anddis0
if__name__=='__main__':
importtime
np.random.seed(1)
atoms=2**5
cutoff=0.5
cutoff_cuda=cuda.to_device(np.array([cutoff]).astype(np.float32))
crd=np.random.random((atoms,3)).astype(np.float32)
crd_cuda=cuda.to_device(crd)
adjacent=np.zeros((atoms,atoms)).astype(np.float32)
adjacent_cuda=cuda.to_device(adjacent)
time0=time.time()
adjacent_c=neighbor_list(crd,adjacent,atoms,cutoff)
time1=time.time()
cuda_neighbor_list[(atoms,atoms),(1,1)](crd_cuda,
adjacent_cuda,
cutoff_cuda)
time2=time.time()
adjacent_g=adjacent_cuda.copy_to_host()
print('ThetimecostofCPUwithnumba.jitis:{}s'.format(\
time1-time0))
print('ThetimecostofGPUwithcuda.jitis:{}s'.format(\
time2-time1))
print('Theresulterroris:{}'.format(np.sum(adjacent_c-\
adjacent_g)))
需要說明的是,當前Numba并未支持所有的numpy的函數,因此有一些計算的功能需要我們自己去手動實現一下,比如計算一個Norm的值。這里我們在輸出結果中不僅統計了結果的正確性,也給出了運行的時間:
$python3cuda_neighbor_list.py
ThetimecostofCPUwithnumba.jitis:0.6401469707489014s
ThetimecostofGPUwithcuda.jitis:0.19208502769470215s
Theresulterroris:0.0
需要說明的是,這里僅僅運行了一次的程序,而jit即時編譯的加速效果在第一次的運行中其實并不明顯,甚至還有一些速度偏慢,但是在后續過程的函數調用中,就能夠起到比較大的加速效果。所以這里的運行時間并沒有太大的代表性,比較有代表性的時間對比可以看如下的案例:
#cuda_neighbor_list.py
fromnumbaimportjit
fromnumbaimportcuda
importnumpyasnp
defneighbor_list(crd,neighbors,data_length,cutoff):
"""CPUbasedneighborlistcalculation.
foriinrange(data_length):
forjinrange(i+1,data_length):
ifnp.linalg.norm(crd[i]-crd[j])=cutoff:
neighbors[i][j]=1
neighbors[j][i]=1
returnneighbors
@cuda.jit
defcuda_neighbor_list(crd,neighbors,cutoff):
"""GPUbasedneighborlistcalculation.
i,j=cuda.grid(2)
dis=((crd[i][0]-crd[j][0])**2+\
(crd[i][1]-crd[j][1])**2+\
(crd[i][2]-crd[j][2])**2)**0.5
neighbors[i][j]=dis=cutoff[0]anddis0
if__name__=='__main__':
importtime
np.random.seed(1)
atoms=2**10
cutoff=0.5
cutoff_cuda=cuda.to_device(np.array([cutoff]).astype(np.float32))
crd=np.random.random((atoms,3)).astype(np.float32)
crd_cuda=cuda.to_device(crd)
adjacent=np.zeros((atoms,atoms)).astype(np.float32)
adjacent_cuda=cuda.to_device(adjacent)
time_c=0.0
time_g=0.0
for_inrange(100):
time0=time.time()
adjacent_c=neighbor_list(crd,adjacent,atoms,cutoff)
time1=time.time()
cuda_neighbor_list[(atoms,atoms),(1,1)](crd_cuda,
adjacent_cuda,
cutoff_cuda)
time2=time.time()
if_!=0:
time_c+=time1-time0
time_g+=time2-time1
print('ThetotaltimecostofCPUwithnumba.jitis:{}s'.format(\
time_c))
print('ThetotaltimecostofGPUwithcuda.jitis:{}s'.format(\
ti
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 經濟法的社會價值試題及答案
- 知識更新2025年試題及答案
- 2025年行政管理自考課堂試題及答案
- 執業藥師考試錄取標準與試題及答案
- 行政管理專科考試真題及答案
- 2025年行政管理中國文化概論的復習資料試題及答案
- 2025年經濟法復習實例分享試題及答案
- 行政管理專科自考真題與答案分析
- 大學語文課程試題及答案
- 行政法的司法解釋問題試題與答案
- 2025年游戲開發與設計專業考試試卷及答案
- 美術高考集訓班協議合同
- 中國證券經營行業市場發展現狀分析及發展趨勢與投資前景研究報告
- 職業技術學院食品質量與安全專業《食品化學》課程標準
- 貿易人居間合同協議
- 《肺結核的診斷與治療》課件
- 陜西省咸陽市2025屆高三下學期高考模擬檢測(三)物理試題(含答案)
- 浙江省溫州市2023-2024學年高一下學期期末考試語文試卷(含答案)
- (高清版)DB3301∕T 0411-2023 公共汽電車維修車間建設與管理規范
- 激光應用技術發展路徑試題及答案
- 期權開戶考試題及答案
評論
0/150
提交評論