Keras というのは Python を使ってニューラルネットワークを組むためのフレームワーク。 Python でニューラルネットワークのフレームワークというと、他にも TensorFlow とか Chainer なんかが有名どころ。 Keras はそれらに比べると、より高い抽象度の API を提供しているところが特徴みたい。 実のところ Keras はデフォルトで TensorFlow をバックエンドとして動作する。 バックエンドとしては、他にも Theano が選べるらしい。
今回は Keras で組んだニューラルネットワークを GPU で学習させてみることにした。 そのとき CPU と比べて、どれくらい速くなるかを試してみたい。
使った環境は次の通り。
$ sw_vers ProductName: Mac OS X ProductVersion: 10.12.3 BuildVersion: 16D32 $ python --version Python 3.5.3
当然だけどマシンには dGPU のグラフィックカードが載っている必要がある。 今回は GeForce GTX 675MX を使った。
まずは CPU で学習させるための下準備
まずは Python のパッケージ管理システムである pip を使って Keras をインストールする。
$ pip install keras
もし pip がそもそも入っていないときは、インストールしておこう。
$ curl -O https://bootstrap.pypa.io/get-pip.py | sudo python
ついでに言うと、システムにサードパーティ製のパッケージをどんどん突っ込んでいくと混乱の元になる。 なので virtualenv などを使って仮想環境を作れるようにした方が良い。 ここらへんに何を使うかは好みによる。
続いてバックエンドとして動作する TensorFlow (CPU 版) もインストールしておこう。
$ pip install tensorflow
インストールが終わったら python コマンドを実行して REPL を立ち上げよう。
$ python
REPL が起動したら Keras の API を使って MNIST データセットをダウンロードしよう。 これにはちょっと時間がかかる。
>>> from keras.datasets import mnist Using TensorFlow backend. >>> mnist.load_data() Downloading data from https://s3.amazonaws.com/img-datasets/mnist.pkl.gz
ダウンロードが終わったら exit()
関数で REPL から抜けよう。
>>> exit()
続いて Keras のサンプルプログラムをダウンロードする。 これは Convolutional Neural Network (CNN) を使って MNIST データセットの画像を分類するものになっている。
$ curl -O https://raw.githubusercontent.com/fchollet/keras/master/examples/mnist_cnn.py
ちなみに、このプログラムにはリソースの開放関係でちょっとした問題があるっぽいのでパッチを当てておく。 これはそのうちいらなくなるかもしれないけど、余分にあったとしても特に問題はないコードなので。
$ echo 'K.clear_session()' >> mnist_cnn.py
CPU を使って学習させる
さて、上記でまずは Keras/TensorFlow を CPU を使って学習させる下準備が整った。
早速、先ほどダウンロードしてきたサンプルプログラムを実行してみよう。
time
コマンドを先頭に入れることで学習にかかった時間を測ることにする。
$ time python mnist_cnn.py Using TensorFlow backend. X_train shape: (60000, 28, 28, 1) 60000 train samples 10000 test samples Train on 60000 samples, validate on 10000 samples Epoch 1/12 W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.1 instructions, but these are available on your machine and could speed up CPU computations. W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations. W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX instructions, but these are available on your machine and could speed up CPU computations. 60000/60000 [==============================] - 78s - loss: 0.3744 - acc: 0.8854 - val_loss: 0.0887 - val_acc: 0.9716 Epoch 2/12 60000/60000 [==============================] - 78s - loss: 0.1357 - acc: 0.9595 - val_loss: 0.0634 - val_acc: 0.9800 Epoch 3/12 60000/60000 [==============================] - 79s - loss: 0.1033 - acc: 0.9693 - val_loss: 0.0572 - val_acc: 0.9818 Epoch 4/12 60000/60000 [==============================] - 78s - loss: 0.0890 - acc: 0.9740 - val_loss: 0.0448 - val_acc: 0.9853 Epoch 5/12 60000/60000 [==============================] - 76s - loss: 0.0784 - acc: 0.9767 - val_loss: 0.0423 - val_acc: 0.9865 Epoch 6/12 60000/60000 [==============================] - 80s - loss: 0.0710 - acc: 0.9788 - val_loss: 0.0384 - val_acc: 0.9871 Epoch 7/12 60000/60000 [==============================] - 84s - loss: 0.0656 - acc: 0.9808 - val_loss: 0.0364 - val_acc: 0.9891 Epoch 8/12 60000/60000 [==============================] - 84s - loss: 0.0606 - acc: 0.9818 - val_loss: 0.0354 - val_acc: 0.9888 Epoch 9/12 60000/60000 [==============================] - 79s - loss: 0.0555 - acc: 0.9839 - val_loss: 0.0336 - val_acc: 0.9883 Epoch 10/12 60000/60000 [==============================] - 76s - loss: 0.0545 - acc: 0.9837 - val_loss: 0.0325 - val_acc: 0.9895 Epoch 11/12 60000/60000 [==============================] - 76s - loss: 0.0500 - acc: 0.9856 - val_loss: 0.0325 - val_acc: 0.9900 Epoch 12/12 60000/60000 [==============================] - 78s - loss: 0.0476 - acc: 0.9860 - val_loss: 0.0328 - val_acc: 0.9893 Test score: 0.0328271338152 Test accuracy: 0.9893 python mnist_cnn.py 2470.93s user 664.19s system 326% cpu 16:00.66 total
MNIST を分類したときの正解率が 98.93% となっている。 かかった時間は 2471 秒で、ようするに 40 分もかかったことになる。
もし仮に一からニューラルネットワークを組むとしたら、もちろんこんな風に一発では上手くいかない。 たくさんのトライアンドエラーを繰り返して、その毎回にこんな時間がかかるとしたら気が遠くなってくる。
TensorFlow (GPU 版) をインストールする
CPU での学習にかかる時間に絶望したところで、次は代わりに GPU を使って学習させてみよう。 GPU は並列化しやすい単純な計算が得意で、ニューラルネットワークで内部的に用いられる行列演算もそれに当たる。
ニューラルネットワークがどうして行列演算を使うのかを知りたいときは、次の本を読むのがおすすめ。 この本はディープラーニングについて理論と実装の両面から理解を深められる貴重な本だと思う。

