p2 インスタンスへの TensorFlow 導入

# はじめに
この記事は AWS の GPU マシンのなかで最も性能の高い p2 系のマシンでの、 TensorFlow の環境構築のメモです。
最終的に [AWS Step Function と AWS Lambda を組み合わせて、ここで作ったマシンをスポットインスタンスとして立ち上げ自動で学習を回す](http://qiita.com/halhorn/items/ae402e8c22bc1083ff23)ことを目指しています。

※ p2 インスタンスは現在東京リージョンには導入されていません。オレゴン・バージニアなどのリージョンを使ってください。

# イメージの選定
[TensorFlow 公式ドキュメント](https://www.tensorflow.org/install/install_linux) を読むと Linux の場合 Ubuntu をベースに書かれているようですので、 Ubuntu のインスタンスを選びました。
`Ubuntu Server 16.04 LTS (HVM), SSD Volume Type`

_予め CUDA 環境などが入っている Amazon Linux の AMI 等も有るようですが、レビューを見ていると GPU で動かない等書かれていたりいまいちジャストなものが無かったため、 Ubuntu で一から作りました。_

学習は基本的にデフォルトで存在する ubuntu ユーザーで行うことを想定しています。
（最終的に学習は自動化するので1インスタンス1ユーザーで良い。）

# pyenv, aws コマンド
（私の個人的趣味で bash ではなく zsh を使うので、事前に chsh で zsh をデフォに切り替えてあります。）
オンデマンドで p2 インスタンスを起動し ubuntu ユーザーログインして、以下の通りセットアップしていきます。

python は今後のメンテを考えて pyenv を使います。

```zsh
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install libffi-dev libssl-dev
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
emacs .zshenv
```

以下 **.zshenv** に追加します。
後々の学習自動化で .zshrc に環境変数を書いていると読み込んでくれなくてハマりました。

```
export PYENV_ROOT=$HOME/.pyenv
export PATH=$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH
eval "$(pyenv init -)"
```
更に以下を実行します。

```zsh
source .zshenv
pyenv install 3.5.2
pyenv global 3.5.2
which pip3
> /home/ubuntu/.pyenv/shims/pip3 # pyenv がちゃんと使われていることを確認
pip3 install --upgrade pip
pip3 install aws
```

# GPU / Cuda
http://qiita.com/S_Shimotori/items/3a10b35cf64d74b6b07e
にそって GPU / Cuda 周りをインストールします。 TensorFlow に関しては現状 v1.0 がリリースされており、記事が古いので上記の記事のやり方はとりません。

パスを通しておく部分は .zshenv に書きましょう。

各種ライブラリは最新のものを入れたいので以下はチェックしておきます。

- CUDA
    - https://developer.nvidia.com/cuda-downloads
- cuDNN
    - https://developer.nvidia.com/rdp/cudnn-download
    - 上で選んだ CUDA のバージョンと揃えること

# TensorFlow
https://www.tensorflow.org/install/install_linux
の公式ページに従ってインストール。 pip3 を使うのが楽でした。

```zsh
sudo apt-get install libcupti-dev
sudo pip3 uninstall tensorflow
pip3 install tensorflow-gpu sklearn matplotlib scipy
```

sklearn 他は word2vec 等での画像生成などに必要なので入れています。

# 動作確認
[word2vec](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/word2vec/word2vec_basic.py) のコード等を落としてきて動くかどうか実験してみましょう。

```
git clone https://github.com/tensorflow/tensorflow.git
python tensorflow/tensorflow/examples/tutorials/word2vec/word2vec_basic.py
```

また、実行時に以下のようなログが出ているかで GPU が使われているかわかります。
（この例は p2.8xlarge での場合です。 p2.xlarge の場合 GPU は1枚しか刺さっていないのでもっとログは少なくなります。）

```
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcublas.so.8.0 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcudnn.so.5 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcufft.so.8.0 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcuda.so.1 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcurand.so.8.0 locally
...
I tensorflow/core/common_runtime/gpu/gpu_device.cc:906] DMA: 0 1 2 3 4 5 6 7
I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 0:   Y Y Y Y Y Y Y Y
I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 1:   Y Y Y Y Y Y Y Y
I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 2:   Y Y Y Y Y Y Y Y
I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 3:   Y Y Y Y Y Y Y Y
I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 4:   Y Y Y Y Y Y Y Y
I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 5:   Y Y Y Y Y Y Y Y
I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 6:   Y Y Y Y Y Y Y Y
I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 7:   Y Y Y Y Y Y Y Y
I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:0) -> (device: 0, name: Tesla K80, pci bus id: 0000:00:17.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:1) -> (device: 1, name: Tesla K80, pci bus id: 0000:00:18.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:2) -> (device: 2, name: Tesla K80, pci bus id: 0000:00:19.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:3) -> (device: 3, name: Tesla K80, pci bus id: 0000:00:1a.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:4) -> (device: 4, name: Tesla K80, pci bus id: 0000:00:1b.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:5) -> (device: 5, name: Tesla K80, pci bus id: 0000:00:1c.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:6) -> (device: 6, name: Tesla K80, pci bus id: 0000:00:1d.0)
I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:7) -> (device: 7, name: Tesla K80, pci bus id: 0000:00:1e.0)
```

さらに nvidia-smi コマンドで、実際のところどの GPU が使われているかもわかります。

```
nvidia-smi

Fri Feb 24 07:20:43 2017
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 367.57                 Driver Version: 367.57                    |
|-------------------------------+----------------------+----------------------+
| 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  | 0000:00:17.0     Off |                    0 |
| N/A   56C    P0    59W / 149W |  10915MiB / 11439MiB |     31%      Default |
+-------------------------------+----------------------+----------------------+
|   1  Tesla K80           Off  | 0000:00:18.0     Off |                    0 |
| N/A   44C    P0    71W / 149W |  10877MiB / 11439MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   2  Tesla K80           Off  | 0000:00:19.0     Off |                    0 |
| N/A   55C    P0    58W / 149W |  10877MiB / 11439MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   3  Tesla K80           Off  | 0000:00:1A.0     Off |                    0 |
| N/A   47C    P0    72W / 149W |  10875MiB / 11439MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   4  Tesla K80           Off  | 0000:00:1B.0     Off |                    0 |
| N/A   56C    P0    59W / 149W |  10875MiB / 11439MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   5  Tesla K80           Off  | 0000:00:1C.0     Off |                    0 |
| N/A   49C    P0    70W / 149W |  10875MiB / 11439MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   6  Tesla K80           Off  | 0000:00:1D.0     Off |                    0 |
| N/A   58C    P0    58W / 149W |  10873MiB / 11439MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   7  Tesla K80           Off  | 0000:00:1E.0     Off |                    0 |
| N/A   50C    P0    71W / 149W |  10873MiB / 11439MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
```
GPU Util が GPU 使用率です。0番目の GPU だけが31%使われていることがわかります。
全 GPU を使う場合、 tensorflow のアプリケーションコード上でゴニョゴニョする必要があるようです。（勘違いかも）

# AMI
上記まで完了しましたら、 AMI に固めます。

# 次のステップへ
これで手作業で DeepLearning できるようになりました。
でも、 p2 インスタンスって高いので、学習が完了したら自動でシャットダウンするとか、その他もろもろ自動化したいですよね？
そんなあなたは [AWS スポットインスタンスでの TensorFlow 学習の自動化](http://qiita.com/halhorn/items/ae402e8c22bc1083ff23) へどうぞ。