GCP Compute engine でGPUを使ってPythonの実行環境を構築する


####経緯とやりたいこと
卒業研究で、グラフデータを取り扱った手法を行っていたのですが、
このグラフデータがかなりのメモリを消費する（主にテンソルの計算）ので
VMで環境構築をしました。

## 環境設定
今回は、以下の設定で環境を構築していきます。

* Ubuntu 16.04 LTS
* GCE
* CUDA 9.0
* cuNN 7.4
* TensolFlowGPU 1.12.0

TensolFlowはバージョンによって、CUDAとバージョンを合わせたりする必要があるみたいです。
このバージョンがずれていたりするとうまくGCPが認識できなかったりするみたいなので、
以下から確認することをお勧めします。
> [TensolFlowGPU ビルド設定](https://www.tensorflow.org/install/source#linux)

## 環境構築の手順

### 0. GCPへの登録
 - CCPへアカウント登録
 - VMインススタンスの課金の有効化
 - VMインスタンスの作成
   - vCPU x 24
   - メモリ 90 GB
   - GPU : NVIDIA Tesla T4
   - Boot disk : Ubuntu 16.04 LTS (Size 250GB)
   - ZONE : us-west1-b
   - HTTPトラフィックを許可

> 参考サイト： [タダでGCPのGPU(NVIDIA Tesla K80)を使ってディープラーニング(NVIDIA DIGITS)する方法](https://qiita.com/SXDSIR2020/items/060806d9fc4366c58d40)

### 1. CUDAとNVIDIAドライバのインストール
VMインスタンスで以下のcommandを実行し，CUDAとドライバをインストールします。

```
$ curl -O http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/cuda-repo-ubuntu1604_9.0.176-1_amd64.deb
$ sudo dpkg -i cuda-repo-ubuntu1604_9.0.176-1_amd64.deb
```

```
$ sudo apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub
```

```
$ sudo apt-get update
$ sudo apt-get install cuda-9-0
```

さらに、GPUのパフォーマンスを最適化するために、以下のcommandを実行します。

```
$ sudo nvidia-smi -pm 1
```

### 2. cuDNN7.0のインストール
[ここから](https://developer.nvidia.com/developer-program)developerアカウントを作成し、cuDNNの以下の３つのファイルを[ダウンロード](https://developer.nvidia.com/rdp/cudnn-download)します。

 - version : ubuntu 16.04 cuda-9.0 version
  - libcudnn7_7.6.4.38-1+cuda9.0_amd64.deb
  - libcudnn7-dev_7.6.4.38-1+cuda9.0_amd64.deb
  - libcudnn7-doc_7.6.4.38-1+cuda9.0_amd64.deb
<br>

ダウンロードが完了したら、３つのファイルをStarageへアップロードします。
ここではバケット名は``cuda_9``とします（お好みで変更してください！）。

アップロードが完了したら gsutil command でそのままインスタンスへの転送します。
アップロードするディレクトリはお好みでどうぞ。

```
$ cd {UP_LOAD_PATH}
$ gsutil cp gs://cuda_9/libcudnn7_7.6.4.38-1+cuda9.0_amd64.deb .
$ gsutil cp gs://cuda_9/libcudnn7-dev_7.6.4.38-1+cuda9.0_amd64.deb .
$ gsutil cp gs://cuda_9/libcudnn7-doc_7.6.4.38-1+cuda9.0_amd64.deb .
```

転送が完了したらファイルを展開してインストールしていきます。

```
$ sudo dpkg -i *.deb
```

### 3. swap file の設定
swap file がない場合、プログラム実行時にメモリリークする可能性があります。
GCEでLinux仮想マシンを作成するとmUbuntuだろうがCentOSだろうが swap file がない状態で仮想マシンが作成される...らしい...です。（私は、ここで詰みました）


ということで、まずはfree commandでswapの有無を確認。

```
$ free -m
```

以下のようになっていたらSwap:がゼロになっているので、swapファイルを作成する必要があります。

```
               total        used        free      shared  buff/cache   available
Mem:            581         148          90           0         342         336
Swap:             0           0           0
```

swap file の作成。swap file の容量はお好みで（今回は10G）

```
$ sudo fallocate -l 10G /swapfile
$ sudo chmod 600 /swapfile
$ sudo mkswap /swapfile
$ sudo swapon /swapfile
```
swap file の確認

```
$ free -m
```

```
               total        used        free      shared  buff/cache   available
Mem:            581         148          88           0         344         336
Swap:          1023           0        10023
```

**Tips** : 再起動時にスワップファイルを自動マウントするには，``/etc/fstab``に以下を追加したらいいみたいです。

```
/swapfile none swap sw 0 0
```

### 4. GPU認識確認とCUDAの設定
CUDAの設定を行っていきます。

```
$ echo "export PATH=/usr/local/cuda-9.0/bin\${PATH:+:\${PATH}}" >> ~/.bashrc
$ source ~/.bashrc
$ sudo /usr/bin/nvidia-persistenced
```

その後、GPUが認識されているかを確認します。

```
$ nvidia-smi
```
以下のようなresponseがあれば、GPUの設定は完了です！

```
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 410.72       Driver Version: 410.72       CUDA Version: 10.0     |
|-------------------------------+----------------------+----------------------+
| 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:04.0 Off |                    0 |
| N/A   42C    P0    65W / 149W |      0MiB / 11441MiB |    100%      Default |
+-------------------------------+----------------------+----------------------+

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

### 5. Python環境の構築

最後に、Python環境をAnadondaで構築していきます。
（普段からAnacondaを使っているのと、他の方法だとなぜがプログラムが動かなかったので今回はAnacondaにしました）

`wget`でAnaconda をダウンロードします。

```
$ wget https://repo.anaconda.com/archive/Anaconda3-5.3.1-Linux-x86_64.sh
$ sh ./Anaconda3-5.3.1-Linux-x86_64.sh
$ echo ". /home/{USER_NAME}/anaconda3/etc/profile.d/conda.sh" >> ~/.bashrc
$ source ~/.bashrc
```
次に、Anaondaの仮装環境を構築します。Pythonのversionと``ENV_NAME``はお好みで。
（今回は``tensorflow==1.12.0``を使いたいので、``Python3.6.5``）

```
$ conda create -n {ENV_NAME} python=3.6.5
$ conda activate {ENV_NAME}
```


### 6. tensorflow-gpuのインストール

condaからinstallします。（ここまでくると安心感がすごい）


```
$ conda install tensorflow-gpu==1.12.0
```


以下のプログラムを実行して、``GPU``と出てきたら`tensorflow-gpu`がGPUを認識してくれています。


```python:test.py
from tensorflow.python.client import device_lib
device_lib.list_local_devices()
```


- OUT

```
[name: "/device:CPU:0"
device_type: "CPU"
memory_limit: 268435456
locality {
}
incarnation: 2319180638018740093
, name: "/device:GPU:0"
device_type: "GPU"
memory_limit: 11324325888
locality {
  bus_id: 1
}
incarnation: 13854674477442207273
physical_device_desc: "device: 0, name: Tesla K80, pci bus id: 0000:00:04.0, compute capability: 3.7"
]
```



その他、必要なライブラリがあればcondaからinstallしてください。

```
$ conda install numpy==1.15.4
$ conda install scipy==1.1.0 
$ conda install scikit-learn==0.20.0
```

これで、GCPのVMを使ってPythonのプログラムを実行できるはずです！

※ 間違いなどがあればコメントをいただけますと幸いです。