最短で作るローカルのディープラーニングGPU環境


# はじめに

ディープラーニングの学習を実行するにはGPUはほぼ必須ですが、GPUを使用するにはNVIDIAドライバー、CUDAなど色々とインストールする必要があります。
この作業はバージョンの組み合わせやインストール方法で結構ハマることが多いようです。

ubuntu-drivers と NVIDIA Docker を使えばこれらを簡単にインストールできます。

# 環境

- [Ubuntu 18.04 LTS 日本語 Remix](https://www.ubuntulinux.jp/home)
- [GeForce GTX 960](https://www.nvidia.co.jp/object/geforce-gtx-960-jp.html)

# ディープラーニングでGPUを使用するのに必要なもの

- [NVIDIAドライバー](http://www.nvidia.co.jp/object/unix-jp.html)
    - LinuxでNVIDIAグラフィックカードのGPUを認識させるのに必要
- [CUDA](https://developer.nvidia.com/cuda-toolkit)
    - NVIDIAが開発・提供している、GPU向けの汎用並列コンピューティングプラットフォーム
- [cuDNN](https://developer.nvidia.com/cudnn)
    - NVIDIAが公開しているDeep Learning用のライブラリ
- [CuPy](https://cupy.chainer.org/)
    - PythonからGPUを使用するためのモジュール
    - 他にもNumba,PyCudaなどがある

# 使うもの

- ubuntu-drivers
    - Ubuntu 18.04 LTS から追加された(?)コマンド
    - NVIDIAドライバーのインストールが簡単に行える
- [NVIDIA Docker](https://github.com/NVIDIA/nvidia-docker)
    - DockerコンテナでGPUを使うためのツール
- [nvidia/cuda](https://hub.docker.com/r/nvidia/cuda/)
    - CUDA/cuDNNがインストール済みのDockerイメージ
- [cupy/cupy](https://hub.docker.com/r/cupy/cupy/)
    - nvidia/cudaをベースにPythonとCuPyを追加したDockerイメージ

# 手順

1. NVIDIAドライバーのインストール
2. Docker CE のインストール
3. Docker Compose のインストール
4. NVIDIA Docker のインストール
5. Dockerコンテナの作成

## 1. NVIDIAドライバーのインストール

`ubuntu-drivers`を使用します。

https://linuxconfig.org/how-to-install-the-nvidia-drivers-on-ubuntu-18-04-bionic-beaver-linux

[Ubuntu 18.04 LTS 日本語 Remix](https://www.ubuntulinux.jp/home)を通常インストールしていれば`ubuntu-drivers`は入っていますが、ない場合はaptでインストールします。

```shell
sudo apt install ubuntu-drivers-common
```

あとは以下のコマンドだけでNVIDIAドライバーがインストールできます。

```shell
sudo ubuntu-drivers autoinstall
```

## 2. Docker CE のインストール

公式ドキュメントの通りインストールします。

https://docs.docker.com/install/linux/docker-ce/ubuntu/#install-docker-ce

一応コマンドを貼り付けておきます。

```shell
sudo apt-get update
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88
sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
sudo apt-get update
sudo apt-get install docker-ce
```

最後にユーザーをDockerグループに追加します。

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

*注意点*
Ubuntuでは`apt`で`docker.io`というのがインストール可能ですが、こちらでは NVIDIA Docker がインストールできなくなります。必ず`Docker CE`をインストールしてください。

## 3. Docker Compose のインストール

こちらも公式ドキュメントの通りインストールします。

https://docs.docker.com/compose/install/#install-compose

```shell
sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
```

## 4. NVIDIA Docker のインストール

公式ドキュメントの通りインストールします。

https://github.com/NVIDIA/nvidia-docker#ubuntu-140416041804-debian-jessiestretch

```shell
# Add the package repositories
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | \
  sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | \
  sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update

# Install nvidia-docker2 and reload the Docker daemon configuration
sudo apt-get install -y nvidia-docker2
sudo pkill -SIGHUP dockerd

# Test nvidia-smi with the latest official CUDA image
docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi
```

## 5. Dockerコンテナの作成

こちらの記事が参考になります。

[nvidia-dockerでGPUコンテナの作成 - Qiita](https://qiita.com/uni-3/items/f5911aaaa538b33f370f)

GPUを使うコンテナのベースイメージは [`nvidia/cuda`](https://hub.docker.com/r/nvidia/cuda/) になりますが、Pythonは含まれていないので自分でインストールする必要があります。
PythonでCuPyを使うのであれば [`cupy/cupy`](https://hub.docker.com/r/cupy/cupy/)がいいでしょう。
こちらは[Python2とPython3](https://hub.docker.com/r/cupy/cupy/tags/)がインストール済みのイメージがそれぞれ用意されています。

# Chainerで作る コンテンツ自動生成AIプログラミング入門

最後に、「[Chainerで作る コンテンツ自動生成AIプログラミング入門](http://www.c-r.com/book/detail/1201)」という書籍のサンプルコードを動かす環境のDockerfileを書いたので載せておきます。

```dockerfile:Dockerfile
FROM cupy/cupy:latest-python3

RUN apt update -y && \
    apt install -y --no-install-recommends \
    wget \
    gdal-bin \
    mecab \
    mecab-ipadic-utf8

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

RUN pip3 install --no-cache-dir \
    pillow \
    h5py \
    chainer
```

```yml:docker-compose.yml
version: '2.3'

services:
  app:
    build: .
    runtime: nvidia
    volumes:
      - ./:/usr/src/app/
```

## 実行方法

上記ファイルとサンプルコードを同じディレクトリに配置します。

```:ファイル構成
project/
    Dockerfile
    docker-compose.yml
    sample/
```

Dockerイメージをビルドします。

```
cd project
docker-compose build
```

コンテナを実行してシェルを起動します。

```shell
docker-compose run --rm app bash
```

以下はコンテナ内のシェルで実行します。


```shell
root@7edd84542481:/usr/src/app# cd sample/chapt02
root@7edd84542481:/usr/src/app/sample/chapt02# python3 chapt02-1.py
Downloading from http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz...
Downloading from http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz...
Downloading from http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz...
Downloading from http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz...

root@7edd84542481:/usr/src/app/sample/chapt02# python3 chapt02-2.py 
0	0.9999981
1	2.981141e-15
2	1.2600368e-06
3	9.146645e-10
4	7.1973303e-13
5	8.957497e-09
6	5.611625e-07
7	1.8054458e-10
8	1.08702736e-07
9	1.4337494e-10
```

## GPUとCPUでパフォーマンス比較

書籍のサンプルコードは以下のようになっていて、`uses_device = -1`とするとGPUを使用しない動作になります。

```python
uses_device = 0                # GPU#0を使用
if uses_device >= 0:
	# GPUを使う
	:
	# GPU用データ形式に変換
	:
```

GPUを使用する場合(uses_device=0)とCPUを使用する場合(uses_device=-1)で実行時間を比較してみます。

```:GPUを使用する場合(uses_device=0)
root@7edd84542481:/usr/src/app/sample/chapt03# python3 chapt03-2.py
     total [..................................................]  0.04%
this epoch [##################................................] 37.61%
      2100 iter, 4 epoch / 10000 epochs
    70.473 iters/sec. Estimated time to finish: 18:54:24.318379.
```

```:CPUを使用する場合(uses_device=-1)
root@7edd84542481:/usr/src/app/sample/chapt03# python3 chapt03-2.py
     total [..................................................]  0.00%
this epoch [####################..............................] 41.68%
       200 iter, 0 epoch / 10000 epochs
    4.2248 iters/sec. Estimated time to finish: 13 days, 3:30:25.476065.
```
|ソース|CPU|GPU|比較|
|:---|---:|---:|---:|
|chapt02-1.py|100s|83s|1.2倍|
|chapt03-1.py|315h|19h|16倍|
|chapt04-1.py|111h|3h21m|33倍|
|chapt06-3.py|33m|8m|4倍|

GeForce GTX 960 は２年前にゲーム用に購入したミドルレンジのグラボですが、それでもこれだけの差が出ました。