nvidia-dockerを使用してGPU環境構築

# はじめに
前回の記事[ThinkPad T480SでUbuntu18.04LTSのデュアブ環境構築](https://qiita.com/gen10nal/items/2ca6e88b906a1cfa8a61)でUbuntu18.04のデュアルブートができるようになるところまでやりました。今回はこのUbuntu上でGPUをDeep Leaningに使用できるようになるところまでやります。　　

環境構築の方針ですが、GPUはバージョンに非常にシビア(Keras2.2.1をKeras2.2.2にアップデートしたらGPUが動かなくなったことが以前あった)であるため、今回はNvidia-Dockerを用いてGPU環境を整えていきます。これにより必要に応じて仮想環境を立ち上げればよく、バージョン管理がしやすくなることが期待されます。

- 使用環境
    - ThinkPad T480S
    - GeForce MX150
    - 24GB DDR4
    - Core i7-8550U
    - Ubuntu18.04   

##　概要
1. Nvidia Driverのインストール
2. Dockerのインストール
3. Nvidia-Dockerのインストール
4. 動作確認


# Nvidia-Driverのインストール
まずはNvidia-Driverをインストールします。これがないとCUDAやNvidia-Dockerが使用できません。

Nvidia-Driverを入れる前に少しUbuntuの設定を済ませます。
Ubuntuの初期設定については[Ubuntu 18.04 LTSのインストール直後にやっておきたいことまとめ](https://linuxfan.info/ubuntu-18-04-basic-settings)に詳しいです。すべてをやる必要はないと思いますが、適宜設定を行いましょう。今回必須だと思われるのは[Canonicalパートーナーレポジトリの有効化](https://linuxfan.info/ubuntu-18-04-basic-settings#Canonical)です。これによりサードパーティ製のソフトウェアがインストールできるようになります。　　　


Nvidia-Driverのインストール自体は非常に簡単です。端末を開いて

```
$ sudo ubuntu-drivers autoinstall
```

とコマンドすることでDriverのバージョンが自動で選択されてインストールされます。コマンドすると以下の画像のようにUEFI Secure Bootを有効化するように要求されるので以下の手順で有効化してください。

![Screenshot from 2019-02-14 18-18-41.png](https://qiita-image-store.s3.amazonaws.com/0/359175/2309be2c-3a8d-f79d-6163-56be5c3cbcde.png)
このメッセージが出て端末の操作が効かなくなり対処に困りますが、「ソフトウェアの更新」というアプリケーションを開きソフトウェアの更新を行うと下の画像のような画面になります。
![Screenshot from 2019-02-15 15-05-06.png](https://qiita-image-store.s3.amazonaws.com/0/359175/99faab83-0258-dfc8-a241-75d7b8f6aa13.png)
この画面で右上のNextを押すと認証用のパスワードを設定することを要求されるので２箇所に同じパスワードを入力します。
![Screenshot from 2019-02-15 15-05-21.png](https://qiita-image-store.s3.amazonaws.com/0/359175/ff597367-d43c-ce41-2579-9935c7ba67d9.png)
これで再起動するとBIOSが自動的に開かれるのでEnroll MOKを選択し先ほど設定したパスワードを入力したらUEFI Secure Bootが有効化されます。

再び

```
$ sudo ubuntu-drivers autoinstall
```

とコマンドすることでインストールが完了します。

```
$ sudo reboot
```

とコマンドするなどして一旦再起動しましょう。
正しくインストールできていれば

```
$ nvidia-smi
```

というコマンドでGPUの使用状況などが端末に表示されるようになります。


# Dockerのインストール
Dockerをインストールします。　　
[Dockerの公式ドキュメント](https://docs.docker.com/install/linux/docker-ce/ubuntu/#set-up-the-repository)に従ってdocker-ceをインストールします。
まずはドキュメントのSET UP THE REPOSITORYに従って以下のようにコマンドしていきます。

```
$ sudo apt-get update
$ sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent 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"
```

5行目のところでnightlyなどのオプションをつけたい場合はドキュメントを見てください。ただしstableが推奨なようなので、特にこだわりがなければ上記のように進めて貰えればと思います。　　　

次にドキュメントのINSTALL DOCKER CEに従って以下のようにコマンドします。

```
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
```

これでDockerのインストールは完了です。最後に

```
$ sudo docker run hello-world
```
とコマンドして以下の画像のようなメッセージが出てきたら正しくインストールできています。
![Screenshot from 2019-02-22 16-18-00.png](https://qiita-image-store.s3.amazonaws.com/0/359175/651b0930-ee64-4958-7ca3-7d25046d9eda.png)


また、

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

とコマンドしておくことで、ログインユーザーにDockerの使用権限を与えることができます。

```
# 権限を与えない場合
$ sudo docker hoge

# 権限を与える場合
$ docker hoge
```

要するに、上記のようにsudoと入力せずにDockerを使用できるようになります。


# Nvidia-Dockerのインストール
Nvidia-Dockerをインストールします。これも[Nvidia-Dockerの公式ドキュメント](https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(version-2.0))に従って進めていきます。   
まずは[Repository configuration](https://nvidia.github.io/nvidia-docker/)のDebian-based distributionsの項目に従って以下のようにコマンドしていきます。

```
$ 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
```

次にNvidia-Dockerのドキュメントの指示に戻って以下のようにコマンドします。

```
$ sudo apt-get install nvidia-docker2
$ sudo pkill -SIGHUP dockerd
```

これでNvidia-Dockerのインストールは完了です。


# 動作確認

### 動作させる前の準備
実際に動かす前にもう一つ踏まなければいけない手順があります。　　
まずは[Docker Hub](https://hub.docker.com/)のアカウントを作成します。UsernameとPasswordはこのあと使用するので忘れずに控えてください(Google Chromeでやっていたのですが「パスワードはGoogle上で保管できるので覚える必要がありません」と出てきて危うくやられるところでした)。

次に端末で

```
$ docker login
```

とコマンドしてUsernameとPasswordを入力してログインします。これをしないとdockerコマンドが全然動かなかったです。

試しに

```
$ docker run --runtime=nvidia --rm nvidia/cuda:9.0-base nvidia-smi
```

とコマンドしてみるとDocker経由でGPUの使用状況が確認できることが分かります。

最後に

```
sudo systemctl restart docker
```

としてデーモンを再起動したら準備は完了です。


### 動作させる

ためしにKerasを用いてみんな大好きMNISTを実行してみます。
まずテキストエディタで以下のような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"]
```

今回使用しているMX150というGPUはcuda9.0とcudnn7.0に対応しているので上記のようになっています。
このDockerfileがあるディレクトリに移動して、まず次のようにコマンドしてビルドします。

```
$ docker build . -t mnist
```

tensorflowやkerasなどがインストールされるのでしばらく待ちましょう。ビルドが終わったら

```
$ docker run --runtime=nvidia --rm -it mnist
```

とコマンドして実行してみます。動作中に新しく端末を開いてnvidia-smiコマンドを使ったら画像のようになっており、GPUが動いていることが確認できました。
![Screenshot from 2019-02-21 18-43-05.png](https://qiita-image-store.s3.amazonaws.com/0/359175/c82d8ef2-aaee-ff19-e3de-6e00032c8494.png)


## 補足
先程Docker Hubにログインする必要があるという説明をしましたが、この記事を書きながら改めて色々調べていたら[ystemd と Docker の管理・設定](http://docs.docker.jp/engine/articles/systemd.html)という記事を見つけました。もしかしたら、dockerコマンドが動かせなかったのはデーモンを起動していなかったことが原因かもしれません。これについては僕がまだDockerに慣れ親しんでおらずよく分かっていない部分があるので、詳しい方がいらっしゃればコメントしていただけるとありがたいです。



# 参考にした記事
- [Ubuntu 18.04 に NVIDIA Docker 環境構築 (2018年秋)](https://qiita.com/hoto17296/items/80ba9c23416991757ab7)
- [開発メモ その114 Ubuntu 18.04でNvidia Driverをインストールする](https://taktak.jp/2018/05/01/2974)