Tensorflow + GPU 環境を nvidia-docker を使って楽に作る (on Ubuntu 17.04)

# 背景&目的
[Tensorflow + GPU 環境を nvidia-docker を使って楽に作る (on CentOS 7.2)](http://qiita.com/ttomoaki/items/5a180f61647750eb8d70)
上記の記事のUbuntu版です。
背景と目的に関してはこちらを参照してください。


# 使うもの
- GPU搭載のサーバ
    - OS : Ubuntu 17.04
    - CPU : Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz
    - GPU : NVIDIA Corporation GM200 [GeForce GTX TITAN X] x 1
- nvidia-docker (https://github.com/NVIDIA/nvidia-docker)
- docker (https://www.docker.com/)
- Tensorflow (https://github.com/tensorflow/tensorflow)

# 導入手順
以下の手順で導入できます。

1. ドライバインストール（ホストOS上）
1. Dockerインストール（ホストOS上）
1. nvidia-dockerインストール（ホストOS上）
1. Tensorflow + GPU のイメージ作成＆実行

## 1. ドライバインストール
nouveauグラフィックスドライバを無効化した後、NVIDIAのドライバをインストールします。
（nouveauを無効化しないとドライバインストールが失敗するため）

```bash
## nouveau ドライバーを無効にする
sudo su -

# nouveauが読み込まれていることを確認
lsmod | grep nouveau
---
nouveau              1403757  0
video                  24400  1 nouveau
mxm_wmi                13021  1 nouveau
i2c_algo_bit           13413  1 nouveau
drm_kms_helper        125008  1 nouveau
ttm                    93441  1 nouveau
drm                   349210  3 ttm,drm_kms_helper,nouveau
i2c_core               40582  5 drm,i2c_i801,drm_kms_helper,i2c_algo_bit,nouveau
wmi                    19070  2 mxm_wmi,nouveau
---

# kernelをビルドするためのパッケージをインストール
sudo apt-get install dkms build-essential linux-headers-generic

# nouveauを含まないように設定
sudo vi /etc/modprobe.d/blacklist.conf
---
# disable nouveau
blacklist nouveau
blacklist lbm-nouveau
options nouveau modeset=0
alias nouveau off
alias lbm-nouveau off
---
echo options nouveau modeset=0 | sudo tee -a /etc/modprobe.d/nouveau-kms.conf

# nouveauなしの起動イメージ生成
sudo update-initramfs -u
  
# 再起動
reboot now

# nouveauが読み込まれていないことを確認
lsmod | grep nouveau
  
## nvidia drive のインストール
sudo su -
apt-get install pciutils gcc linux-headers-$(uname -r) 

# GPUの型番を確認
lspci | grep -i nvidia
---
05:00.0 VGA compatible controller: NVIDIA Corporation GM200 [GeForce GTX TITAN X] (rev a1)
---

# http://www.nvidia.co.jp/Download/index.aspx?lang=jp
# ここからGPUに合った最新のドライバを探す
# 今回はこれ
# http://www.nvidia.com/Download/driverResults.aspx/118290/en-us
# http://jp.download.nvidia.com/XFree86/Linux-x86_64/384.98/NVIDIA-Linux-x86_64-384.98.run (2017/12/07最新版)
cd /tmp/
wget http://us.download.nvidia.com/XFree86/Linux-x86_64/375.66/NVIDIA-Linux-x86_64-375.66.run
sh NVIDIA-Linux-x86_64-375.66.run
# 誘導にしたがってインストールする

# 再起動
reboot now

# GPUが認識されているかを確認
nvidia-smi
# 以下の様な出力を確認
---
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 375.66                 Driver Version: 375.66                    |
|-------------------------------+----------------------+----------------------+
| 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 TIT...  Off  | 0000:05:00.0     Off |                  N/A |
|  0%   56C    P0    54W / 250W |      0MiB / 12205MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

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

## 2. Dockerインストール
[公式のインストールマニュアル](https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/#install-docker-ce)に従ってインストールします。

sudo無しでdockerコマンド使えるようにユーザをグループに追加。

```bash
sudo gpasswd -a $USER docker
sudo service docker restart
```

docker-composeもインストールしておきましょう。
[Install Docker Compose](https://docs.docker.com/compose/install/#install-compose)

## 3. nvidia-dockerインストール
[公式のQuickStart](https://github.com/NVIDIA/nvidia-docker)に従ってインストールしたいのですが、公式はUbuntu17をまだサポートしていないようなので、編集されたdebファイルを用いてインストールします。

参考)
https://github.com/NVIDIA/nvidia-docker/issues/412
https://github.com/NVIDIA/nvidia-docker/issues/234

```bash
### nvidia-docker install
# Install nvidia-docker and nvidia-docker-plugin
wget -P /tmp https://github.com/NVIDIA/nvidia-docker/files/818401/nvidia-docker_1.0.1-yakkety_amd64.deb.zip
unzip /tmp/nvidia-docker_1.0.1-yakkety_amd64.deb.zip -d /tmp/
sudo dpkg -i /tmp/nvidia-docker*.deb && rm /tmp/nvidia-docker*.deb

# Test nvidia-smi
nvidia-docker run --rm nvidia/cuda nvidia-smi
# 以下の様な出力を確認
---
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 375.66                 Driver Version: 375.66                    |
|-------------------------------+----------------------+----------------------+
| 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 TIT...  Off  | 0000:05:00.0     Off |                  N/A |
| 22%   48C    P8    28W / 250W |      0MiB / 12205MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

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

## 4. Tensorflow + GPU のイメージ作成＆実行
https://hub.docker.com/r/tensorflow/tensorflow/
Tensorflowが提供しているDockerhubのイメージを使います。

```bash
## run tensorflow docker
nvidia-docker run -it -p 8888:8888 gcr.io/tensorflow/tensorflow:latest-gpu
```

Dockerを起動後
http://${HOST_IP}:8888/
にアクセスすればjupyterの画面が確認できます。

![jupyter_home.png](https://qiita-image-store.s3.amazonaws.com/0/39236/85f7665b-fb97-6dd6-118d-9a9bc82856d3.png)

3_mnist_from_scratch.ipynb のnotebookを起動して Cell -> Run All でサンプルが動くことを確認します。結果を確認。

![3_mnist_from_scratch.png](https://qiita-image-store.s3.amazonaws.com/0/39236/4cdfc692-78ef-9bbd-f7b3-9fa91c74137f.png)

jupyterのログでGPUを使って計算されていることを確認します。

```
2017-08-17 08:02:43.311687: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:893] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2017-08-17 08:02:43.312309: I tensorflow/core/common_runtime/gpu/gpu_device.cc:940] Found device 0 with properties:
name: GeForce GTX TITAN X
major: 5 minor: 2 memoryClockRate (GHz) 1.076
pciBusID 0000:05:00.0
Total memory: 11.92GiB
Free memory: 11.81GiB
2017-08-17 08:02:43.312328: I tensorflow/core/common_runtime/gpu/gpu_device.cc:961] DMA: 0
2017-08-17 08:02:43.312346: I tensorflow/core/common_runtime/gpu/gpu_device.cc:971] 0:   Y
2017-08-17 08:02:43.312358: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1030] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX TITAN X, pci bus id: 0000:05:00.0)
```

以上です。