LoginSignup
16
12

More than 5 years have passed since last update.

CuPyの行列演算が驚異的に早かった

Posted at

この記事の内容

  • 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があるとします。

先ほどのaBに含まれる各ベクトルとの距離をすべて計算してみましょう。

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が使える環境ならかなり役立ちそうです。

16
12
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
12