AWS EC2 P2インスタンスでnvidia-docker+caffeを使う

## はじめに

[前回の記事](http://qiita.com/take60/items/19362ffd4829b921ad47)でCUDAおよびCuDNNを自分でインストールする手法を紹介しましたが、Dockerを使うとさらに簡単にディープラーニング環境を構築できます。
さらに、簡単に使えるだけではなく、複数のバージョンやフレームワークを共存させるときにも便利です。

書き終えたときに[こんなすばらしい投稿](http://qiita.com/daxanya1/items/f04c7f75a6d2ecb92b23)を発見し、これ自体の価値はなくなってしまいましたが、自分用のメモということで公開します。

OS:ubuntu 14.04

## 準備

AWSのP２インスタンスを立てた後に色々インストールします。

```
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y build-essential git python-pip python-dev libxml2-dev libxslt1-dev zlib1g-dev libcurl4-openssl-dev libatlas-base-dev linux-image-extra-virtual libopencv-dev python-numpy
sudo apt-get autoremove -y 
```

ホスト側のドライバを無効にする

`sudo vi /etc/modprobe.d/blacklist-nouveau.conf`　を実行

```/etc/modprobe.d/blacklist-nouveau.conf
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
sudo update-initramfs -u
sudo reboot
```

## nvidia-driverのインストール

事前にGPUに適合するドライバを調べておく
P2インスタンスのGPUはK80

```
sudo apt-get install -y linux-source 
sudo apt-get install -y linux-headers-`uname -r`
wget http://us.download.nvidia.com/XFree86/Linux-x86_64/352.99/NVIDIA-Linux-x86_64-352.99.run
sudo chmod +x NVIDIA-Linux-x86_64-352.99.run
sudo ./NVIDIA-Linux-x86_64-352.99.run
```

## nvidia-dockerのインストール

ここからが肝です。
Dockerは仮想化技術の1つで、コンテナ型と呼ばれます。これは、仮想マシンごとにゲストOSが必要でハードウェアリソースの一部を占有するハイパーバイザ型と異なり、1つのOS上で実行することができるので、オーバーヘッドを少なくすることができます。Dockerはコンテナを管理するためのエンジンで、コンテナはアプリケーション単位で独立させることができるので、バージョン違いの複数バージョンのライブラリを動かすことができます。

以上、"Dockerとは" とググると出てくるような情報でした。
いつかDockerに関する記事もかけたらいいな、と思います。


コンテナとホストはファイルやデバイスを共有させることもできるので、Dockerのコンテナを立ち上げ、そこからホストのGPUにアクセスできるようにします。

まず、Dockerをインストールします。

```
curl -fsSL https://get.docker.com/ | sh
```

Dockerはsudo権限が必要なので、ユーザをdockerグループに加えます。

```
sudo groupadd docker
sudo gpasswd -a $USER docker
# exitして再ログインすると反映される。
sudo systemctl restart docker
exit
```

次に[nvidia-docker](https://github.com/NVIDIA/nvidia-docker)をインストールします。
自力でdockerの`--device`オプションを用いて実行することも可能であるのですが、nvidia-dockerはそれらの処理のラッパーのような役割を担ってくれるので非常に便利です。
インストールは上記GitHubページを参考に実行します。

```
# Install nvidia-docker and nvidia-docker-plugin
wget -P /tmp https://github.com/NVIDIA/nvidia-docker/releases/download/v1.0.0-rc.3/nvidia-docker_1.0.0.rc.3-1_amd64.deb
sudo dpkg -i /tmp/nvidia-docker*.deb && rm /tmp/nvidia-docker*.deb
```

次にテストします。

```
nvidia-docker run --rm nvidia/cuda:7.5 nvidia-smi
```

やっていることとしては、nvidia/cudaイメージをダウンロードして、コンテナを立ち上げて`nvidia-smi`コマンドを実行しています。
GPU情報が出たらOKです。

## caffeのDockerイメージを作成

Dockerはイメージを作成して、それをコンテナとして起動、というような流れで利用します。
[Docker Hub](https://hub.docker.com/)等からダウンロードして使うことができます。（さきほどのテストイメージはこれを利用）
一方自分でイメージを作成する場合はDockerfileを作成してビルドするのがおすすめです。
これは

- ベースのイメージに何を使うか
- どんなSWをインストールするか
- 起動時のデフォルトコマンドは何か

といった情報をコードで記述することができるため、バージョン管理や何をしているかの確認が容易になります。

CaffeのGithubレポジトリにはすでにCaffeイメージ用のDockerfileが用意されているため、そちらを使います。

```
git clone https://github.com/BVLC/caffe.git
cd caffe/docker
docker build -t caffe:gpu standalone/gpu
```

ビルドには結構時間がかかります。
Dockerファイルは[ここ](https://github.com/BVLC/caffe/blob/master/docker/standalone/gpu/Dockerfile)なのですが、やっていることとしては

1. ベースイメージとしてCUDA7.5およびCuDNN5が入っているものを利用。つまりこれらのインストールが不要！
2. `apt-get`でもろもろインストール
3. /opt/caffeに移動し、Caffeのビルド
4. パスを通す

という感じです。

## テスト
それでは最後にテストしてみましょう。

```
nvidia-docker run -it caffe:gpu
```

これで作成したCaffeのコンテナを起動し、コンテナ上でBashが使える状況です。
あとはよくあるmnistのサンプルを実行します。

```
cd /opt/caffe/
./data/mnist/get_mnist.sh
./examples/mnist/create_mnist.sh
./examples/mnist/train_lenet.sh
```

ちゃんとジョブが実行されますね！

## その他
上記テストだとコンテナを落とした後結果が残りません。
`--volume` でホストとコンテナのボリュームを共有させるなり、`docker cp`でコピーするなりしましょう。