AWSのGPUインスタンスでTensorFlowを動かす

  • 110
    Like
  • 0
    Comment
More than 1 year has passed since last update.

以下の環境で試したので、インストール時の作業記録を残しておきます。

なお、TensoFlowはWindowsで動作しません。TensorFlowが採用しているGoogle製のビルドツールBazelが、LinuxとMacのみの対応です。手元にMacかLinuxマシンが無ければ、AWSでUbuntu環境を用意するのが簡単だと思います。

Mac OS X

CPUのみで動作するパッケージをインストールしました。最もお手軽です。
スペック
- MacBook Pro (Retina, 15-inch, Mid 2014)
- CPU: 2.2 GHz Intel Core i7
- メモリ: 16 GB 1600 MHz DDR3

公式ドキュメント通りpipでパッケージを導入。

$ sudo easy_install --upgrade six
$ sudo pip install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.6.0-py2-none-any.whl

テストとして、CIFAR-10 datasetを学習してみます。

$ git clone https://github.com/tensorflow/tensorflow.git
$ cd tensorflow/tensorflow/models/image/cifar10/
$ python cifar10_train.py

実行すると、データセットがダウンロードされ学習が開始されます。
途中の経過がターミナルに出力されるので、学習が安定した100stepごろを見ると、1つのバッチ学習に0.540秒かかりました。

2015-12-31 15:00:08.397460: step 100, loss = 4.49 (237.0 examples/sec; 0.540 sec/batch)

Amazon web service(AWS)

AWS EC2のG2インスタンスを使用して、環境構築します。

注意: TensorFlowはCuda compute capability 3.5以下の場合は特別な対応が必要です。
Cuda compute capabilityはGPUのアーキテクチャのようなもので、GPUによって決まっています。AWS G2インスタンスに搭載されているGRID K520はCuda compute capability3.0なので、そのままではTensorFlowのGPU計算を実行できません。ここで3.0への対応が議論されています。

料金の安かったオレゴン(米国)のインスタンスを使用しました。
以下の料金や情報は2015年12月30日時点の情報です。

モデル GPU vCPU メモリ(GiB) SSDストレージ(GB) 料金 - オレゴン(米国)
g2.2xlarge GRID K520 x 1 8 15 1 x 60 $0.65 /1 時間
g2.8xlarge GRID K520 x 4 32 60 2 x 120 $2.6 /1 時間

インストール

Linuxインスタンスへの接続はここを参照。
こちらを参考に進めました。
まずは必要なソフトウェアをインストール。

$ sudo apt-get update
$ sudo apt-get upgrade -y # “install package maintainers version”を選択
$ sudo apt-get install -y build-essential python-pip python-dev git python-numpy swig python-dev default-jdk zip zlib1g-dev ipython

NVIDIAドライバとの衝突をさけるため、Nouveauのブラックリストを追加。

$ echo -e "blacklist nouveau\nblacklist lbm-nouveau\noptions nouveau modeset=0\nalias nouveau off\nalias lbm-nouveau off\n" | sudo tee /etc/modprobe.d/blacklist-nouveau.conf
$ echo options nouveau modeset=0 | sudo tee -a /etc/modprobe.d/nouveau-kms.conf
$ sudo update-initramfs -u
$ sudo reboot

リブートされるので、再度ログインして、以下を実行。ここはなんで必要なのか理解していない。

$ sudo apt-get install -y linux-image-extra-virtual
$ sudo reboot
# Install latest Linux headers
$ sudo apt-get install -y linux-source linux-headers-`uname -r`

次に、CUDAとcuDNNをインストールします。公式ドキュメントのここも参考に作業を進めます。なお、インストールするバージョンは必ず下記のものである必要があります。
- CUDA Toolkit 7.0
- cuDNN Toolkit 6.5

まずは、CUDAをインストール。

# Install CUDA 7.0
$ wget http://developer.download.nvidia.com/compute/cuda/7_0/Prod/local_installers/cuda_7.0.28_linux.run
chmod +x cuda_7.0.28_linux.run
$ ./cuda_7.0.28_linux.run -extract=`pwd`/nvidia_installers
$ cd nvidia_installers
$ sudo ./NVIDIA-Linux-x86_64-346.46.run
$ sudo modprobe nvidia
$ sudo ./cuda-linux64-rel-7.0.28-19326674.run

次にcuDNNをインストールします。cuDNNはDeep neural networkの学習をGPUで高速化することに特化したライブラリです。この記事が参考になります。cuDNNを入手するには、NVIDIAのデベロッパーアカウントへの登録が必要です。wgetで入手できないので、一度ローカル環境でここからダウンロードします。
ダウンロードしたファイルをローカルからSCPで転送します。
以下はLinuxからの転送例。xxxxx.amazonaws.comはAMIのパブリックDNS。

# ローカルで作業
# SCPでAMIへ転送
$ scp -i /path/my-key-pair.pem cudnn-6.5-linux-x64-v2.tgz ubuntu@xxxxx.amazonaws.com:~

転送が終わったら解凍し、cudaのディレクトリにコピーする。

