GPU版TensorFlowをAzure NCシリーズ上に構築する

AzureにはGPU搭載のNVシリーズとNCシリーズが存在する。NVシリーズは視覚コンピューティング向け、NCシリーズは数値コンピューティング向け。Deep LearningならNCシリーズを使う。

NCシリーズは現在、米国東部と米国中南部のリージョンにしか提供されていない。また、クォータが高いので無料試用版の場合は上限を開放してサポートにクォータ緩和を要求する必要がある。1-5営業日くらいで対応してもらえる。

以下の情報でNCシリーズのインスタンスを作成したものとして書きます。適宜読み替えてください。

※2017/02/23補足：NCシリーズは、「VM disk type」を「HDD」にしないと選択できません。 

- NC6 Standard
- OS: Ubuntu Server 16.04 LTS
- Username: MaruLabo
- IP addr: x.x.x.x
- ネットワークセキュリティグループでTCP/80を許可（サンプルアプリを実行するため）

[cuDNN](https://developer.nvidia.com/cudnn)は登録・認証しないとダウンロードできないので、ローカルマシンにダウンロードして、scpでインスタンスのストレージへ転送しておきます。

※2017/02/23補足：あくまでもクラウド上で使うためなので、ダウンロードするのは「for Linux」です。また、Windowsだと拡張子が文字化けするという情報をいただきました。その場合はファイル名を直すことで問題なく使用できるとのことです。

```
scp cudnn-8.0-linux-x64-v5.1-tgz MaruLabo@x.x.x.x:/home/MaruLabo
```

sshで接続したら、GPUを確認します。NC6 StandardではTesla K80が1つ認識されています。

```
MaruLabo@MaruLabo:~$ lspci | grep -i nvidia
8184:00:00.0 3D controller: NVIDIA Corporation GK210GL [Tesla K80] (rev a1)
```

cudaとcuDNN、TensorFlowをセットアップします。

```
sudo apt-get update
sudo apt-get upgrade -y

# cudaのインストール
wget http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/cuda-repo-ubuntu1604_8.0.44-1_amd64.deb
sudo dpkg -i cuda-repo-ubuntu1604_8.0.44-1_amd64.deb
sudo apt-get update
sudo apt-get install -y cuda

# cuDNNのインストール
tar xvzf cudnn-8.0-linux-x64-v5.1.tgz
sudo mkdir -p /usr/local/cuda/include /usr/local/cuda/lib64
sudo cp -P cuda/include/cudnn.h /usr/local/cuda/include
sudo cp -P cuda/lib64/libcudnn* /usr/local/cuda/lib64
sudo chmod a+r /usr/local/cuda/include/cudnn.h /usr/local/cuda/lib64/libcudnn*
sudo ldconfig /usr/local/cuda/lib64

# TensorFlow GPU版に必要なパッケージのインストール
sudo apt-get install -y libcupti-dev python python-dev python-pip

# 2017/02/23追記:サンプルアプリをまだ1.0に対応させていないので、0.12.1をインストールします
# pip install tensorflow-gpu
pip install tensorflow-gpu===0.12.1
```

ちなみに、CPUインスタンスの方は、以下のコマンドだけでTensorFlowのセットアップは終わります。

```
sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get install -y python python-dev python-pip
pip install tensorflow==0.12.1
```

ドライバも一緒に入ります。試した環境では367.57になりました。pipパッケージのtensorflow-gpuは現時点でcuda-8、cuDNN-5.1を想定してビルドされていますので、異なるバージョンを使う場合はソースコードから自分でビルドする必要があります。

```
MaruLabo@MaruLabo:~$ nvidia-smi
Thu Feb  2 02:38:37 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  | 8184:00:00.0     Off |                    0 |
| N/A   66C    P0    61W / 149W |      0MiB / 11439MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

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

pythonからtensorflowをimportしたときにCUDAライブラリが読み込まれたというログが出ればGPU版TensorFlowのセットアップは成功です。

```
MaruLabo@MaruLabo:~$ python
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcublas.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcudnn.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcufft.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcuda.so.1 locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcurand.so locally
>>>
```

実際にGPUが使われることを確認するためにTensorFlow公式リポジトリにあるMNISTのSoftmax回帰モデルを走らせます。GPUの数だけ`Creating TensorFlow device`と出ればOK。

```
$ wget https://github.com/tensorflow/tensorflow/raw/master/tensorflow/examples/tutorials/mnist/mnist_softmax.py
$ python mnist_softmax.py
I tensorflow/core/common_runtime/gpu/gpu_device.cc:885] Found device 0 with properties:
name: Tesla K80
major: 3 minor: 7 memoryClockRate (GHz) 0.8235
pciBusID 8184:00:00.0
Total memory: 11.17GiB
Free memory: 11.11GiB
I tensorflow/core/common_runtime/gpu/gpu_device.cc:906] DMA: 0
I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 0:   Y
I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:0) -> (device: 0, name: Tesla K80, pci bus id:8184:00:00.0)
```

ついでに私のMNIST視覚化サンプルの実行。

```
# 依存パッケージのインストール
sudo apt-get install -y python-scipy
pip install tornado futures Pillow

# サンプルダウンロード
cd ~
wget https://github.com/ornew/mnist-visual/releases/download/v3.0.1/mnist-visualize-example_3.0.1.tar.gz

# 展開
tar zxvf mnist-visualize-example_3.0.1.tar.gz
cd ~/mnist-visualize-example_3.0.1/

# サーバ起動
sudo python server.py -p 80
```

ブラウザでインスタンスのパブリックIPアドレスの80番ポートにアクセスして、訓練を開始します。

```
Total time: 275.116462946 [sec]
```

NC6 Standardでは275秒かかりました。参考までに、vCPUx8コアのDS4_V2 Standardだと1733秒かかる。7倍ほど速い。

```
Total time: 1733.28408003 [sec]
```

# TensorBoardの起動

6006番ポートにアクセスしてください。

```
tensorboard --logdir ~/mnist-visualize-example_3.0.1/var
```