Ubuntu 18.04 に NVIDIA Docker 環境構築 (2018年秋)

Deep Learning 界隈のツールはまだまだアップデートが激しくて、ちょっと目を離すと環境構築手順が変わっていたりするので面倒くさい。

むかし書いた [趣味でディープラーニングするための GPU 環境を安上がりに作る方法](https://qiita.com/hoto17296/items/16f57b319a0293bd2688) が今でも地味に伸びているのだけど、あの頃の環境構築手順とも変わってきたのでもう一度まとめておく。

あと Amazon EC2 の p3 インスタンスで Tesla V100 が使えるようになったので、どれだけ速いのか試してみたかった、というのもある。

## (2018.10 追記) NVIDIA Volta Deep Learning AMI
[NVIDIA Volta Deep Learning AMI](https://aws.amazon.com/marketplace/pp/B076K31M1S) なんてのがあることを知った。

- NVIDIA 公式
- Ubuntu Server 16.04 ベース
- Volta 用のドライバインストール済み
- Docker + NVIDIA Docker インストール済み

AWS で、かつ Volta GPU (p3 インスタンス) を使うのであればコレを使えばいいと思う。

## 作る環境
- Amazon EC2 の p3.2xlarge インスタンス
    - 現時点で最強の GPU、Tesla V100 が載っている、とても強い
    - とても高い (3.06 USD/時間)
- Ubuntu 18.04 LTS
    - [AWS Marketplace の AMI](https://aws.amazon.com/marketplace/pp/B07CQ33QKV) を使った
- Docker 18.06
- NVIDIA Docker 2

## 作り方
### GPU ドライバを入れる
`apt` で入るドライバでも V100 に対応しているらしい。

``` console
$ sudo apt update
$ sudo apt install -y nvidia-384
$ sudo reboot
```

確認

``` console
$ nvidia-smi
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.48                 Driver Version: 390.48                    |
|-------------------------------+----------------------+----------------------+
| 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 V100-SXM2...  Off  | 00000000:00:1E.0 Off |                    0 |
| N/A   31C    P0    39W / 300W |      0MiB / 16160MiB |      3%      Default |
+-------------------------------+----------------------+----------------------+
```

`nvidia-384` をインストールするとバージョン 390.48 のドライバが入るのは一体何故なんだぜ？

### Docker を入れる
[Docker 公式ドキュメント](https://docs.docker.com/install/linux/docker-ce/ubuntu/#set-up-the-repository) に従って `docker-ce` を入れる。

`apt install docker.io` でも Docker をインストールできるが、これだと少しバージョンが古くてこの後入れる NVIDIA Docker 2 が入らないので、公式ドキュメントに従って最新版を入れる必要がある。

あとログインユーザから Docker リソースを触れるように権限を与えておく。

``` console
$ sudo usermod -aG docker $USER
```

これはログインし直すと反映される。

### NVIDIA Docker 2 を入れる
以下の２つの公式ドキュメントに従って、NVIDIA Docker 2 を入れる。

0. [Repository configuration | nvidia-docker](https://nvidia.github.io/nvidia-docker/)
0. [Installation (version 2.0) · NVIDIA/nvidia-docker Wiki](https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(version-2.0))

## 試しに動かす
Keras の MNIST サンプルが動く Dockerfile がこちら。

``` Dockerfile:Dockerfile
FROM nvidia/cuda:9.0-cudnn7-runtime

RUN apt update && apt install -y python3-pip
RUN pip3 install tensorflow-gpu keras

RUN apt install -y wget
RUN wget https://raw.githubusercontent.com/fchollet/keras/master/examples/mnist_cnn.py

CMD ["python3", "/mnist_cnn.py"]
```

CUDA 9.1 以上にはまだ TensorFlow が対応していない？っぽいので 9.0 を利用した。

これをビルドして動かしてみる。

``` console
$ docker build . -t mnist
$ docker run --runtime=nvidia --rm -it mnist
```

```
Using TensorFlow backend.
Downloading data from https://s3.amazonaws.com/img-datasets/mnist.npz
11493376/11490434 [==============================] - 4s 0us/step
x_train shape: (60000, 28, 28, 1)
60000 train samples
10000 test samples
Train on 60000 samples, validate on 10000 samples
Epoch 1/12
2018-09-18 09:32:37.310108: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2018-09-18 09:32:38.461658: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:897] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2018-09-18 09:32:38.462128: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1405] Found device 0 with properties:
name: Tesla V100-SXM2-16GB major: 7 minor: 0 memoryClockRate(GHz): 1.53
pciBusID: 0000:00:1e.0
totalMemory: 15.78GiB freeMemory: 15.36GiB
2018-09-18 09:32:38.462169: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1484] Adding visible gpu devices: 0
2018-09-18 09:32:38.837916: I tensorflow/core/common_runtime/gpu/gpu_device.cc:965] Device interconnect StreamExecutor with strength 1 edge matrix:
2018-09-18 09:32:38.837997: I tensorflow/core/common_runtime/gpu/gpu_device.cc:971]      0
2018-09-18 09:32:38.838016: I tensorflow/core/common_runtime/gpu/gpu_device.cc:984] 0:   N
2018-09-18 09:32:38.838372: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1097] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 14865 MB memory) -> physical GPU (device: 0, name: Tesla V100-SXM2-16GB, pcibus id: 0000:00:1e.0, compute capability: 7.0)
60000/60000 [==============================] - 12s 201us/step - loss: 0.2613 - acc: 0.9205 - val_loss: 0.0542 - val_acc: 0.9827
Epoch 2/12
60000/60000 [==============================] - 3s 44us/step - loss: 0.0869 - acc: 0.9738 - val_loss: 0.0391 - val_acc: 0.9867
Epoch 3/12
60000/60000 [==============================] - 3s 44us/step - loss: 0.0627 - acc: 0.9809 - val_loss: 0.0330 - val_acc: 0.9894
Epoch 4/12
60000/60000 [==============================] - 3s 44us/step - loss: 0.0539 - acc: 0.9837 - val_loss: 0.0342 - val_acc: 0.9884
Epoch 5/12
60000/60000 [==============================] - 3s 44us/step - loss: 0.0470 - acc: 0.9865 - val_loss: 0.0294 - val_acc: 0.9894
Epoch 6/12
60000/60000 [==============================] - 3s 44us/step - loss: 0.0411 - acc: 0.9874 - val_loss: 0.0313 - val_acc: 0.9892
Epoch 7/12
60000/60000 [==============================] - 3s 44us/step - loss: 0.0380 - acc: 0.9881 - val_loss: 0.0276 - val_acc: 0.9900
Epoch 8/12
60000/60000 [==============================] - 3s 44us/step - loss: 0.0337 - acc: 0.9895 - val_loss: 0.0299 - val_acc: 0.9901
Epoch 9/12
60000/60000 [==============================] - 3s 44us/step - loss: 0.0308 - acc: 0.9906 - val_loss: 0.0277 - val_acc: 0.9909
Epoch 10/12
60000/60000 [==============================] - 3s 44us/step - loss: 0.0290 - acc: 0.9909 - val_loss: 0.0322 - val_acc: 0.9897
Epoch 11/12
60000/60000 [==============================] - 3s 44us/step - loss: 0.0268 - acc: 0.9919 - val_loss: 0.0269 - val_acc: 0.9909
Epoch 12/12
60000/60000 [==============================] - 3s 44us/step - loss: 0.0267 - acc: 0.9919 - val_loss: 0.0246 - val_acc: 0.9914
Test loss: 0.024574520272191876
Test accuracy: 0.9914
```

p2 インスタンス (Tesla K80) のときは 1 epoch あたり 9s だったのが、3s で終わっている。

すっごーい (適当)