ショートストーリー: 「初めてのGPU CUDAプログラミング」
陽介はコンピュータサイエンスを専攻する大学生で、卒業研究のテーマとしてGPUプログラミングに挑戦することを決めた。彼はこれまでCPUを使ったプログラミングには慣れていたが、GPUについては全くの初心者だった。卒業研究の初日に、彼の指導教官である田中教授は、簡単な課題を出した。
「陽介、今日は初めてのGPUプログラミングの課題として、配列の各要素を2倍にするプログラムを作ってみてくれ。PythonとPyCUDAを使って、これをGoogle Colab上で実行するんだ。」
陽介は教授の指示に従い、まずPyCUDAの使い方を調べ始めた。Google Colabにアクセスし、PyCUDAのインストールから始めた。彼の目の前の画面には、PyCUDAのインストールコマンドが入力されていた。
# PyCUDAのインストール
!pip install pycuda
次に、陽介は教授が指定した通りに、CUDAカーネルをPythonコードに書き込み始めた。彼はまだ少し緊張していたが、一つ一つのステップを確実に進めた。
import pycuda.driver as cuda
import pycuda.autoinit
from pycuda.compiler import SourceModule
import numpy as np
# CUDAカーネル
kernel_code = """
__global__ void doubleElements(int *d_array, int size) {
int index = threadIdx.x + blockIdx.x * blockDim.x;
if (index < size) {
d_array[index] *= 2;
}
}
"""
# カーネルをコンパイル
mod = SourceModule(kernel_code)
double_elements = mod.get_function("doubleElements")
# ホスト側のデータ
h_array = np.array([1, 2, 3, 4, 5], dtype=np.int32)
# デバイス側のデータ
d_array = cuda.mem_alloc(h_array.nbytes)
cuda.memcpy_htod(d_array, h_array)
# カーネルの起動
block_size = 256
grid_size = (h_array.size + block_size - 1) // block_size
double_elements(d_array, np.int32(h_array.size), block=(block_size, 1, 1), grid=(grid_size, 1, 1))
# 結果をホスト側にコピー
cuda.memcpy_dtoh(h_array, d_array)
# 結果を表示
print("Result:", h_array)
プログラムを書き終えた陽介は、緊張しながら実行ボタンを押した。コンソールに表示されるインストールと実行のメッセージを見つめながら、心臓が高鳴るのを感じていた。やがて、結果が表示された。
Result: [ 2 4 6 8 10]
陽介の顔に笑みが広がった。「やった、成功だ!」彼は声をあげた。自分が初めて書いたGPUプログラムが正しく動作したことに、達成感と満足感が湧き上がった。
その日、陽介はGPUプログラミングの楽しさとその力強さを初めて実感した。教授から出された簡単な課題であったが、それは彼にとって大きな一歩だった。これを機に、陽介はもっと高度なGPUプログラミングの世界に踏み出す決意を固めた。
PyCUDAはPythonからCUDAを呼び出すためのライブラリです。以下にPyCUDAを使って同様の配列の要素を2倍にする例を示します。
まず、Google ColabのノートブックでPyCUDAをインストールします。
!pip install pycuda
import pycuda.driver as cuda
import pycuda.autoinit
from pycuda.compiler import SourceModule
import numpy as np
# CUDAカーネル
kernel_code = """
__global__ void doubleElements(int *d_array, int size) {
int index = threadIdx.x + blockIdx.x * blockDim.x;
if (index < size) {
d_array[index] *= 2;
}
}
"""
# カーネルをコンパイル
mod = SourceModule(kernel_code)
double_elements = mod.get_function("doubleElements")
# ホスト側のデータ
h_array = np.array([1, 2, 3, 4, 5], dtype=np.int32)
# デバイス側のデータ
d_array = cuda.mem_alloc(h_array.nbytes)
cuda.memcpy_htod(d_array, h_array)
# カーネルの起動
block_size = 256
grid_size = (h_array.size + block_size - 1) // block_size
double_elements(d_array, np.int32(h_array.size), block=(block_size, 1, 1), grid=(grid_size, 1, 1))
# 結果をホスト側にコピー
cuda.memcpy_dtoh(h_array, d_array)
# 結果を表示
print("Result:", h_array)
説明
CUDAカーネルの定義: CUDAカーネル関数をPythonの文字列として定義します。
カーネルのコンパイル: SourceModuleを使ってカーネルコードをコンパイルし、カーネル関数を取得します。
ホスト側のデータ: NumPy配列としてホスト側のデータを準備します。
デバイス側のデータ: CUDAメモリを割り当て、ホスト側のデータをデバイス側にコピーします。
カーネルの起動: double_elements関数を呼び出してカーネルを起動します。
結果のコピー: 結果をデバイスからホストにコピーします。
結果の表示: 計算結果を表示します。
この方法により、Google Colab上でPyCUDAを使ってCUDAプログラムを実行することができます。
思ったより難しくなさそうですね。GPU CUDAプログラミング。