環境 win10, visual studio 2019, pycuda 2019.02,
在你使用pycuda之前,要先用import命令來匯入並初始化一下。
import pycuda.driver as cuda
import pycuda.autoinit
from pycuda.compiler import sourcemodule
這裡要注意,你並不是必須使用 pycuda.autoinit,如果你願意的話,初始化、內容的建立和清理也都可以手動實現。
接下來就是要把資料傳輸到裝置(device)上了。一般情況下,在使用pycuda的時候,你主要是傳輸主機host上的numpy陣列。(不過實際上,只要符合python緩衝區介面的資料型別就都可以使用的,甚至連字串型別str都可以。)下面這行示例**建立了乙個隨機數組成的4*4大小的陣列a:
import numpy
a = numpy.random.randn(4,
4)
不過要先暫停一下—咱們剛剛建立的這個陣列a包含的是雙精度浮點數,但大多數常用的nvidia顯示卡只支援單精度浮點數,所以需要轉換一下型別:
a = a.astype(numpy.float32)
接下來,要把已有的資料轉移過去,還要設定乙個目的地,所以我們要在顯示卡中分配一段視訊記憶體:
a_gpu = cuda.mem_alloc(a.nbytes)
最後,咱們把剛剛生成的陣列a轉移到gpu裡面吧:
cuda.memcpy_htod(a_gpu, a)
咱們這篇簡介爭取說的都是最簡單的內容:咱們寫乙個**來把a_gpu這段視訊記憶體中儲存的陣列的每乙個值都乘以2. 為了實現這個效果,我們就要寫一段cuda c**,然後把這段**提交給乙個建構函式,這裡用到了pycuda.compiler.sourcemodule:
mod = sourcemodule(
""" __global__ void doublify(float *a)
""")
這一步如果沒有出錯,就說明這段**已經編譯成功,並且載入到顯示卡中。然後咱們可以使用pycuda.driver.function
,然後呼叫此引用,把視訊記憶體中的陣列a_gpu作為引數傳過去,同時設定塊大小為4x4:
func = mod.get_function(
"doublify"
)func(a_gpu, block=(4
,4,1
))
最後,咱們就把經過運算處理過的資料從gpu取回,並且將它和原始陣列a一同顯示出來對比一下:
a_doubled = numpy.empty_like(a)
cuda.memcpy_dtoh(a_doubled, a_gpu)
print
(a_doubled)
print
(a)
輸出的效果大概就是如下所示:
[[ 0.51360393 1.40589952 2.25009012 3.02563429]
[-0.75841576 -1.18757617 2.72269917 3.12156057]
[ 0.28826082 -2.92448163 1.21624792 2.86353827]
[ 1.57651746 0.63500965 2.21570683 -0.44537592]]
[[ 0.25680196 0.70294976 1.12504506 1.51281714]
[-0.37920788 -0.59378809 1.36134958 1.56078029]
[ 0.14413041 -1.46224082 0.60812396 1.43176913]
[ 0.78825873 0.31750482 1.10785341 -0.22268796]]
出現上面這樣輸出就說明成功了!整個攻略就完成了。另外很值得慶幸的是,執行輸出之後pycuda就會把所有清理和記憶體**工作做好了,咱們的簡介也就完畢了。不過你可以再看一下接下來的內容,裡面有一些有意思的東西。
pycuda提供了pycuda.driver.in, pycuda.driver.out, 以及pycuda.driver.inout 這三個引數處理器(argument handlers),能用來簡化記憶體和視訊記憶體之間的資料拷貝。例如,咱們可以不去建立乙個a_gpu,而是直接把a移動過去,下面的**就可以實現:
func(cuda.inout(a), block=(4, 4, 1))
有準備地呼叫函式
使用內建的pycuda.driver.function.call() 方法來進行的函式呼叫,會增加型別識別的資源開銷(參考顯示卡介面)。 要實現跟上面**同樣的效果,又不造成這種開銷,這個函式就需要設定好引數型別(如python的標準庫中的結構體模組struct所示),然後再去呼叫該函式。這樣也就不用需要再使用numpy.number類去制定引數的規模了:
grid =(1
,1)block =(4
,4,1
)func.prepare(
"p")
func.prepared_call(grid, block, a_gpu)
饋贈:抽象以降低複雜度
使用 pycuda.gpuarray.gpuarray,同樣效果的**實現起來就更加精簡了:
import pycuda.gpuarray as gpuarray
import pycuda.driver as cuda
import pycuda.autoinit
import numpy
a_gpu = gpuarray.to_gpu(numpy.random.randn(4,
4).astype(numpy.float32)
)a_doubled =(2
*a_gpu)
.get(
)print a_doubled
print a_gpu
GPU共享記憶體小結 pycuda
先來點題外話,由於導師的要求使用gpu加速但是又沒有系統的學習就開始了使用pycuda進行gpu的程式設計,變用邊學。在優化程式的時候shared memory是必用的,所以理解共享記憶體是個什麼東西才可以做到自己對資料是如何跑的有數。先看看這張gpu的儲存結構圖 偷的圖,哈哈 在圖中我們關心的重點...
PyCuda學習一之 Helloword
安裝網上有教程,ps 如果是win系統的話,最好先安裝vs,在安裝cuda 匯入必要的庫 import pycuda.driver as cuda import pycuda.autoinit from pycuda.compiler import sourcemodule 建立乙個4 4的陣列,並...
pycuda安裝報錯(已解決)
在安裝pycuda的過程中,出現找不到cuda.件,出現這種問題有倆種原因 1.確實沒有找到cuda.件,原因是環境變數沒有包含cuda路徑,開啟 bashrc新增環境路徑 export c include path usr local cuda 9.0 include export cplus i...