ytbilly3636’s 研究備忘録

機械学習,Python,ガンダムなど

NumPyを使うと幸せになれるかも2: CuPyを使う

こんにちは.

今回の記事はシリーズ第2段です. 厳密に言えばNumPyの話ではなく, Chainerに含まれている行列演算モジュールCuPyの話です.

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

※とある事情でコードを手打ちで書いたのでミスがあるかもしれません,悪しからず.