Check! Azure VM の GPU インスタンスで Chainer を動かしてみる (Ubuntu)


こんにちは、 @dz_ こと大平かづみです。

Prologue - はじめに
====

もっと GPU のことを知ろうと思って、Azure Linux VM で [Chainer](https://chainer.org/) を動かす環境を作ってみました！

実施環境
---
- Azure Virtual Machine
    - NC6 インスタンス
        - Tesla K80
- Ubuntu 16.04
- [CUDA](https://developer.nvidia.com/cuda-toolkit)
    - [cuDNN](https://developer.nvidia.com/cudnn)
    - [NCCL](https://developer.nvidia.com/nccl)
- Python 3
- [Chainer](https://chainer.org/)

Azure VM の GPU インスタンスについて
====

今回は、 Azure VM の NC6 インスタンスを利用します。

Azure VM のうち、GPUが最適化されたNシリーズは、それぞれの用途に合わせ、NC、ND、NVシリーズが提供されています。

| シリーズ | 搭載GPU | ドライバ | 主な特徴 |
| --- | --- | --- | --- |
| NC | Tesla K80  | CUDA | CUDA を利用した高速な計算に適している。 |
| NCv2 | Tesla P100 | CUDA | NCシリーズの2倍以上の計算性能を有する。 |
| ND | Tesla P40 | CUDA | ディープラーニングのワークロードを想定した構成。 |
| NV | Tesla M60 | GRID | リモートでのグラフィック描画処理、ストリーミングなどに適している。 |

- [Azure Linux VM のサイズ - GPU | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/virtual-machines/linux/sizes-gpu)
- [Linux 用 Azure N シリーズ ドライバー セットアップ | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/virtual-machines/linux/n-series-driver-setup)

環境構築
====

さくっと Ubuntu 16.04 の VM を起動して、下記の手順で環境を構築しました。関連資料は後述しています。

```bash
# GPU のチェック
$ lspci | grep -i NVIDIA
2ffb:00:00.0 3D controller: NVIDIA Corporation GK210GL [Tesla K80] (rev a1)

# 初期化
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git build-essential

# CUDAドライバ、 CUDA toolkit のインストール
CUDA_REPO_PKG=cuda-repo-ubuntu1604_9.1.85-1_amd64.deb
wget -O /tmp/${CUDA_REPO_PKG} http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/${CUDA_REPO_PKG}
sudo dpkg -i /tmp/${CUDA_REPO_PKG}
sudo apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub
rm -f /tmp/${CUDA_REPO_PKG}
sudo apt-get update
sudo apt-get install cuda-drivers
sudo apt-get install cuda
sudo reboot

# CUDAドライバの確認
$ nvidia-smi
Wed Feb  7 12:09:27 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.12                 Driver Version: 390.12                    |
|-------------------------------+----------------------+----------------------+
| 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  | 00002FFB:00:00.0 Off |                    0 |
| N/A   39C    P0    73W / 149W |      0MiB / 11441MiB |     99%      Default |
+-------------------------------+----------------------+----------------------+

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

# GPU の persistence mode を有効化
$ $ sudo nvidia-smi -pm 1
Enabled persistence mode for GPU 00002FFB:00:00.0.
All done.

# cuDNN のインストール
# 下記を参照して debファイルをダウンロードし、インストールする
sudo dpkg -i libcudnn7_7.0.5.15-1+cuda9.1_amd64.deb
sudo dpkg -i libcudnn7-dev_7.0.5.15-1+cuda9.1_amd64.deb

# NCCL のインストール
# 下記を参照して debファイルをダウンロードし、インストールする
sudo dpkg -i nvidia-machine-learning-repo-ubuntu1604_1.0.0-1_amd64.deb
sudo apt-get install libnccl2=2.1.4-1+cuda9.1 libnccl-dev=2.1.4-1+cuda9.1

# Python 3 環境を整備
sudo apt-get install python3-venv libpython3.5-dev
python3 -m venv ~/chainerenv
source ~/chainerenv/bin/activate
(chainerenv) pip install -U pip setuptools

# CuPy および Chainer をインストール
(chainerenv) pip install cupy
(chainerenv) pip install chainer
```
- Chainer
    - [Installation Guide — Chainer 3.3.0 documentation](https://docs.chainer.org/en/stable/install.html)
- CuPy
    - [Installation Guide — CuPy 2.3.0 documentation](https://docs-cupy.chainer.org/en/stable/install.html)
- CUDA Toolkit
    - [CUDA Toolkit 9.1 Download | NVIDIA Developer](https://developer.nvidia.com/cuda-downloads)
        - `Linux` > `x86_64` > `Ubuntu` > `16.04` > `deb (network)` を選択
- cuDNN
    - [NVIDIA cuDNN | NVIDIA Developer](https://developer.nvidia.com/cudnn)
        - Signin/Login して進み、`Download cuDNN v7.0.5 (Dec 11, 2017), for CUDA 9.1` を開く
            - `cuDNN v7.0.5 Runtime Library for Ubuntu16.04 (Deb)` と `cuDNN v7.0.5 Developer Library for Ubuntu16.04 (Deb)` をそれぞれダウンロードし、サーバーにアップロードする。
    - [2.3. Installing cuDNN on Linux - cuDNN Installation Guide :: Deep Learning SDK Documentation](http://docs.nvidia.com/deeplearning/sdk/cudnn-install/index.html#installlinux)
- NCCL
    - [NVIDIA Collective Communications Library (NCCL) | NVIDIA Developer](https://developer.nvidia.com/nccl)
        - Signin/Login して進み、 `Download NCCL v2.1.4, for CUDA 9.1, Jan 18, 2018` > `Network Installer for NCCL 2.1.4 for Ubuntu16.04` をダウンロードし、サーバーにアップロードする。
    - [3. Installing NCCL - NCCL Installation Guide :: Deep Learning SDK Documentation](http://docs.nvidia.com/deeplearning/sdk/nccl-install-guide/index.html#down)


動作確認
====

Chainer ドキュメントでも示されている MNIST のサンプルで動作確認をしてみます。

- [Run Neural Networks on a Single GPU | Using GPU(s) in Chainer — Chainer 3.3.0 documentation](https://docs.chainer.org/en/stable/tutorial/gpu.html?highlight=mnist#run-neural-networks-on-a-single-gpu)
- [chainer/examples/mnist at master · chainer/chainer](https://github.com/chainer/chainer/tree/master/examples/mnist)

```bash
# Chainer のリポジトリをクローンする
(chainerenv) git clone https://github.com/chainer/chainer.git

# Chainer のリリースバージョンを確認する
(chainerenv) pip show chainer
Name: chainer
Version: 3.3.0
...<略>...

# Chainer のリリースバージョンに合わせる（※1）
(chainerenv) git checkout v3.3.0

# GPU 0番を指定して実行する（※2 --noplot で描画を無効にする）
(chainerenv) cd chainer/examples/mnist/
(chainerenv) python train_mnist.py --gpu=0 --noplot
```
上記の演算結果は以下のようになりました。ちゃんと動きましたー！

```bash
GPU: 0
# unit: 1000
# Minibatch-size: 100
# epoch: 20

epoch       main/loss   validation/main/loss  main/accuracy  validation/main/accuracy  elapsed_time
1           0.190745    0.0844128             0.9413         0.9736                    3.84636
2           0.0740447   0.0751793             0.976783       0.9776                    6.94456
3           0.047704    0.0771665             0.984898       0.9766                    9.99173
4           0.0343457   0.0671767             0.988882       0.9809                    13.0028
5           0.0286408   0.0626079             0.990581       0.9815                    16.1552
6           0.0234828   0.0909236             0.992348       0.9765                    19.1792
7           0.0210257   0.062924              0.993132       0.9838                    22.133
8           0.0160507   0.116491              0.994482       0.9731                    25.0751
9           0.0191589   0.0819106             0.993716       0.9802                    28.0509
10          0.0140842   0.0906959             0.995482       0.9809                    31.0017
11          0.0152206   0.0936491             0.994832       0.9801                    33.9752
12          0.00902538  0.0895441             0.997132       0.9816                    36.953
13          0.0142587   0.0820686             0.995833       0.985                     39.9059
14          0.00841077  0.0988157             0.997166       0.9819                    42.882
15          0.0121234   0.1204                0.996332       0.9792                    45.8412
16          0.0135489   0.133547              0.996166       0.9764                    48.8171
17          0.0100978   0.100952              0.997133       0.9818                    51.8358
18          0.00653642  0.104121              0.998133       0.9816                    54.7911
19          0.0109874   0.119144              0.996782       0.9803                    57.7446
20          0.0121006   0.0777734             0.996632       0.9844                    60.7114
```

## examples に関する備考

じつは、ここで使う `train_mnist.py` は、現時点（2018年2月）の master ブランチだとエラーが出るので、こちらの記事を参考に回避しました。大変助かりました！（具体的な解説は後述）

- [Ubuntu 16.04 LTSにChainerをインストールする - TadaoYamaokaの日記](http://tadaoyamaoka.hatenablog.com/entry/2018/01/05/232416)


### ※1 リリースバージョンのタグに切り替える

Chainer は、 `pip` で配布されているリリースバージョンは `3.3.0` ですが、 `master` ブランチは `v4.0.0b3` のリリースタグに含まれます。このバージョン間で `train_mnist.py` に差異があり、 `master` ブランチをそのまま使うと以下のエラーが出てしまいます。ですので、ここでは `v3.3.0` のタグに切り替えて使用しました。

- 該当のコミット: [Move StandardUpdater and ParallelUpdater under chainer.training.updat… · chainer/chainer@9fd1500](https://github.com/chainer/chainer/commit/9fd1500b60d6f24cb4bf03d70c5af23700da711b)

```
AttributeError: module 'chainer.training.updaters' has no attribute 'StandardUpdater'
```

もしくは、下記のように該当箇所を書き換えても動作します。

```bash
# 該当箇所のみ v3.3.0 の構造に書き換える
sed -i -E 's/^(.+?)training.updaters.StandardUpdater(.+?)$/\1training.StandardUpdater\2/g' examples/mnist/train_mnist.py
```

### ※2 `--noplot` オプションについて

`matplotlib` がない場合、このオプションを指定しないと以下のような warning が表示されます。 `matplotlib` をインストールしてもGUI環境がない場合は表示できないため、この `--noplot` オプションを指定するとよさそうです。

```bash:matplotlibがない場合のwarning
/home/user/chainerenv/lib/python3.5/site-packages/chainer/training/extensions/plot_report.py:25: UserWarning: matplotlib is not installed on your environment, so nothing
will be plotted at this time. Please install matplotlib to plot figures.

  $ pip install matplotlib

  warnings.warn('matplotlib is not installed on your environment, '
```

- [MNIST example gets invalid DISPLAY error when run without X11 · Issue #3924 · chainer/chainer](https://github.com/chainer/chainer/issues/3924)

余談
====
`matplotlib` をインストールする場合、 `python3-tk` も必要です。ただし、GUI環境がない場合はどちらにしろ以下のエラーになります。

```bash:matplotlibにはpython3-tkが必要
pip install matplotlib
...<略>...
ImportError: No module named '_tkinter', please install the python3-tk package
```
```bash:ディスプレイ環境がないとmatplotlibは使えない
# python3-tk をインストールする
sudo apt-get install python3-tk

# matplotlib をインストールする
pip install matplotlib

# train_mnist.py を実行してみるが、 ディスプレイ環境がないためエラー
python train_mnist.py --gpu=0

...<略>...
    self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
_tkinter.TclError: no display name and no $DISPLAY environment variable
```

Epilogue - おわりに
====
深層学習についてももっと理解を深めたく、これをベースに勉強を進めていけたらいいなと思います！