PyCUDA Tutorial:基礎中の基礎編 その1

pycudaが使えるのは良く分かったが、pycudaを実際にどう使っていいのか全く分からないので、とりあえず、pycudaの簡単なチュートリアルを実践してみた。

スポンサーリンク

必要なmoduleのimport

pycudaを使えるようにするには、以下のような事前準備が必要。

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)
[[-5.4600463   2.8155563   0.43376884  3.3224792 ]
 [-1.1481057   0.48839888  2.2067583  -0.03688723]
 [ 0.58235794 -0.15110129 -1.088815    2.9215548 ]
 [ 5.7338758   2.326712   -2.2736397  -0.29396093]]
[[-2.7300231   1.4077781   0.21688442  1.6612396 ]
 [-0.5740529   0.24419944  1.1033791  -0.01844361]
 [ 0.29117897 -0.07555065 -0.5444075   1.4607774 ]
 [ 2.8669379   1.163356   -1.1368198  -0.14698046]]

上が関数doublifyによって倍増された値で、下がオリジナルのaの値

まずはこのコードを完全に理解するところから始めるしかない。

参考サイトhttps://documen.tician.de