Python3+pycuda實(shí)現(xiàn)執(zhí)行簡(jiǎn)單GPU計(jì)算任務(wù)
技術(shù)背景
GPU的加速技術(shù)在深度學(xué)習(xí)、量子計(jì)算領(lǐng)域都已經(jīng)被廣泛的應(yīng)用。其適用的計(jì)算模型是小內(nèi)存的密集型計(jì)算場(chǎng)景,如果計(jì)算的模型內(nèi)存較大,則需要使用到共享內(nèi)存,這會(huì)直接導(dǎo)致巨大的數(shù)據(jù)交互的運(yùn)算量,通信開(kāi)銷較大。因?yàn)閜ycuda的出現(xiàn),也使得我們可以直接在python內(nèi)直接使用GPU函數(shù),當(dāng)然也可以直接在python代碼中集成一些C++的代碼,用于構(gòu)建GPU計(jì)算的函數(shù)。有一個(gè)專門(mén)介紹pycuda使用案例的中文開(kāi)源代碼倉(cāng)可以簡(jiǎn)單參考一些實(shí)現(xiàn)的示例,但是這里面的示例數(shù)量還是比較有限,更多的案例可以直接參考pycuda官方文檔。
pycuda環(huán)境配置
pycuda的安裝環(huán)境很大程度上取決約顯卡驅(qū)動(dòng)本身是否能夠安裝成功,除了安裝pycuda庫(kù)本身之外,重點(diǎn)是需要確保如下的指令可以運(yùn)行成功:
[dechin@dechin-manjaro pycuda]$ nvidia-smi
Sun Mar 21 20:26:43 2021
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 455.45.01 Driver Version: 455.45.01 CUDA Version: 11.1 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 GeForce MX250 Off | 00000000:3C:00.0 Off | N/A |
| N/A 48C P0 N/A / N/A | 0MiB / 2002MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
上述返回的結(jié)果是一個(gè)沒(méi)有GPU任務(wù)情況下的展示界面,包含有顯卡型號(hào)、顯卡內(nèi)存等信息。如果存在執(zhí)行的任務(wù),則顯示結(jié)果如下案例所示:
[dechin@dechin-manjaro pycuda]$ nvidia-smi
Sun Mar 21 20:56:04 2021
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 455.45.01 Driver Version: 455.45.01 CUDA Version: 11.1 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 GeForce MX250 Off | 00000000:3C:00.0 Off | N/A |
| N/A 47C P0 N/A / N/A | 31MiB / 2002MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| 0 N/A N/A 18427 C python3 29MiB |
+-----------------------------------------------------------------------------+
我們發(fā)現(xiàn)這里多了一個(gè)pid為18427的python的進(jìn)程正在使用GPU進(jìn)行計(jì)算。在運(yùn)算過(guò)程中,如果任務(wù)未能夠執(zhí)行成功,有可能在內(nèi)存中遺留一個(gè)進(jìn)程,這需要我們自己手動(dòng)去釋放。最簡(jiǎn)單粗暴的方法就是:直接使用kill -9 pid來(lái)殺死殘留的進(jìn)程。我們可以使用pycuda自帶的函數(shù)接口,也可以自己寫(xiě)C++代碼來(lái)實(shí)現(xiàn)GPU計(jì)算的相關(guān)功能,當(dāng)然一般情況下更加推薦使用pycuda自帶的函數(shù)。以下為一部分已經(jīng)實(shí)現(xiàn)的接口函數(shù),比如gpuarray的函數(shù):

再比如cumath的函數(shù):