# AMIで作業
$ cd
$ tar -xzf cudnn-6.5-linux-x64-v2.tgz
$ sudo cp cudnn-6.5-linux-x64-v2/libcudnn* /usr/local/cuda/lib64
$ sudo cp cudnn-6.5-linux-x64-v2/cudnn.h /usr/local/cuda/include/

パスを通します。

$ vi .bashrc # viやnanoなどで以下の2行を.bashrcに追加
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/cuda/lib64"
export CUDA_HOME=/usr/local/cuda
$ source .bashrc # .bashrcの設定を反映

AMIで利用出来るディスク領域はあまり大きくありません。この後、Bazelでビルドする際や、学習用データをダウンロードする場合に、十分に大きなディスク容量が必要になります。
インスタンス作成時に割り当てられるエフェメラルストレージ(/mnt/以下)には十分なディスク領域があるので、シンボリックリンクを作っておきます。
なお、もう使用しないnvidia_installersやcudnn-6.5-linux-x64-v2.tgzは削除しても構いません。

$ df
Filesystem     1K-blocks    Used Available Use% Mounted on
udev             7687184      12   7687172   1% /dev
tmpfs            1540096     344   1539752   1% /run
/dev/xvda1       8115168 5874536   1805356  77% /
none                   4       0         4   0% /sys/fs/cgroup
none                5120       0      5120   0% /run/lock
none             7700472       0   7700472   0% /run/shm
none              102400       0    102400   0% /run/user
/dev/xvdb       66946696   53144  63486192   1% /mnt
# /mnt/tmp/へのシンボリックリンクを作成
$ sudo mkdir /mnt/tmp
$ sudo chmod 777 /mnt/tmp
$ sudo rm -rf /tmp
$ sudo ln -s /mnt/tmp /tmp

注意: インスタンス停止時に、/mnt/以下の内容は全て削除されます。AMIイメージに残す必要があるデータは/tmp/に保存しないでください。
後述する公開AMIにはインスタンスの作成時やリスタート時に、エフェメラルストレージにtmpを作成するシェルスクリプト(create_tmp_on_ephemeral_storage.sh)を用意しました。

ビルドツールであるBazelをインストールします。

$ cd /mnt/tmp
$ git clone https://github.com/bazelbuild/bazel.git
$ cd bazel
$ git checkout tags/0.1.0
$ ./compile.sh
$ sudo cp output/bazel /usr/bin

次にTensorFlowをインストールします。
"./configure"は、ここで議論されている通り、"TF_UNOFFICIAL_SETTING=1 ./configure"のようにオプションをつけて実行します。これにより、Cuda compute capability 3.0にも対応可能なアンオフィシャル設定になります。

$ cd /mnt/tmp
$ git clone --recurse-submodules https://github.com/tensorflow/tensorflow
$ cd tensorflow
$ TF_UNOFFICIAL_SETTING=1 ./configure

コンフィグレーション中に、以下のような質問があります。デフォルトでは、Cuda compute capability 3.5と5.2のみの対応ですので、以下のように3.0を追加します。

Please specify a list of comma-separated Cuda compute capabilities you want to build with.
You can find the compute capability of your device at: https://developer.nvidia.com/cuda-gpus.
Please note that each additional compute capability significantly increases your build time and binary size.
[Default is: "3.5,5.2"]: 3.0,3.5,5.2   #3.0を追加

TensorFlowをビルド。

$ bazel build -c opt --config=cuda //tensorflow/cc:tutorials_example_trainer

次にTensorFlowのPythonパッケージをビルド、インストールします。
"/tmp/tensorflow_pkg/tensorflow-0.6.0-cp27-none-linux_x86_64.whl"の部分は、実際に生成されたバージョンのファイル名に合わせてください。

$ bazel build -c opt --config=cuda //tensorflow/tools/pip_package:build_pip_package
$ bazel-bin/tensorflow/tools/pip_package/build_pip_package /tmp/tensorflow_pkg
$ sudo pip install /tmp/tensorflow_pkg/tensorflow-0.6.0-cp27-none-linux_x86_64.whl

これで、インストール完了です。

テスト

まずはg2.2xlargeインスタンスで試します。

$ cd tensorflow/models/image/cifar10/
$ python cifar10_multi_gpu_train.py

結果は以下のとおり。

2016-01-01 09:08:55.345446: step 100, loss = 4.49 (285.9 examples/sec; 0.448 sec/batch)

さらに、g2.8xlargeで試します。
以下のように、cifar10_multi_gpu_train.pyの63行目あたりでGPUの数を4に設定します。これを行わない場合、見かけはGPUを4つ使用しますが、並列化が正常に行われないためか高速化されません。

tf.app.flags.DEFINE_integer('num_gpus', 4,
                            """How many GPUs to use.""")

実行結果。かなり高速されました。

2016-01-01 09:33:24.481037: step 100, loss = 4.49 (718.2 examples/sec; 0.178 sec/batch)

コミュニティAMI

AWS オレゴン(米国)のコミュニティAMIに今回作成したイメージを公開しています。
ubuntu14.04_tensorflow0.6.0_gpu - ami-69475f08
インスタンスの作成後、create_tmp_on_ephemeral_storage.shを実行して、エフェメラルストレージ上の/tmpディレクトリを作成してください。

$ ./create_tmp_on_ephemeral_storage.sh