AWS EC2のGPUが使えるubuntu16.04に、自力でCUDA 9.2/CuDNNを入れてみよう



# 前提

機械学習の環境を作る際、最新版のCUDAがインストールされてしまうと、
思っていた通りフレームワークが動かない、なんてこともあるかと思います。
今回は、CUDA/CuDNNのバージョンを指定したセットアップ手順と確認手順をざっと書きました。

# 環境構築

Ubuntu 16.04、 CUDAは9.2を想定しています。また、AWS EC2上で作業をしています。
EC2上という前提を置いていますが、
プロキシ無しでインターネットに接続できる環境であれば概ね同じ手順になるかと思います。

# 構築手順

## 機種の確認とドライバの確認

まずGPUの機種を確認。あとドライバーが入っていないか確認しましょう。

```
$  lspci | grep -i NVIDIA
00:1e.0 3D controller: NVIDIA Corporation GK210GL [Tesla K80] (rev a1)
$ dpkg -l | grep nvidia
$ 
$ cat /proc/driver/nvidia/version
cat: /proc/driver/nvidia/version: No such file or directory
```

インストールされていない場合は、そのままドライバのインストールを行います。
覚えがないのに既にドライバがインストールされている場合は…　
下の手順などを元に、本来入れるべきドライバのバージョンを確認し、適切な物が入っているのかなどを確認したほうが良いかもしれません。(試したことはないです) 

## ドライバーのインストール

nVIDIAの公式ページでドライバを選択し、ダウンロードします。それぞれ環境によってバージョン等は様々です。基本的には公式ページにアクセスし確認したほうが確実なのかなーと思います。

公式のページはここ。

https://www.nvidia.com/Download/index.aspx?lang=en-us

色々選択が必要ですが、前述のlspci の結果から判断できるかと思います。

個人的には、wgetでやる方がおすすめです。ダウンロードボタンのURLをみると、debファイルのURLが記載されていますので、そのdebファイルを指定してファイルを取得するやり方が楽かなと思います。

今回は ubuntu 16.04 & CUDA 9.2 を使用したいので、このOSやCUDA 9.2を指定してdebを取得します。
debファイルを取得したら、ドライバをインストールする予定のマシンへ転送。
転送後は、そのdebをdpkgでインストールします。 その際、鍵が必要となりますが、
不足している場合はご丁寧にコメントが出ますので、それを元に作業すればよいかと。


