この記事の内容
- Numpy-LikeなAPIを持ち、CUDAによってGPUを計算リソースとして使えるCuPyというライブラリがあります。
- このライブラリをちょっと試してみたら非常に高速だったので、どのくらい早かったかちょっとまとめてみました。
環境
- Hardware
- CPU Intel Core i7-8700
- GPU Nvidia GeForce GTX 1080
- Software
- Ubuntu 16.04
- CUDA 9.0
- Python 3.6
- numpy 1.14.5
- cupy 4.2.0
お題
速度比較のために簡単な問題を設定してみます。
ある100次元のベクトルaと、同じく100次元のベクトルbとのユークリッド距離を求めるとします。
Numpyで書くとこうなります。
import numpy
a = numpy.random.rand(100)
b = numpy.random.rand(100)
numpy.linalg.norm(a - b)
次に、100次元のベクトルが1000000含まれる集合Bがあるとします。
先ほどのaとBに含まれる各ベクトルとの距離をすべて計算してみましょう。
a = numpy.random.rand(100)
B = numpy.random.rand(1000000, 100)
[numpy.linalg.norm(a - b) for b in B]
IPythonに含まれる%%timeitで測定してみると3.48 s ± 10.1 ms程度の時間が掛かっていました。
今回は、この処理をNumpyのブロードキャストとCuPyに置き換えることでそれぞれどの程度高速化するか調べてみます。
Numpyのブロードキャスト
先ほどのコードと同じ処理をNumpyのブロードキャストを使って書き直します。
numpy.linalg.norm(a - B, axis=1)
掛かった時間は505 ms ± 2.35 msでした。
この時点でリスト内包表記を使った場合より6〜7倍程度早くなっています。
CuPy
さらに上記の処理をCuPyで行ってみましょう。
ここからの演算はnumpy.ndarrayではなくcupy.core.core.ndarrayで行うので変数も作り直します。
import cupy
a = cupy.random.rand(100)
B = cupy.random.rand(1000000, 100)
以下のコードで速度を測定してみましょう。
cupy.linalg.norm(a - B, axis=1)
なんと、133 µs ± 0 nsでした。
- リスト内包表記を使った場合と比べて,約20000倍
- Numpy ブロードキャストを使った場合と比べても, 約3800倍
という驚異的な速さでした。
行列演算として書ける処理は色々あるので、GPUが使える環境ならかなり役立ちそうです。