CuPyはNumPyとSciPyで記述されたCPU用のプログラムをGPUで動かすためのツールです。
簡単な移植作業により、GPUの高い計算性能を生かして高速に計算することができます。
リスト5-1にCuPyを用いてベクトル和とベクトル内積を計算するプログラムを示します。
計算時間を正確に測定するためにEventクラスを使用しています。
リスト5-1 CuPyによるベクトル和のベクトル内積のソースコード
(vector_cupy.py)
""" vector_cupy.py test program of vector operations CuPy """ import numpy as np import cupy as cp # (vadd) add two vectors : CuPy + NumPy version def vadd(a, b): return a + b # (sdot-1) scalar product of two vectors : CuPy version def sdot_cupy(a, b): return cp.dot(a, b) # (sdot-2) scalar product of two vectors : NumPy version def sdot_numpy(a, b): return np.dot(a, b) # parameters N = 100000000 L = 100 dtype = 'f4' # 'f4' or 'f8' fn = 'vadd-1' #fn = 'sdot-1' # timer start = cp.cuda.Event() end = cp.cuda.Event() start.record() # setup a = np.arange(N).astype(dtype) b = np.arange(N).astype(dtype) if fn.startswith('vadd'): c = np.zeros(N, dtype) # copy to device d_a = cp.array(a) d_b = cp.array(b) if fn.startswith('vadd'): d_c = cp.array(c) # timer end.record() end.synchronize() t1 = cp.cuda.get_elapsed_time(start, end) start.record() # calculation for _ in range(L): if fn == 'vadd-1': d_c = vadd(d_a, d_b) elif fn == 'vadd-2': c = vadd(a, b) elif fn == 'sdot-1': s = sdot_cupy(d_a, d_b) elif fn == 'sdot-2': s = sdot_numpy(a, b) # timer end.record() end.synchronize() t2 = cp.cuda.get_elapsed_time(start, end) # check if fn == 'vadd-1': c = cp.asnumpy(d_c) r1 = np.sum(c) r2 = N * (N - 1) elif fn == 'vadd-2': r1 = np.sum(c) r2 = N * (N - 1) else: r1 = s r2 = N * (N - 1) * (2 * N - 1) / 6 # output print('(%s) N=%d, L=%d' % (fn, N, L)) print('%.2f+%.2f[sec], %e, %e' % (t1 * 1e-3, t2 * 1e-3, r1, r2)) # free a = None b = None d_a = None d_b = None if fn.startswith('vadd'): c = None d_c = None
CuPyのNumPyとの主な違いは以下の通りです。
表5-1にCuPyのベクトル和とベクトル内積の計算時間を示します。
配列の大きさ(=N)と繰り返し回数(=L)の積は一定(=1010)です。
従って全体の演算量は同じです。
No. | 配列の大きさN | 繰り返し回数L | ベクトル和 | ベクトル内積 | ||
---|---|---|---|---|---|---|
単精度 | 倍精度 | 単精度 | 倍精度 | |||
1 | 100,000,000 | 100 | 0.49秒 | 1.00秒 | 0.65秒 | 1.30秒 |
2 | 10,000,000 | 1,000 | 0.50秒 | 0.99秒 | 0.66秒 | 1.33秒 |
3 | 1,000,000 | 10,000 | 0.52秒 | 1.03秒 | 0.94秒 | 1.44秒 |
4 | 100,000 | 100,000 | 2.34秒 | 2.49秒 | 9.78秒 | 9.90秒 |
5 | 10,000 | 1,000,000 | 28.48秒 | 27.34秒 | 99.60秒 | 98.78秒 |
表5-1から以下のことがわかります。