生まれて初めてGPUにふれた

生まれてこの方GPUというものにふれてこず印象はなんか計算が早くなるんでしょみたいな解釈しかしてませんでした。

とはいえさわってみないと分からないので今回は実際にさわってみてその効果のほどを確認することにしました。
まずGPUインスタンスを搭載したマシンをどう調達するかについてですが、今年のAWSのEC2で5月に東京リージョンへGPUを搭載したP2インスタンスがきたのでそれを使用することにしました。
なんと最大でGPUが16搭載したインスタンスが用意できると言う….凄い世界だ…

Amazon EC2 P2 Instances are now available in Asia Pacific (Tokyo) and Asia Pacific (Sydney) Regions

今回やること

Chainerを使用してその中でサンプルとしてMulti-Layer Perceptron for MNIST Classificationを使ってGPUを使ってない場合と使った場合を比較する。

動作環境

  • インスタンスタイプ: p2.xlarge
  • AMI: NVIDIA CUDA Toolkit 7.5 on Amazon Linux
    • 今回はGPUを使用するためのドライバとかをいれる時間を省くためにそれらが入ったAMIを使用しました。

GPUの情報はnvidia-smiというコマンドで確認できます。

$ nvidia-smi
Sat Jul 29 02:13:54 2017
+------------------------------------------------------+
| NVIDIA-SMI 352.99     Driver Version: 352.99         |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla K80           On   | 0000:00:1E.0     Off |                    0 |
| N/A   42C    P8    25W / 149W |     55MiB / 11519MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

検証準備

ドライバなどは入っているので、後はChainerを使用するのでPythonとChainerを入れるだけです。
(とその時は思ってた)

Pythonpyenvを使用していれます。

$ python --version
Python 3.6.2

ChainerのインストールとGPUを使用する時に必要なcupyもいれます。

# chainerは2.0.1, cupyは1.0.1が入りました
$ pip install chainer cupy

検証

まずはGPUを使用していないものから検証しました。

GPUを使用しない

$ python chainer-2.0.1/examples/mnist/train_mnist.py
GPU: -1
# unit: 1000
# Minibatch-size: 100
# epoch: 20

epoch       main/loss   validation/main/loss  main/accuracy  validation/main/accuracy  elapsed_time
1           0.192339    0.11301               0.941083       0.9648                    17.211
2           0.0733699   0.0710786             0.977117       0.9774                    36.1076
3           0.0475365   0.0789325             0.98475        0.9769                    55.7616
4           0.0348562   0.0745593             0.98885        0.9787                    75.8827
5           0.0277311   0.102257              0.9907         0.9724                    96.4579
6           0.0241048   0.0879807             0.992483       0.9779                    117.416
7           0.0219072   0.0710079             0.992833       0.9818                    138.455
8           0.017988    0.0681981             0.993783       0.982                     160.079
9           0.0172883   0.0842126             0.994467       0.9804                    181.897
10          0.0123837   0.0860014             0.99585        0.9809                    204.486
11          0.0167936   0.081263              0.9943         0.9822                    227.67
12          0.0123561   0.0797155             0.996233       0.9839                    251.241
13          0.0113728   0.100481              0.9964         0.9814                    275.906
14          0.0119349   0.120433              0.996317       0.9799                    301.254
15          0.00982063  0.13196               0.996917       0.9787                    327.206
16          0.0106473   0.119098              0.99675        0.9797                    353.597
17          0.0108263   0.103797              0.997133       0.9806                    380.39
18          0.00896206  0.0968817             0.99725        0.9837                    408.096
19          0.00930343  0.100058              0.9972         0.9808                    436.251
20          0.00915619  0.130336              0.997133       0.9789                    465.153

GPUを使用する

続いてがGPUを使用した時で--gpu [GPU ID]オプションを指定するだけです。
GPU IDは先程nvidia-smiコメンドで確認した際のGPUというカラムの値の数値を使用します。
今回はIDが0なので--gpu 0と指定して実行します。

ただこの時1つ問題がありました。

まずは No such file or directory: 'nvcc'と出てそもそも実行されない。
これは単純に/usr/local/cuda/bin/nvccにパスが通ってないだけなのでexport PAHT=$PATH:/usr/local/cuda/binとパスを通してあげたらいけました。
これで実行できるようになったのですが、次は cuDNN is not enabled.が出てWARNINGが出たのですが、この解決が少し厄介でした。

ソース自体はここから落としてくるのですが、まずユーザー登録をしないといけないです。
ユーザー登録をして先程のリンクを開くとcuDNNがバージョンとプラットフォームごとに提供されているので、今回はcuDNN v6.0 (April 27, 2017), for CUDA 7.5cuDNN v6.0 Library for Linuxを使用しました。
今回は一度ローカルにファイルを落としてscpでインスタンスにアップロードしました。
ここから少しはまったのですが、どうやらchainerとかcupyを再インストールする必要があり、再インストールした後に無事動きました。
動いた結果が下記になります。

$ python chainer-2.0.1/examples/mnist/train_mnist.py --gpu 0
GPU: 0
# unit: 1000
# Minibatch-size: 100
# epoch: 20

epoch       main/loss   validation/main/loss  main/accuracy  validation/main/accuracy  elapsed_time
1           0.191885    0.118277              0.941883       0.9621                    3.53774
2           0.0720202   0.081614              0.977799       0.9763                    6.58676
3           0.0503432   0.0710561             0.984349       0.9785                    9.64134
4           0.0356193   0.0623461             0.988699       0.9829                    12.7405
5           0.0277371   0.082205              0.990815       0.9782                    15.8074
6           0.0252137   0.0703964             0.992082       0.9842                    18.9066
7           0.018074    0.0871086             0.994048       0.9794                    21.9982
8           0.0193796   0.0948052             0.993699       0.979                     25.0666
9           0.0176497   0.0816459             0.994315       0.9799                    28.1616
10          0.0145537   0.105795              0.995649       0.975                     31.252
11          0.0136489   0.0991074             0.995982       0.9787                    34.3346
12          0.0139412   0.0984373             0.995632       0.9811                    37.4096
13          0.0116104   0.104966              0.996449       0.981                     40.4892
14          0.0111883   0.0863221             0.996499       0.9835                    43.5692
15          0.011418    0.0900974             0.996432       0.9827                    46.6455
16          0.00842275  0.112952              0.997332       0.9796                    49.7249
17          0.00932168  0.0908319             0.997299       0.9827                    52.8396
18          0.0130952   0.106359              0.996282       0.9814                    55.9584
19          0.00778945  0.120892              0.997666       0.9789                    59.0483
20          0.00633532  0.106582              0.998116       0.9836                    62.1564

結果

GPUなしの時が7分くらいでGPUありで1分くらい 早い!

最後に

今回はとりあえず動かしてみただけなのでソースとか動作的な動きまでは追ってないですが、
コードを見る感じだとわりと簡単にかけそう?な感じ。

p2インスタンスを使用する時はお金と時間のトレードオフになりますが、やっぱり早く終るのは嬉しいなぁー