使用GPU計(jì)算向量指數(shù)
對(duì)于一個(gè)向量的指數(shù)而言,其實(shí)就是將每一個(gè)的向量元素取指數(shù)。當(dāng)然,這與前面一篇關(guān)于量子門(mén)操作的博客中介紹的矩陣指數(shù)略有區(qū)別,這點(diǎn)要注意區(qū)分。
在下面的示例中,我們對(duì)比了numpy中實(shí)現(xiàn)的指數(shù)運(yùn)算和pycuda中實(shí)現(xiàn)的指數(shù)運(yùn)算。
# array_exp.py
import pycuda.autoinit
import pycuda.gpuarray as ga
import pycuda.cumath as gm
import numpy as np
import sys
if sys.argv[1] == '-l':
length = int(sys.argv[2]) # 從命令行獲取參數(shù)值
np.random.seed(1)
array = np.random.randn(length).astype(np.float32)
array_gpu = ga.to_gpu(array)
exp_array = np.exp(array)
print (exp_array)
exp_array_gpu = gm.exp(array_gpu)
gpu_exp_array = exp_array_gpu.get()
print (gpu_exp_array)
這里面我們計(jì)算一個(gè)隨機(jī)向量的指數(shù),向量的維度length是從命令行獲取的一個(gè)參數(shù),上述代碼的執(zhí)行方式和執(zhí)行結(jié)果如下所示:
[dechin@dechin-manjaro pycuda]$ python3 array_exp.py -l 5
[5.0750957 0.5423974 0.58968204 0.34199178 2.3759744 ]
[5.075096 0.5423974 0.58968204 0.34199178 2.3759747 ]
我們先確保兩者計(jì)算出來(lái)的結(jié)果是一致的,這里我們可以觀察到,兩個(gè)計(jì)算的結(jié)果只保障了7位的有效數(shù)字是相等的,這一點(diǎn)在大部分的場(chǎng)景下精度都是有保障的。接下來(lái)我們使用timeit來(lái)統(tǒng)計(jì)和對(duì)比兩者的性能:
# array_exp.py
import pycuda.autoinit
import pycuda.gpuarray as ga
import pycuda.cumath as gm
import numpy as np
import sys
import timeit
if sys.argv[1] == '-l':
length = int(sys.argv[2])
np.random.seed(1)
array = np.random.randn(length).astype(np.float32)
array_gpu = ga.to_gpu(array)
def npexp():
exp_array = np.exp(array)
def gmexp():
exp_array_gpu = gm.exp(array_gpu)
# gpu_exp_array = exp_array_gpu.get()
if __name__ == '__main__':
n = 1000
t1 = timeit.timeit('npexp()', setup='from __main__ import npexp', number=n)
print (t1)
t2 = timeit.timeit('gmexp()', setup='from __main__ import gmexp', number=n)
print (t2)
這里也順便介紹一下timeit的使用方法:這個(gè)函數(shù)的輸入分別是:函數(shù)名、函數(shù)的導(dǎo)入方式、函數(shù)的重復(fù)次數(shù)。這里需要特別說(shuō)明的是,如果在函數(shù)的導(dǎo)入方式中,不使用__main__函數(shù)進(jìn)行導(dǎo)入,即使是本文件下的python函數(shù),也是無(wú)法被導(dǎo)入成功的。在輸入的向量達(dá)到一定的規(guī)模大小時(shí),我們發(fā)現(xiàn)在執(zhí)行時(shí)間上相比于numpy有非常大的優(yōu)勢(shì)。當(dāng)然還有一點(diǎn)需要注意的是,由于我們測(cè)試的是計(jì)算速度,原本使用了get()函數(shù)將GPU中計(jì)算的結(jié)果進(jìn)行導(dǎo)出,但是這部分其實(shí)不應(yīng)該包含在計(jì)算的時(shí)間內(nèi),因此后來(lái)又注釋掉了。具體的測(cè)試數(shù)據(jù)如下所示:
[dechin@dechin-manjaro pycuda]$ python3 array_exp.py -l 10000000
26.13127974300005
3.469969915000547
總結(jié)概要
使用GPU來(lái)進(jìn)行計(jì)算,可以極大程度上的加速我們所需要計(jì)算的任務(wù),這得益于GPU強(qiáng)大的自帶的并行化技術(shù)。pycuda的出現(xiàn),使得我們不需要手工去寫(xiě)GPU的C或者C++代碼也可以調(diào)用GPU來(lái)進(jìn)行計(jì)算,還提供了眾多的python接口可以直接使用。經(jīng)過(guò)測(cè)試,本文給出了一些pycuda的基本使用方法示例,以及初步的測(cè)試結(jié)果,從測(cè)試結(jié)果中我們進(jìn)一步明確了pycuda的高性能特性。
到此這篇關(guān)于Python3+pycuda實(shí)現(xiàn)執(zhí)行簡(jiǎn)單GPU計(jì)算任務(wù)的文章就介紹到這了,更多相關(guān)Python pycuda計(jì)算GPU內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Python求解帶約束的最優(yōu)化問(wèn)題詳解
今天小編就為大家分享一篇使用Python求解帶約束的最優(yōu)化問(wèn)題詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-02-02
Django 實(shí)現(xiàn)admin后臺(tái)顯示圖片縮略圖的例子
今天小編就為大家分享一篇Django 實(shí)現(xiàn)admin后臺(tái)顯示圖片縮略圖的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07
使用python編寫(xiě)批量卸載手機(jī)中安裝的android應(yīng)用腳本
該腳本的功能是卸載android手機(jī)中安裝的所有第三方應(yīng)用,主要是使用adb shell pm、adb uninstall 命令,需要的朋友可以參考下2014-07-07
python web框架中實(shí)現(xiàn)原生分頁(yè)
這篇文章主要為大家詳細(xì)介紹了python web框架中使用原生分頁(yè)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09
解決python腳本中error: unrecognized arguments: True錯(cuò)誤
這篇文章主要介紹了解決python腳本中error: unrecognized arguments: True錯(cuò)誤,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-04-04
python使用flask與js進(jìn)行前后臺(tái)交互的例子
今天小編就為大家分享一篇python使用flask與js進(jìn)行前后臺(tái)交互的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-07-07

