NumPyを使うと幸せになれるかも2: CuPyを使う
こんにちは.
今回の記事はシリーズ第2段です. 厳密に言えばNumPyの話ではなく, Chainerに含まれている行列演算モジュールCuPyの話です.
CuPyとはNumPyの機能をCUDA上で動かせるというもの. 使い方はnumpyをcupyで置き換えれば良いとのこと. そんなに簡単に使えるのなら使わない手はないと思い, NumPyで実装したあるコードをCuPyで置き換えてみましたが……
遅い……
ということで検証してみました.
環境
項目 | 詳細 |
---|---|
OS | Ubuntu 14.04 |
CPU | i5-3570 |
GPU | GTX970 |
コード
numpyとcuda.cupyの速度を行列積で比較してみました. cuda.cupyは何もしないバージョンとto_gpu()をするバージョンの2つを比較しました.
# -*- coding: utf-8 -*- import numpy as np import chainer import chainer.cuda.cupy as cp import time # MNISTを読み込み # 784次元のベクトル train, test = chainer.datasets.get_mnist() s1 = time.time() np_ar1 = np.array(train[0][0]) np_ar2 = np.array(train[1][0]) a1 = np_ar1.dot(np_ar2.T) s2 = time.time() cp_ar1 = cp.array(train[0][0]) cp_ar2 = cp.array(train[1][0]) a2 = cp_ar1.dot(cp_ar2.T) s3 = time.time() cp2_ar1 = chainer.cuda.to_gpu(cp.array(train[0][0])) cp2_ar2 = chainer.cuda.to_gpu(cp.array(train[1][0])) a3 = cp2_ar1.dot(cp2_ar2.T) s4 = time.time() print 'np:',s2-s1 print 'cp:',s3-s2 print 'cp2:',s4-s3
np: 5.57899475098e-05
cp: 0.182370185852
cp2: 0.000236988067627
やはりNumPyが一番速かったです. CuPyが負けてしまったのはGPUへのメモリ転送がネックになっているのだと思います.
あと,numpyをcupyにただ置き換えるだけではなく, to_gpu()を書いてあげたほうがいいみたいです. (書いても書かなくても実行結果が同じだったというコメントをいただきました.要検証です.)
ちなみに大きめの行列だとCuPyに軍配が上がります.
s1 = time.time() a = np.ones((1000, 1000),dtype=np.float32) a.dot(a.T) s2 = time.time() b = cp.ones((1000, 1000),dtype=cp.float32) b.dot(b.T) s3 = time.time() c = chainer.cuda.to_gpu(cp.ones((1000, 1000),dtype=cp.float32)) c.dot(c.T) s4 = time.time() print 'np:',s2-s1 print 'cp:',s3-s2 print 'cp2:',s4-s3
np: 0.0469000339508 cp: 0.281046152115 cp2: 0.000430822372437
※とある事情でコードを手打ちで書いたのでミスがあるかもしれません,悪しからず.