Tensorflow with NVIDIA GPU on Docker Container
ホストOS上にNVIDIAのGPUのカーネルドライバをインストールし、Dockerコンテナにcudaとtensorflowをインストールする。
検証環境
- ホストOS: Ubuntu Server 16.04
- GPU: GeForce GTX 1050 Ti
- GPUドライバ: 375.10 (Linux 64-bit)
- DockerコンテナのOS: Ubuntu 16.04
- CUDA Toolkit: 8.0
- cuDNN: v5.1
- Tensorflow: 0.11.0rc2 (GPU版)
ホストOS上にGPUドライバをインストールする
デフォルトでインストールされているグラフィックスドライバ(nouveau)を無効化する
lsmodコマンドでnouveauのカーネルモジュールがロードされているか確認し、 もしロードされていたらmodprobeコマンドでカーネルモジュールをアンロードする
lsmod | grep nouveau
sudo modprobe -r nouveau
次に、nouveauを無効化するために、以下のコマンドを実行し、 /etc/modprobe.d の下に blacklist-nouveau.conf と nouveau-kms.conf を作成する。
sudo tee -a /etc/modprobe.d/blacklist-nouveau.conf << EOF
blacklist nouveau
blacklist lbm-nouveau
options nouveau modeset=0
alias nouveau off
alias lbm-nouveau off
EOF
echo options nouveau modeset=0 | sudo tee -a /etc/modprobe.d/nouveau-kms.conf
update-initramfsを実行し、設定を反映させる。
sudo update-initramfs -u
参考URL
デバイスドライバをインストールする
カーネルドライバのビルドに必要なファイルをインストールする。
sudo apt-get install build-essential linux-headers-generic
NVIDIAのドライバのダウンロードサイト から最新版のドライバのインストーラのダウンロードし、実行する。
chmod 700 ./NVIDIA-Linux-x86_64-375.10.run
sudo ./NVIDIA-Linux-x86_64-375.10.run
Linuxカーネルをアップデートした場合などにドライバのカーネルモジュールだけを再インストールしたい場合には、 --kernel-module-only オプションを使用する。
sudo ./NVIDIA-Linux-x86_64-375.10.run --kernel-module-only
また、--dkmsオプションを使用することで、 Linuxカーネルをアップデートしたときに自動的にドライバのカーネルモジュールを再インストールするように設定することができる。
sudo apt-get install dkms
sudo ./NVIDIA-Linux-x86_64-375.10.run --dkms
/dev/nvidia-uvmを作成する
以下のコマンドを実行すると、/dev/nvidia-uvmという名前のデバイスファイルが作成される。
nvidia-modprobe -u -c=0
再起動後などで/dev/nvidia*が存在しないときの対処方法
ドライバのインストール時に同時にインストールされたnvidia-smiコマンドを実行すると、 /dev/nvidia0, /dev/nvidiactl が作成される。 また、/dev/nvidia-uvmも同時に作成しておく。
nvidia-smi && nvidia-modprobe -u -c=0
Dockerコンテナの起動
NVIDIAのカーネルドライバが作成したデバイスファイル、及び、 ドライバと同時にインストールされたlibcuda*,libnvidia*をコンテナと共有するために、 docker run コマンドに以下のようなオプションを追加する。 なお、ライブラリのバージョン(375.10)の部分は、インストールしたデバイスドライバのバージョンによって変化する。
※ nvidia-docker が提供するコマンドを使えばこのような面倒なオプションをいちいち入力しなくてもすむようである。
sudo docker run \
--device /dev/nvidia0:/dev/nvidia0 \
--device /dev/nvidiactl:/dev/nvidiactl \
--device /dev/nvidia-uvm:/dev/nvidia-uvm \
-v /usr/lib/x86_64-linux-gnu/libcuda.so:/usr/lib/x86_64-linux-gnu/libcuda.so:ro \
-v /usr/lib/x86_64-linux-gnu/libcuda.so.1:/usr/lib/x86_64-linux-gnu/libcuda.so.1:ro \
-v /usr/lib/x86_64-linux-gnu/libcuda.so.375.10:/usr/lib/x86_64-linux-gnu/libcuda.so.375.10:ro \
-v /usr/lib/x86_64-linux-gnu/libnvidia-fatbinaryloader.so.375.10:/usr/lib/x86_64-linux-gnu/libnvidia-fatbinaryloader.so.375.10:ro \
-v /usr/lib/x86_64-linux-gnu/libnvidia-ptxjitcompiler.so.375.10:/usr/lib/x86_64-linux-gnu/libnvidia-ptxjitcompiler.so.375.10:ro \
-t -i --entrypoint=/bin/bash [image name]
Dockerコンテナ内にライブラリをインストールする
cudaとcuDNNのインストール方法は、 NVIDIA公式のdockerコンテナの作成方法 を参考にする。
cudaランタイムのインストール
公式のDockerfile では、aptのリポジトリの追加をマニュアルで行っているが、ここではパッケージを使ってリポジトリの追加を行っている。
また、cudaのランタイムライブラリのうち、tensorflowの実行に必要なものだけをインストールする。
apt-get update
apt-get install -y --no-install-recommends wget
wget -nv http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/cuda-repo-ubuntu1604_8.0.44-1_amd64.deb
dpkg -i cuda-repo-ubuntu1604_8.0.44-1_amd64.deb
rm -f cuda-repo-ubuntu1604_8.0.44-1_amd64.deb
apt-get update
apt-get install -y --no-install-recommends \
cuda-cudart-8-0 \
cuda-cublas-8-0 \
cuda-cufft-8-0 \
cuda-curand-8-0
ln -s cuda-8.0 /usr/local/cuda
cuDNNのインストール
本来ならばcuDNNをダウンロードするには NVIDIA Developer で開発者登録を行う必要があるが、 NVIDIA公式のDockerfile によると、登録なしでダウンロードできてしまうようである。
sha256sumの値はライブラリのバージョンによって変わるので注意。
CUDNN_DOWNLOAD_SUM=a87cb2df2e5e7cc0a05e266734e679ee1a2fadad6f06af82a76ed81a23b102c8 && \
wget -nv http://developer.download.nvidia.com/compute/redist/cudnn/v5.1/cudnn-8.0-linux-x64-v5.1.tgz && \
echo "$CUDNN_DOWNLOAD_SUM cudnn-8.0-linux-x64-v5.1.tgz" | sha256sum -c --strict - && \
tar -xzf cudnn-8.0-linux-x64-v5.1.tgz -C /usr/local --wildcards 'cuda/lib64/libcudnn.so*' && \
rm cudnn-8.0-linux-x64-v5.1.tgz && \
ldconfig
Tensorflowのインストール
この例ではvirtualenvを使用せずにインストールしている。
apt-get install -y --no-install-recommends python python-dev python-pip
pip install https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-0.11.0rc2-cp27-none-linux_x86_64.whl
pythonを起動し、tensorflowをインポートする。
>>> import tensorflow
I tensorflow/stream_executor/dso_loader.cc:111] successfully opened CUDA library libcublas.so locally
I tensorflow/stream_executor/dso_loader.cc:111] successfully opened CUDA library libcudnn.so locally
I tensorflow/stream_executor/dso_loader.cc:111] successfully opened CUDA library libcufft.so locally
I tensorflow/stream_executor/dso_loader.cc:111] successfully opened CUDA library libcuda.so.1 locally
I tensorflow/stream_executor/dso_loader.cc:111] successfully opened CUDA library libcurand.so locally
ライブラリが正しくインストールされていない場合、 "Couldn't open CUDA library libcuda.so.1" などのメッセージが表示される。
続いて、新しいセッションを作成すると、以下のようなログが表示される。
>>> sess = tensorflow.Session()
I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:925] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
I tensorflow/core/common_runtime/gpu/gpu_device.cc:951] Found device 0 with properties:
name: GeForce GTX 1050 Ti
major: 6 minor: 1 memoryClockRate (GHz) 1.392
pciBusID 0000:01:00.0
Total memory: 3.94GiB
Free memory: 3.90GiB
I tensorflow/core/common_runtime/gpu/gpu_device.cc:972] DMA: 0
I tensorflow/core/common_runtime/gpu/gpu_device.cc:982] 0: Y
I tensorflow/core/common_runtime/gpu/gpu_device.cc:1041] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX 1050 Ti, pci bus id: 0000:01:00.0)
Tensorflowのチュートリアルを実行する
Tensorflowのチュートリアルである「Deep MNIST for Experts」を実行してみる。 このプログラムは、4コア8スレッドのPCで実行した場合には1000ステップの学習に2分ほど要するが、 GPUで実行すると16秒程度で学習が完了するので7.5倍程度の高速化が達成できたことになる。
ただし、tensorflowを最初に実行するときだけ、 ライブラリをロードするためか実行時間が長くなってしまう。