WonderPlanet Tech Blog

アドバンストテクノロジー部やCTO室のメンバーを中心に最新の技術情報を発信しています。

nvidia-docker2を使ってみる

こんにちは。アドバンストテクノロジー部のR&Dチーム所属岩原です。
今回は、nvidia-dockerをdocker-composeから使う - WonderPlanet Tech Blogの記事が、
nvidia-dockerのversion2.0の登場によって過去のものになってしまったので、対応した記事を新たに書きました。

検証環境

  • AWS(p2.xlarge)
  • Ubuntu 16.04 LTS

CUDAやドライバー,Dockerのインストールなど

nvidia-dockerをdocker-composeから使う - WonderPlanet Tech Blogの各項目を参照してください。
バージョンなどは上がっているかと思うので、そこは最新に合わせてください。
念のため、各項目のインストールページを載せておきます。

また、前回書き忘れていたのですが、dockerグループにユーザーを所属させると、
dockerの実行にsudoが必要なくなるので、やっておくと良いかと思います。
手順は以下のとおりです。

  • 現在のユーザーをdockerグループに所属させる
sudo gpasswd -a $USER docker

docker-compose対応

add support for runtime option in service definitions by cuckoohello · Pull Request #5405 · docker/composeによると、
docker-composeの正式対応(runtime指定)は1.19ぐらいになりそうです。
したがって、それまではdocker deamonのデフォルトのコンテナランタイムをnvidia-dockerに変える必要があります。

兎にも角にも、最新のdocker-composeを入れましょう。
前回と同じ手順ですが、バージョン変わってるのでついでにコマンドを載せておきます。
現在(2017/12/13)の最新安定版は1.17のようです。

sudo curl -L https://github.com/docker/compose/releases/download/1.17.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version

でバージョン情報が出力されればOKです。

nvidia-dockerのインストール

前準備として、GPGキーの登録やリポジトリの追加などを行います。

curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/ubuntu16.04/amd64/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update

上記が正常終了したら、次はnvidia-docker2のインストールです。

sudo apt-get install nvidia-docker2

インストールが完了したら、docker daemonの設定をリロードさせます。

sudo pkill -SIGHUP dockerd

問題なければ動作確認してみましょう。

docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi

nvidia-smiの結果が出力されればOKです。

出力例(AWSのp2.xlargeの場合)

Wed Dec 13 05:28:55 2017
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 387.26                 Driver Version: 387.26                    |
|-------------------------------+----------------------+----------------------+
| 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  | 00000000:00:1E.0 Off |                    0 |
| N/A   50C    P0    57W / 149W |      0MiB / 11439MiB |     99%      Default |
+-------------------------------+----------------------+----------------------+

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

docker-composeで使う(v1.19.0未満の場合)

dockerdのdefault runtimeをnvidiaに設定します。
nvidia-dockerのインストール直後は未設定なので、runcと言うものDockerデフォルトのものになっています。

sudo vi /etc/docker/daemon.json

でDocker daemonの設定ファイルを開き、"default-runtime": "nvidia",を追加します。
追加後のファイルの内容は以下の通りになるかと思います。

