pycudaが使えるのは良く分かったが、pycudaを実際にどう使っていいのか全く分からないので、とりあえず、pycudaの簡単なチュートリアルを実践してみた。
必要なmoduleのimport¶
import pycuda.driver as cuda
import pycuda.autoinit
from pycuda.compiler import SourceModule
pycuda.autoinitは使わなければならないわけではなく、初期化やコンテクスト作成やクリーンアップは、必要に応じて手動で行える。
データ転送¶
次に、データをデバイスに転送する。PyCudaでは、たいていホスト上のnumpyアレイからデータを転送する。例として、4×4の乱数アレイを作る。
import numpy
a = numpy.random.randn(4,4)
これだと倍精度数が含まれてしまっているが、ほとんどのnvidiaデバイスは単精度しかサポートしていない。
a = a.astype(numpy.float32)
最後に、どこかデータを転送する場所が必要なので、デバイス上のメモリを確保する必要が生じる。
a_gpu = cuda.mem_alloc(a.nbytes)
最終段階として、データをGPUへ転送する。
cuda.memcpy_htod(a_gpu, a)
カーネルを実行する¶
次にGPUに転送されたデータを倍増させるカーネルコードを書く。この目的を達成するために、それに対応したCUDA Cコードを書き、それをpycuda.compiler.SourceModuleのコンストラクターへフィードする。
mod = SourceModule("""
__global__ void doublify(float *a)
{
int idx = threadIdx.x + threadIdx.y*4;
a[idx] *= 2;
}
""")
エラーがなければコードはコンパイルされ、デバイス上にロードされる。pycuda.driver.Functionへのリファレンスを探して、それを呼び出してa_gpuを引数に、ブロックサイズを4×4に指定する。
func = mod.get_function("doublify")
func(a_gpu, block=(4,4,1))
最後に、オリジナルのaと共にデータをGPUからフェッチして表示する。
a_doubled = numpy.empty_like(a)
cuda.memcpy_dtoh(a_doubled, a_gpu)
print (a_doubled)
print (a)
上が関数doublifyによって倍増された値で、下がオリジナルのaの値
まずはこのコードを完全に理解するところから始めるしかない。