ゼロから作るDeep Learning ―Pythonで学ぶディープラーニングの理論と実装
- 作者: 斎藤康毅
- 出版社/メーカー: オライリージャパン
- 発売日: 2016/09/24
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (11件) を見る
話が脱線したけど Keras/TensorFlow で組むニューラルネットワークを GPU で学習させるには CUDA が必要になる。 また、バックエンドとして動作する TensorFlow についても GPU 対応版のものをインストールする必要がある。 代わりに、サンプルコードに関しては、学習に CPU を使うときと GPU を使うときで同じものが使える。
まずは Homebrew を使って coreutils をインストールしておく。
$ brew install coreutils
もし Homebrew が入っていないという場合には公式サイトの記述をもとにインストールしておこう。
続いて CUDA をインストールする。 これも Homebrew Cask を使って入れられる。
$ brew tap caskroom/cask $ brew cask install cuda
続いて cuDNN をインストールする。 これだけはコマンドラインでちょちょいとインストールすることができない。 なぜかというと、サイトでユーザ登録をしないとダウンロードできないようになっているから。
なので、まずは以下の公式サイトでユーザ登録をしよう。
NVIDIA cuDNN | NVIDIA Developer
その上で、今なら “cuDNN v5.1 Library for OSX” というバージョンをダウンロードしてくる。
ダウンロードできたら、それを CUDA のディレクトリに解凍して放り込む。
$ sudo tar -xvf cudnn-8.0-osx-x64-v5.1.tgz -C /usr/local
ここで念のためマシンを再起動しておこう。
$ sudo shutdown -r now
再起動が終わったら、まずは CPU 版の TensorFlow をアンインストールする。 そして、改めて GPU 版の TensorFlow をインストールしよう。 これには名前のサフィックスとして -gpu がついている。
$ pip uninstall -y tensorflow $ pip install tensorflow-gpu
GPU を使って学習させる
さて、これで GPU を使ってニューラルネットワークを学習させるための準備が整った。 先ほどと同じサンプルコードを実行して GPU を使った学習を試してみよう。
$ time python mnist_cnn.py Using TensorFlow backend. I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcublas.8.0.dylib locally I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcudnn.5.dylib locally I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcufft.8.0.dylib locally I tensorflow/stream_executor/dso_loader.cc:126] Couldn't open CUDA library libcuda.1.dylib. LD_LIBRARY_PATH: :/usr/local/cuda/lib I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcuda.dylib locally I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcurand.8.0.dylib locally X_train shape: (60000, 28, 28, 1) 60000 train samples 10000 test samples Train on 60000 samples, validate on 10000 samples Epoch 1/12 W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.1 instructions, but these are available on your machine and could speed up CPU computations. W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations. W tensorflow/core/platform/cpu_feature_guard.cc:45] The TensorFlow library wasn't compiled to use AVX instructions, but these are available on your machine and could speed up CPU computations. I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:874] OS X does not support NUMA - returning NUMA node zero I tensorflow/core/common_runtime/gpu/gpu_device.cc:885] Found device 0 with properties: name: GeForce GTX 675MX major: 3 minor: 0 memoryClockRate (GHz) 0.719 pciBusID 0000:01:00.0 Total memory: 1023.69MiB Free memory: 639.50MiB I tensorflow/core/common_runtime/gpu/gpu_device.cc:906] DMA: 0 I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 0: Y I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX 675MX, pci bus id: 0000:01:00.0) 60000/60000 [==============================] - 16s - loss: 0.3717 - acc: 0.8865 - val_loss: 0.0904 - val_acc: 0.9714 Epoch 2/12 60000/60000 [==============================] - 13s - loss: 0.1365 - acc: 0.9596 - val_loss: 0.0616 - val_acc: 0.9809 Epoch 3/12 60000/60000 [==============================] - 13s - loss: 0.1048 - acc: 0.9694 - val_loss: 0.0515 - val_acc: 0.9841 Epoch 4/12 60000/60000 [==============================] - 13s - loss: 0.0894 - acc: 0.9736 - val_loss: 0.0439 - val_acc: 0.9857 Epoch 5/12 60000/60000 [==============================] - 13s - loss: 0.0769 - acc: 0.9771 - val_loss: 0.0401 - val_acc: 0.9869 Epoch 6/12 60000/60000 [==============================] - 13s - loss: 0.0700 - acc: 0.9790 - val_loss: 0.0360 - val_acc: 0.9885 Epoch 7/12 60000/60000 [==============================] - 13s - loss: 0.0646 - acc: 0.9806 - val_loss: 0.0364 - val_acc: 0.9881 Epoch 8/12 60000/60000 [==============================] - 13s - loss: 0.0611 - acc: 0.9819 - val_loss: 0.0345 - val_acc: 0.9882 Epoch 9/12 60000/60000 [==============================] - 13s - loss: 0.0553 - acc: 0.9838 - val_loss: 0.0323 - val_acc: 0.9889 Epoch 10/12 60000/60000 [==============================] - 13s - loss: 0.0534 - acc: 0.9841 - val_loss: 0.0307 - val_acc: 0.9898 Epoch 11/12 60000/60000 [==============================] - 13s - loss: 0.0504 - acc: 0.9851 - val_loss: 0.0297 - val_acc: 0.9895 Epoch 12/12 60000/60000 [==============================] - 13s - loss: 0.0474 - acc: 0.9860 - val_loss: 0.0298 - val_acc: 0.9899 Test score: 0.0298051692682 Test accuracy: 0.9899 python mnist_cnn.py 138.85s user 22.06s system 91% cpu 2:55.87 total
今度は 139 秒で学習が終わった。
CPU を使ったときが 2471 秒なので、およそ 17.8 倍も学習が高速化できた。 学習時間が約 5.6% に短縮されているともいえる。 これだけ違うとトライアンドエラーを繰り返すときにかかる時間は全く変わってくる。
まとめ
- Keras/TensorFlow で学習に GPU を使いたいときは、以下のものを入れる
- CUDA
- cuDNN
- GPU 対応版 TensorFlow
- ソースコードは CPU/GPU どちらを学習に使うときであっても共用できる
- 学習にかかる時間を CPU と GPU で比較してみた
- 今回試したパターンでは GPU を使うと CPU 比で 17.8 倍も高速化できた
- 結論: ディープラーニングをやるなら GPU は絶対に使おう
めでたしめでたし。

スマートPythonプログラミング: Pythonのより良い書き方を学ぶ
- 作者: もみじあめ
- 発売日: 2016/03/12
- メディア: Kindle版
- この商品を含むブログ (1件) を見る