{
    "default-runtime": "nvidia", 
    "runtimes": {
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}

これで、デフォルトで使われるdockerコンテナのランタイムがruncからnvidiaに変わります。
一旦、この状態で再起動かけると設定が適用されます。

この状態で、以下をdocker-compose.ymlとして保存し、

version: '3'
services:
  nvidia:
    image: nvidia/cuda
    command: nvidia-smi

docker-compose upしてnvidia-smiの結果が出力されればOKです。

出力例(AWS のp2.xlargeの場合)

Creating network "ubuntu_default" with the default driver
Creating ubuntu_nvidia_1 ...
Creating ubuntu_nvidia_1 ... done
Attaching to ubuntu_nvidia_1
nvidia_1  | Wed Dec 13 05:13:22 2017
nvidia_1  | +-----------------------------------------------------------------------------+
nvidia_1  | | NVIDIA-SMI 387.26                 Driver Version: 387.26                    |
nvidia_1  | |-------------------------------+----------------------+----------------------+
nvidia_1  | | GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
nvidia_1  | | Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
nvidia_1  | |===============================+======================+======================|
nvidia_1  | |   0  Tesla K80           Off  | 00000000:00:1E.0 Off |                    0 |
nvidia_1  | | N/A   49C    P0    57W / 149W |      0MiB / 11439MiB |     99%      Default |
nvidia_1  | +-------------------------------+----------------------+----------------------+
nvidia_1  |
nvidia_1  | +-----------------------------------------------------------------------------+
nvidia_1  | | Processes:                                                       GPU Memory |
nvidia_1  | |  GPU       PID   Type   Process name                             Usage      |
nvidia_1  | |=============================================================================|
nvidia_1  | |  No running processes found                                                 |
nvidia_1  | +-----------------------------------------------------------------------------+

volumesとかdevicesとかは必要なくなりましたが、Docker daemonの設定を弄らないといけないのは面倒です。
また、コンテナごとにコンテナランタイムを変えられないのはちょっと不便ですね。
そこら辺はdocker-composeのバージョンアップを待ちましょう。

docker-composeで使う(v1.19.0以上の場合)

まだリリースされていません(2017/12/13時点では1.18rc2が最新)が、前述のプルリクエストを見る限り、
以下のようにdocker-compose.ymlにruntime: nvidiaを追記するだけです。

version: '3'
services:
  nvidia:
    image: nvidia/cuda
    runtime: nvidia
    command: nvidia-smi

簡単ですね。 Docker daemonの設定を弄る必要はありません。
コンテナごとにruntimeを変えることも可能となるでしょう。

実践

nvidia-dockerをdocker-composeから使う - WonderPlanet Tech Blogでやったのと同じ、
Kerasのサンプルの1つである、mnist + CNNを動かすDockerイメージを作ります。
詳細は元記事を参照してください。

元記事と違う点として、docker-compose.ymlからvolume周りの設定が全て消えました。

version: "3"
services:
    tensorflow_keras:
        build:
            context: ./tensorflow_keras
            dockerfile: Dockerfile

上記以外は元記事と一緒です。

結果

tensorflow_keras_1  | 2017-12-13 05:55:43.084455: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:0) -> (device: 0, name: Tesla K80, pci bus id: 0000:00:1e.0)

きちんとGPUが認識されているようです。

複数GPUは認識されるのか

インスタンスタイプをp2.8xlarge(8GPU)に上げてやってみました。 これで複数GPUが認識されるのかどうか確かめてみます。

tensorflow_keras_1  | 2017-12-13 06:09:22.743220: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:0) -> (device: 0, name: Tesla K80, pci bus id: 0000:00:17.0)
tensorflow_keras_1  | 2017-12-13 06:09:22.743232: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:1) -> (device: 1, name: Tesla K80, pci bus id: 0000:00:18.0)
tensorflow_keras_1  | 2017-12-13 06:09:22.743238: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:2) -> (device: 2, name: Tesla K80, pci bus id: 0000:00:19.0)
tensorflow_keras_1  | 2017-12-13 06:09:22.743243: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:3) -> (device: 3, name: Tesla K80, pci bus id: 0000:00:1a.0)
tensorflow_keras_1  | 2017-12-13 06:09:22.743252: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:4) -> (device: 4, name: Tesla K80, pci bus id: 0000:00:1b.0)
tensorflow_keras_1  | 2017-12-13 06:09:22.743257: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:5) -> (device: 5, name: Tesla K80, pci bus id: 0000:00:1c.0)
tensorflow_keras_1  | 2017-12-13 06:09:22.743262: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:6) -> (device: 6, name: Tesla K80, pci bus id: 0000:00:1d.0)
tensorflow_keras_1  | 2017-12-13 06:09:22.743270: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:7) -> (device: 7, name: Tesla K80, pci bus id: 0000:00:1e.0)

全て認識されています。

使用するGPUを指定する方法

環境変数NVIDIA_VISIBLE_DEVICESを使います。 以下のように、NVIDIA_VISIBLE_DEVICESの値として0,1,2を指定すると、 0番目、1番目、2番目のGPUを指定したことになります。 他にもallnoneなども指定できます。 詳細はNVIDIA/nvidia-container-runtime: NVIDIA container runtimeで確認してください。

version: "3"
services:
    tensorflow_keras:
        build:
            context: ./tensorflow_keras
            dockerfile: Dockerfile
        environment:
            - NVIDIA_VISIBLE_DEVICES=0,1,2

実行してみると、

tensorflow_keras_1  | 2017-12-13 06:19:44.448613: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:0) -> (device: 0, name: Tesla K80, pci bus id: 0000:00:17.0)
tensorflow_keras_1  | 2017-12-13 06:19:44.448624: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:1) -> (device: 1, name: Tesla K80, pci bus id: 0000:00:18.0)
tensorflow_keras_1  | 2017-12-13 06:19:44.448630: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1045] Creating TensorFlow device (/gpu:2) -> (device: 2, name: Tesla K80, pci bus id: 0000:00:19.0)

のように3つ使用されているのが確認できます。

結論

docker-composeは1.19が出るまで待つと良いです。
現状では、docker-composeを使用するとnvidiaのランタイムかDockerのランタイムどちらかしか使用できません。
ただし、volumeとか作る必要はなくなったので、そこは良くなった点ですね。

参考