はじめに
Qiita初投稿です。
本記事ではタイトルの件について書きますが、chainer は、そうまでしなくても使うべきところでは cuDNN を使い、使わなくてもいいところでは使わない設計になっているような気がしています。なので、本記事は、単にデフォルトOFFの箇所でも cuDNN を使わせてみたかった、単にQiitaに投稿してみたかった、というモチベーションで書かれたモノと思っていただいてかまいません。
実行環境は、Windows10, Python 3.5, Chainer 2.0, CuPy 1.0, CUDA 8.0, cuDNN 5.1 です。
動機: ReLU 等活性化関数は cuDNN を使わないようだ。使わせたい!
ReLU 等の実装では、cuDNN 有効な chainer 環境でもデフォルトでは cuDNN 関数を使わないようです。
内部的には、should_use_cudnn('==always') を参照し、Trueの時だけ cuDNN を使用し、Falseの時には cupy 側の実装を実行するようです。この設定値を True にする方法が、ぱっとググってもわからなかったので試して確認しました。
その方法をメモしておきます。
結論: chainer.using_config('use_cudnn', 'always') を使う
以下のようなコードで設定できました。
import chainer
import chainer.functions as F
import cupy
import time
x = chainer.Variable(cupy.arange(-10., 10., 0.01))
with chainer.using_config('use_cudnn', 'always'):
y = F.relu(x)
使わせてみた結果: 実行時間に大きな差は見受けられない
手元のマシンで確認しました。
マシン構成 | |
---|---|
CPU | Intel Core i7-4790S CPU @ 3.20GHz |
Memory | 16GB |
GPU | NVIDIA GeForce GTX 970 |
GPU VRAM | 4GB |
GPU driver version | 382.05 |
ソフトウェア構成 | |
---|---|
OS | Windows 10 Pro |
Python | 3.5.3 |
Chainer | 2.0.0 |
CuPy | 1.0.0.1 |
CUDA | 8.0 |
cuDNN | 5.1 |
以下のコードを実行して実行時間を測定・比較しました。
chainer.using_config('use_cudnn', c) を設定する箇所で、強制的に cuDNN を使わせたい場合に c='always'
, そうでないときは c='auto'
としました。この辺の設定は、chainerソース を見て、あてずっぽうで設定しています。
cond = ['always', 'auto']
func = [F.relu, F.tanh, F.elu]
for f in func:
print('{}:'.format(f.__name__))
for c in cond:
with chainer.using_config('use_cudnn', c):
s = time.time()
for i in range(100):
y = F.relu(x)
e = time.time()
should = chainer.should_use_cudnn('==always')
print('\tc={:6}, should={:5}: time = {:.3f} sec.'.format(c, str(should), e-s))
結果は以下が出ましたが、何度か実行すると傾向含め変動したので、当てになりません。
ただ、大きな差が無いことは確かなようなので、デフォルトOFFなのも納得といったところ。
relu:
c=always, should=True : time = 0.017 sec.
c=auto , should=False: time = 0.014 sec.
tanh:
c=always, should=True : time = 0.015 sec.
c=auto , should=False: time = 0.013 sec.
elu:
c=always, should=True : time = 0.014 sec.
c=auto , should=False: time = 0.013 sec.
動かせたので良しとします。
以上。