![qiita1.png](https://qiita-image-store.s3.amazonaws.com/0/214695/fabe23aa-43f4-0262-8353-acc0a9dce889.png)

```
~$ wget http://us.download.nvidia.com/tesla/396.82/nvidia-diag-driver-local-repo-ubuntu1604-396.82_1.0-1_amd64.deb
～中略～
HTTP request sent, awaiting response... 200 OK
～中略～
2019-03-08 05:58:30 (983 KB/s) - ‘nvidia-diag-driver-local-repo-ubuntu1604-396.82_1.0-1_amd64.deb’ saved [109509142/109509142]

$ sudo dpkg -i nvidia-diag-driver-local-repo-ubuntu1604-396.82_1.0-1_amd64.deb 
Selecting previously unselected package nvidia-diag-driver-local-repo-ubuntu1604-396.82.
(Reading database ... 51284 files and directories currently installed.)
Preparing to unpack nvidia-diag-driver-local-repo-ubuntu1604-396.82_1.0-1_amd64.deb ...
Unpacking nvidia-diag-driver-local-repo-ubuntu1604-396.82 (1.0-1) ...
Setting up nvidia-diag-driver-local-repo-ubuntu1604-396.82 (1.0-1) ...

The public CUDA GPG key does not appear to be installed.
To install the key, run this command:
sudo apt-key add /var/nvidia-diag-driver-local-repo-396.82/7fa2af80.pub

$ 
$ 
$ sudo apt-key add /var/nvidia-diag-driver-local-repo-396.82/7fa2af80.pub
OK
$ 
$ sudo dpkg -i nvidia-diag-driver-local-repo-ubuntu1604-396.82_1.0-1_amd64.deb 
(Reading database ... 51309 files and directories currently installed.)
Preparing to unpack nvidia-diag-driver-local-repo-ubuntu1604-396.82_1.0-1_amd64.deb ...
Unpacking nvidia-diag-driver-local-repo-ubuntu1604-396.82 (1.0-1) over (1.0-1) ...
Setting up nvidia-diag-driver-local-repo-ubuntu1604-396.82 (1.0-1) ...
```

リポジトリの情報を最新化します
リポジトリの情報を最新化し、apt installをします。

```
~$ sudo apt update
Hit:1 http://ap-northeast-1.ec2.archive.ubuntu.com/ubuntu xenial InRelease
～中略～
Reading state information... Done
110 packages can be upgraded. Run 'apt list --upgradable' to see them.
~$ sudo apt install cuda-drivers
～インストール～

```

適切にインストールできたかどうかの確認ですが、dpkg と nvidia-smiで確認するとよいと思います。
不要なバージョンのものが入り混じっていないか等確認するとよいかもです。

```
$ dpkg -l | grep nvidia
ii  nvidia-396                                      396.82-0ubuntu1                            amd64        NVIDIA binary driver - version 396.82
ii  nvidia-396-dev                                  396.82-0ubuntu1                            amd64        NVIDIA binary Xorg driver development files
ii  nvidia-diag-driver-local-repo-ubuntu1604-396.82 1.0-1                                      amd64        nvidia-diag-driver-local repository configuration files
ii  nvidia-modprobe                                 396.82-0ubuntu1                            amd64        Load the NVIDIA kernel driver and create device files
ii  nvidia-opencl-icd-396                           396.82-0ubuntu1                            amd64        NVIDIA OpenCL ICD
ii  nvidia-prime                                    0.8.2                                      amd64        Tools to enable NVIDIA's Prime
ii  nvidia-settings                                 396.82-0ubuntu1                            amd64        Tool for configuring the NVIDIA graphics driver
$ nvidia-smi
Fri Mar  8 06:13:48 2019       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 396.82                 Driver Version: 396.82                    |
|-------------------------------+----------------------+----------------------+
| 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           Off  | 00000000:00:1E.0 Off |                    0 |
| N/A   55C    P0    68W / 149W |      0MiB / 11441MiB |     84%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+
```

ここでドライバのインストールが完了しました。


## CUDAのセットアップと確認

Driverがセットアップできましたら、CUDAのセットアップをするとよいと思います。
こちらも基本的に公式のページを見たほうが良いと思います。

https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#pre-installation-actions

念のため公式に従うと、pre installation actionから進めます。

```
$ uname -r
4.4.0-1067-aws
$ 
$ lspci | grep -i nvidia
00:1e.0 3D controller: NVIDIA Corporation GK210GL [Tesla K80] (rev a1)
$ 
$ uname -m && cat /etc/*release
x86_64
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.5 LTS"
NAME="Ubuntu"
VERSION="16.04.5 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.5 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial
$ 
$  gcc --version
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.11) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ sudo apt-get install linux-headers-$(uname -r)
Reading package lists... Done
Building dependency tree       
Reading state information... Done
linux-headers-4.4.0-1067-aws is already the newest version (4.4.0-1067.77).
0 upgraded, 0 newly installed, 0 to remove and 105 not upgraded.
```

以下を行います。最後のaptとgcc以外は割と飛ばしても大丈夫かなと思います。

- lspciの結果から、http://developer.nvidia.com/cuda-gpus に記載のカードであることを確認します 
- unameの結果から、x86_64 であることを確認します
- gcc コマンドが異常なく動作することを確認します
- 上記が問題ないのでしたら、kernel header と開発用のパッケージをインストールします。

次にCUDA Toolkit です。
↓URLより、自分が使いたいCUDAのtoolkitを選択し、必要な物を指定します。

https://developer.nvidia.com/cuda-toolkit-archive

今回は、CUDA9.2を使いますから、CUDA9.2を選択しました。
ここでも、driverと同様に、DownloadボタンのLink URLを元に、
debファイルを wget で取得してもよいと思います。

![qiita2.png](https://qiita-image-store.s3.amazonaws.com/0/214695/90e69ab8-ba9a-ea55-6eb1-2af7aa6e63d9.png)

```
$ wget https://developer.nvidia.com/compute/cuda/9.2/Prod2/local_installers/cuda-repo-ubuntu1604-9-2-local_9.2.148-1_amd64
～ 略 ～
$ sudo dpkg -i cuda-repo-ubuntu1604-9-2-local_9.2.148-1_amd64
～ 略 ～
$ sudo apt-key add /var/cuda-repo-9-2-local/7fa2af80.pub 
～ 略 ～
$ sudo apt update
～ 略 ～
$ sudo apt install cuda
～ 略 ～

```

インストールの確認と環境変数の設定などをします。
結構忘れがちですが、pathを通さないといけませんので注意が必要です。
また、インストールができますと、/usr/local配下に、cuda XXXX といったディレクトリが作成され、それ以下にtoolkit等が置いてあります。 個人的には、CUDAのバージョン確認も可ね、nvcc を使った確認が良いと思います。

```
$ vi ~/.bash_profile
export PATH=/usr/local/cuda-9.2/bin${PATH:+:${PATH}}
export LD_LIBRARY_PATH=/usr/local/cuda-9.2/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
export CUDA_HOME=/usr/local/cuda
$ source ~/.bash_profile
$ nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2018 NVIDIA Corporation
Built on Tue_Jun_12_23:07:04_CDT_2018
Cuda compilation tools, release 9.2, V9.2.148
```

## CuDNNのセットアップと確認

次はcuDNNをセットアップをします。殆どの方はCUDAまでしか必要ではないと思いますので、
不要な方はスキップでOKです。cuDNNは、nvidiaの会員登録が必要となります。
インストールしたCUDAのバージョンを確認した後、必要な物をダウンロードします。
公式ページと手順は以下を参照されるといいと思いました。

https://developer.nvidia.com/rdp/cudnn-download
https://docs.nvidia.com/deeplearning/sdk/cudnn-install/index.html


私の場合は、↓の 3つをセットアップしました。
cuDNN Runtime Library for Ubuntu16.04 
cuDNN Developer Library for Ubuntu16.04 
cuDNN Code Sample and Library for Ubuntu16.04 

![qiita3.png](https://qiita-image-store.s3.amazonaws.com/0/214695/53229bc3-875e-fa37-7776-4f3dba5f4729.png)


```
$ sudo dpkg -i libcudnn7_7.5.0.56-1+cuda9.2_amd64.deb 
$ sudo dpkg -i libcudnn7-dev_7.5.0.56-1+cuda9.2_amd64.deb 
$ sudo dpkg -i libcudnn7-doc_7.5.0.56-1+cuda9.2_amd64.deb 

```

あとは、MNISTとよばれるモデルを動かして、動作確認をします。

```
$ ls /usr/src/cudnn_samples_v7/
conv_sample/       mnistCUDNN/        RNN/               samples_common.mk  
$ sudo cp -r  /usr/src/cudnn_samples_v7/  $HOME
$ sudo chown -R ubuntu:ubuntu cudnn_samples_v7/
$ cd cudnn_samples_v7/mnistCUDNN/
$ make clean && make
～略～
$ ./mnistCUDNN
cudnnGetVersion() : 7500 , CUDNN_VERSION from cudnn.h : 7500 (7.5.0)
Host compiler version : GCC 5.4.0
There are 1 CUDA capable devices on your machine :
device 0 : sms 13  Capabilities 3.7, SmClock 823.5 Mhz, MemSize (Mb) 11441, MemClock 2505.0 Mhz, Ecc=1, boardGroupID=0
Using device 0

Testing single precision
Loading image data/one_28x28.pgm
Performing forward propagation ...
Testing cudnnGetConvolutionForwardAlgorithm ...
Fastest algorithm is Algo 2
Testing cudnnFindConvolutionForwardAlgorithm ...
^^^^ CUDNN_STATUS_SUCCESS for Algo 1: 0.036096 time requiring 100 memory
^^^^ CUDNN_STATUS_SUCCESS for Algo 0: 0.037728 time requiring 0 memory
^^^^ CUDNN_STATUS_SUCCESS for Algo 2: 0.070112 time requiring 57600 memory
^^^^ CUDNN_STATUS_SUCCESS for Algo 4: 0.142144 time requiring 207360 memory
^^^^ CUDNN_STATUS_SUCCESS for Algo 5: 0.255360 time requiring 203008 memory
Resulting weights from Softmax:
0.0000000 0.9999399 0.0000000 0.0000000 0.0000561 0.0000000 0.0000012 0.0000017 0.0000010 0.0000000 
Loading image data/three_28x28.pgm
Performing forward propagation ...
Resulting weights from Softmax:
0.0000000 0.0000000 0.0000000 0.9999288 0.0000000 0.0000711 0.0000000 0.0000000 0.0000000 0.0000000 
Loading image data/five_28x28.pgm
Performing forward propagation ...
Resulting weights from Softmax:
0.0000000 0.0000008 0.0000000 0.0000002 0.0000000 0.9999820 0.0000154 0.0000000 0.0000012 0.0000006 

Result of classification: 1 3 5

Test passed!

Testing half precision (math in single precision)
Loading image data/one_28x28.pgm
Performing forward propagation ...
Testing cudnnGetConvolutionForwardAlgorithm ...
Fastest algorithm is Algo 2
Testing cudnnFindConvolutionForwardAlgorithm ...
^^^^ CUDNN_STATUS_SUCCESS for Algo 1: 0.032480 time requiring 100 memory
^^^^ CUDNN_STATUS_SUCCESS for Algo 0: 0.033792 time requiring 0 memory
^^^^ CUDNN_STATUS_SUCCESS for Algo 2: 0.067040 time requiring 28800 memory
^^^^ CUDNN_STATUS_SUCCESS for Algo 4: 0.133792 time requiring 207360 memory
^^^^ CUDNN_STATUS_SUCCESS for Algo 5: 0.252768 time requiring 203008 memory
Resulting weights from Softmax:
0.0000001 1.0000000 0.0000001 0.0000000 0.0000563 0.0000001 0.0000012 0.0000017 0.0000010 0.0000001 
Loading image data/three_28x28.pgm
Performing forward propagation ...
Resulting weights from Softmax:
0.0000000 0.0000000 0.0000000 1.0000000 0.0000000 0.0000714 0.0000000 0.0000000 0.0000000 0.0000000 
Loading image data/five_28x28.pgm
Performing forward propagation ...
Resulting weights from Softmax:
0.0000000 0.0000008 0.0000000 0.0000002 0.0000000 1.0000000 0.0000154 0.0000000 0.0000012 0.0000006 

Result of classification: 1 3 5

Test passed!
```


これで、CUDA / CuDNN の導入が完了しました。 お疲れ様でした。

## 参考
以後、実際に機械学習の開発環境を整えていく上では、nvidia docker2を使うと良いかと思います。
ただ、nvidia docker-2 も色々な手順がwebに散乱している気がしますので、後で投稿するかも。