以前、このブログで Keras/TensorFlow の学習スピードを GPU を使って速くする記事を書いた。 ただし、このとき使った OS は Mac OS X (macOS Sierra) だった。
とはいえ NVIDIA の dGPU を積んだ Mac がどれだけあるんだというと、正直なかなか無いと思う。 実際にやってみるとしたら Linux だよねということで、今回は Ubuntu 16.04 LTS を使う場合について書く。
インストールの手順については次の公式ドキュメントをベースに進める。
Installing TensorFlow on Ubuntu | TensorFlow
環境について
今回使った OS のバージョンなどは次の通り。
$ cat /etc/lsb-release DISTRIB_ID=Ubuntu DISTRIB_RELEASE=16.04 DISTRIB_CODENAME=xenial DISTRIB_DESCRIPTION="Ubuntu 16.04.2 LTS" $ uname -r 4.4.0-66-generic
また、学習に GPU を使う場合はハードウェアの環境にも制約があるので、ここで記述しておく。 まず、当たり前だけど大前提として CUDA をサポートしている NVIDIA のグラフィックカードが必ず必要になる。 ちなみに TensorFlow のドキュメントを見ると一部 Radeon も対応しているらしいことが書かれていたけど、試してはいない。
さらに、NVIDIA のグラフィックカードなら何でも良いのかというと、そういうわけでもない。 次の NVIDIA 公式ページを見てほしい。 ここには NVIDIA の各 GPU ごとの Compute Capability という数値が載っている。
Compute Capability という字面だけを見ると、性能を表す数値のような印象を受けるけど、そうではない。 数値はパフォーマンスとは関係がなく、あくまで GPU の世代というか載っている機能のバージョンらしい。 問題は、この数値が少なくとも 3.0 以上ないと現行の CUDA 8.0 がサポートしていない、という点だ。
また、PyPI で配布されている TensorFlow の GPU 版バイナリパッケージは CUDA 8.0 でビルドされている。 なので、もちろん動かす環境にも CUDA 8.0 が必要になる。 以上のことから Compute Capability が 3.0 以上の GPU を用意すべきだ。
ちなみに、ドキュメントを見ると一応 TensorFlow は今のところ CUDA 7.5 もサポートしているらしい。 CUDA 7.5 であれば Compute Capability は 2.0 以上をサポートしている。 ただし、そのときは自分でソースコードからビルドしなければいけない。 それについて、この記事では扱わない。
今回 GPU には GeForce GTX 1050 Ti を用意した。 これの Compute Capability は 6.1 となっている。 具体的なグラフィックカードは次のもの。
MSI GeForce GTX 1050 Ti 4G OC グラフィックスボード VD6191
- 出版社/メーカー: MSI COMPUTER
- 発売日: 2016/10/25
- メディア: Personal Computers
- この商品を含むブログを見る
GPU のチョイスについては、現時点 (2017/3) で最もコストパフォーマンスが高くなるものを選んだ。 PassMark というベンチマークのスコアを値段で割った値を考えると GeForce GTX 1050 Ti が一番高くなる。 あとは、CPU に比べると GPU の学習速度はそれこそ一桁か、下手すると二桁は違ってくる。 つまり、GPU が載っていること自体がまずは重要で、性能はその次かなという感じ。 ようするに 60 秒かかった処理が 6 秒になるのは大きく違うけど、6 秒が 3 秒になってどれだけ嬉しいか?っていう。 それもあってハイエンドモデルではなくエントリーモデルを選ぶことにした。
グラフィックカードを刺して GPU を Ubuntu 16.04 LTS が認識することを確認しておこう。
$ lspci | grep -i nvidia 01:00.0 VGA compatible controller: NVIDIA Corporation Device 1c82 (rev a1) 01:00.1 Audio device: NVIDIA Corporation Device 0fb9 (rev a1)
CUDA Toolkit をインストールする
インストールの第一歩として CUDA Toolkit をインストールする。 そのために、まずは NVIDIA 公式サイトを参照する。
インストール方法は色々とあるけど、ここでは CUDA のリモートリポジトリを APT に登録するやり方を取る。 これなら、後からマイナーアップデートがあったときにも自動で更新できる。 上記ウェブサイトで、次のように操作して deb ファイルのダウンロード URL を取得しよう。
Linux > x86_64 > Ubuntu > 16.04 > deb (network)
上記で得られた URL から deb ファイルをダウンロードしてくる。
$ wget http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/cuda-repo-ubuntu1604_8.0.61-1_amd64.deb
deb ファイルをインストールする。 これで CUDA のリポジトリが APT パッケージシステムに登録される。
$ sudo dpkg -i cuda-repo-ubuntu1604_8.0.61-1_amd64.deb
$ sudo apt-get update
これで APT 経由で CUDA をインストールできるようになる。 ちなみに、インストールにはとても長い時間がかかるので覚悟しておこう。 先ほどのインストール方法でローカルインストールを選んだ場合には 1.9GB のファイルを落とすことになる。 かかる時間は、推して知るべし。
$ sudo apt-get -y install cuda
上記が終わると、依存パッケージとして一緒に NVIDIA のグラフィックドライバなんかも入る。
$ dpkg -l | grep nvidia-[0-9] ii nvidia-375 375.26-0ubuntu1 amd64 NVIDIA binary driver - version 375.26 ii nvidia-375-dev 375.26-0ubuntu1 amd64 NVIDIA binary Xorg driver development files
cuDNN をインストールする
次に cuDNN をインストールする。
cuDNN のインストールには、あらかじめ NVIDIA のサイトでデベロッパー登録が必要になる。 登録を済ませると cuDNN をダウンロードできるようになる。
https://developer.nvidia.com/rdp/cudnn-download
cuDNN の現行のバージョンは 5.1 となっている。 ダウンロードに使うパッケージは CUDA Toolkit のバージョンと組み合わせになっている。 今回であれば v5.1 + CUDA 8.0 のパッケージを選ぼう。
Download cuDNN v5.1 (Jan 20, 2017), for CUDA 8.0 > cuDNN v5.1 Library for Linux
ダウンロードしてきたら、それを CUDA のインストールされたディレクトリに放り込む。
$ sudo tar xvf cudnn-8.0-linux-x64-v5.1.tgz -C /usr/local cuda/include/cudnn.h cuda/lib64/libcudnn.so cuda/lib64/libcudnn.so.5 cuda/lib64/libcudnn.so.5.1.10 cuda/lib64/libcudnn_static.a
libcupti-dev をインストールする
次に The CUDA Profiling Tools Interface もインストールしておく。
$ sudo apt-get -y install libcupti-dev
ここまで終わったら、一旦再起動しておこう。
$ sudo shutdown -r now
Keras/TensorFlow (GPU)
さて、次はいよいよ Keras/TensorFlow をインストールする…と言いたいところだけど、その前に。 システムの Python 実行環境を汚したくないので Python の仮想環境を作れるようにしよう。
ここでは virtualenvwrapper を使う。
$ sudo apt-get -y install virtualenvwrapper
シェルを起動し直す。
$ exec $SHELL
これで Python 仮想環境が作れるようになった。
tensorflow-with-gpu
という名前で Python3 の仮想環境を作る。
$ mkvirtualenv tensorflow-with-gpu -p $(which python3)
これで最低限のパッケージが入った、システムから独立した仮想環境ができた。
(tensorflow-with-gpu) $ pip list --format=columns Package Version ------------- -------- appdirs 1.4.3 packaging 16.8 pip 9.0.1 pkg-resources 0.0.0 pyparsing 2.2.0 setuptools 34.3.2 six 1.10.0 wheel 0.30.0a0
ここに Keras と GPU 版 TensorFlow をインストールする。
(tensorflow-with-gpu) $ pip install keras tensorflow-gpu
インストールすると、こんな感じ。
(tensorflow-with-gpu) $ pip list --format=columns | grep -i -e keras -e tensorflow Keras 1.2.2 tensorflow-gpu 1.0.1
ちなみに、以降はシェルのプレフィックスを表記しないけど Python 仮想環境上で実行し続けている。
GPU で学習させる
まずはベンチマーク用のアプリケーションで使うデータセット (MNIST) をダウンロードしよう。 Python の REPL を起動する。
$ python
Keras の mnist パッケージをインポートする。
>>> from keras.datasets import mnist Using TensorFlow backend. I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcublas.so.8.0 locally I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcudnn.so.5 locally I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcufft.so.8.0 locally I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcuda.so.1 locally I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcurand.so.8.0 locally
load_data() 関数でデータセットのダウンロードが始まる。 これには少し時間がかかる。
>>> mnist.load_data() Downloading data from https://s3.amazonaws.com/img-datasets/mnist.pkl.gz ... [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0]]], dtype=uint8), array([7, 2, 1, ..., 4, 5, 6], dtype=uint8)))
終わったら REPL から抜ける。
>>> exit()
続いて学習のベンチマークに使うアプリケーションをダウンロードしてくる。
$ curl -O https://raw.githubusercontent.com/fchollet/keras/master/examples/mnist_cnn.py $ echo 'K.clear_session()' >> mnist_cnn.py
ベンチマーク用のアプリケーションを実行する。 これは MNIST データセットを CNN で認識するものになっている。 初めての実行だと GPU の環境を整えるので学習を始まるまで時間がかかるかも。
$ time python mnist_cnn.py Using TensorFlow backend. I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcublas.so.8.0 locally I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcudnn.so.5 locally I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcufft.so.8.0 locally I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcuda.so.1 locally I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcurand.so.8.0 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 SSE3 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.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. I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:910] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero I tensorflow/core/common_runtime/gpu/gpu_device.cc:885] Found device 0 with properties: name: GeForce GTX 1050 Ti major: 6 minor: 1 memoryClockRate (GHz) 1.455 pciBusID 0000:01:00.0 Total memory: 3.94GiB Free memory: 3.84GiB 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 1050 Ti, pci bus id: 0000:01:00.0) 60000/60000 [==============================] - 8s - loss: 0.3661 - acc: 0.8871 - val_loss: 0.0864 - val_acc: 0.9726 Epoch 2/12 60000/60000 [==============================] - 6s - loss: 0.1337 - acc: 0.9604 - val_loss: 0.0613 - val_acc: 0.9806 Epoch 3/12 60000/60000 [==============================] - 6s - loss: 0.1046 - acc: 0.9694 - val_loss: 0.0524 - val_acc: 0.9838 Epoch 4/12 60000/60000 [==============================] - 6s - loss: 0.0879 - acc: 0.9737 - val_loss: 0.0428 - val_acc: 0.9858 Epoch 5/12 60000/60000 [==============================] - 6s - loss: 0.0755 - acc: 0.9773 - val_loss: 0.0393 - val_acc: 0.9870 Epoch 6/12 60000/60000 [==============================] - 6s - loss: 0.0683 - acc: 0.9801 - val_loss: 0.0368 - val_acc: 0.9875 Epoch 7/12 60000/60000 [==============================] - 6s - loss: 0.0648 - acc: 0.9806 - val_loss: 0.0367 - val_acc: 0.9888 Epoch 8/12 60000/60000 [==============================] - 6s - loss: 0.0593 - acc: 0.9820 - val_loss: 0.0353 - val_acc: 0.9889 Epoch 9/12 60000/60000 [==============================] - 6s - loss: 0.0548 - acc: 0.9833 - val_loss: 0.0328 - val_acc: 0.9890 Epoch 10/12 60000/60000 [==============================] - 6s - loss: 0.0529 - acc: 0.9845 - val_loss: 0.0316 - val_acc: 0.9897 Epoch 11/12 60000/60000 [==============================] - 6s - loss: 0.0508 - acc: 0.9848 - val_loss: 0.0308 - val_acc: 0.9902 Epoch 12/12 60000/60000 [==============================] - 6s - loss: 0.0484 - acc: 0.9852 - val_loss: 0.0298 - val_acc: 0.9899 Test score: 0.0297728348608 Test accuracy: 0.9899 real 1m28.273s user 1m39.684s sys 0m8.740s
全体の実行が一分半ほどで終わった。 一回のエポックは大体 6 秒ほどで終わっている。
ちなみに GPU の仕事っぷりは nvidia-smi
コマンドから見られる。
$ nvidia-smi Sun Mar 12 20:24:56 2017 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 375.26 Driver Version: 375.26 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | |===============================+======================+======================| | 0 GeForce GTX 105... Off | 0000:01:00.0 On | N/A | | 35% 38C P0 58W / 75W | 3862MiB / 4037MiB | 77% Default | +-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+ | Processes: GPU Memory | | GPU PID Type Process name Usage | |=============================================================================| | 0 1510 G /usr/lib/xorg/Xorg 59MiB | | 0 3374 C python 3799MiB | +-----------------------------------------------------------------------------+
毎秒ごとに表示を更新したいときは、こんな感じで。
$ nvidia-smi -l 1
CPU で学習させる
ちなみに対比として CPU を使ったときの例も載せておく。
使った CPU は次の通り。 第一世代 Core i7 なので、なかなか古い。 現行世代なら Core i3 くらいの性能らしい。
$ cat /proc/cpuinfo | grep -i name | head -n 1 model name : Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz $ cat /proc/cpuinfo | grep -i name | wc -l 8
余談ながら、当然チップセットやマザーボードも古いので今回使ったグラフィックカードを認識するかドキドキした。
先ほどインストールした GPU 版 TensorFlow をアンインストールして CPU 版 TensorFlow をインストールする。
$ pip uninstall -y tensorflow-gpu $ pip install tensorflow
先ほどと同じようにベンチマーク用のアプリケーションを実行する。
$ 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 SSE3 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.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. 60000/60000 [==============================] - 117s - loss: 0.3733 - acc: 0.8858 - val_loss: 0.0885 - val_acc: 0.9723 Epoch 2/12 60000/60000 [==============================] - 117s - loss: 0.1347 - acc: 0.9596 - val_loss: 0.0635 - val_acc: 0.9799 Epoch 3/12 60000/60000 [==============================] - 115s - loss: 0.1031 - acc: 0.9693 - val_loss: 0.0565 - val_acc: 0.9818 Epoch 4/12 60000/60000 [==============================] - 115s - loss: 0.0887 - acc: 0.9740 - val_loss: 0.0448 - val_acc: 0.9852 Epoch 5/12 60000/60000 [==============================] - 114s - loss: 0.0780 - acc: 0.9773 - val_loss: 0.0415 - val_acc: 0.9868 Epoch 6/12 60000/60000 [==============================] - 113s - loss: 0.0707 - acc: 0.9788 - val_loss: 0.0376 - val_acc: 0.9870 Epoch 7/12 60000/60000 [==============================] - 112s - loss: 0.0651 - acc: 0.9808 - val_loss: 0.0352 - val_acc: 0.9893 Epoch 8/12 60000/60000 [==============================] - 112s - loss: 0.0604 - acc: 0.9818 - val_loss: 0.0352 - val_acc: 0.9888 Epoch 9/12 60000/60000 [==============================] - 112s - loss: 0.0555 - acc: 0.9840 - val_loss: 0.0332 - val_acc: 0.9884 Epoch 10/12 60000/60000 [==============================] - 112s - loss: 0.0542 - acc: 0.9835 - val_loss: 0.0322 - val_acc: 0.9895 Epoch 11/12 60000/60000 [==============================] - 111s - loss: 0.0495 - acc: 0.9853 - val_loss: 0.0319 - val_acc: 0.9897 Epoch 12/12 60000/60000 [==============================] - 110s - loss: 0.0477 - acc: 0.9857 - val_loss: 0.0326 - val_acc: 0.9893 Test score: 0.032642004689 Test accuracy: 0.9893 real 22m54.715s user 123m6.744s sys 46m53.296s
今度は 23 分ほどかかった。
GPU が 1 分 28 秒で終わったのに対して CPU では 22 分 54 秒かかっている。 つまり、GPU を使うことで学習が 15.6 倍高速化できた。 一回のエポック当たりでは 19.1 倍速くなっている。
まとめ
今回は OS として Ubuntu 16.04 LTS を使って Keras/TensorFlow の学習を GPU で高速化してみた。 CUDA がサポートしている GPU は Compute Capability という数値で表現されている。 この数値が大きいものほど、新しい世代のものになっている。 使う GPU については NVIDIA で、少なくとも Compute Capability が 3.0 以上のものを選ぼう。 もちろん、将来の CUDA で最小要件の Compute Capability は上がっていくはずなので、なるべく大きい方が良い。
いじょう。
MSI GeForce GTX 1050 Ti 4G OC グラフィックスボード VD6191
- 出版社/メーカー: MSI COMPUTER
- 発売日: 2016/10/25
- メディア: Personal Computers
- この商品を含むブログを見る