CUBE SUGAR CONTAINER

技術系のこと書きます。

Ubuntu 18.04 LTS で NVIDIA-Docker2 を使ってみる

ニューラルネットワークに代表される機械学習の一部のアルゴリズムでは、学習する上で大量の行列演算を必要とする。 そこで、行列演算を高速化する目的で GPGPU を利用することが一般的になっている。 そして、この分野では機械学習のライブラリが GPGPU の API として NVIDIA の CUDA を使うのがほとんどデファクトになっている。

また、一般的に機械学習のライブラリはサポートしている CUDA のバージョンに制約を設けている。 つまり、ライブラリのバージョンが新しくなると古い CUDA のサポートは落とされて、少しずつ新しいものに移っていく。 ようするに、利用するライブラリのバージョンを上げるときには、同時に CUDA のバージョンも上げる必要に迫られる。 しかしながら、既に動いている CUDA のバージョンをアップデートするというのは、結構面倒な作業ともいえる。

そこで活躍するのが今回利用する NVIDIA-Docker2 となる。 NVIDIA-Docker2 を使うと Docker のコンテナから CUDA 経由で GPU が利用できるようになる。 また、ホストには NVIDIA のグラフィックスドライバしかインストールする必要がない。 CUDA に関しては Docker のコンテナ内にインストールされている。 つまり、ライブラリをアップデートするときは利用するコンテナを切り替えるだけで良い。

ただし、注意点として CUDA はグラフィックスドライバのバージョンにも制約がある。 そこについてはホスト側の作業が必要になってしまうが、CUDA と一緒に入れ替えるよりはぐっと楽ができると思う。

ところで、NVIDIA-Docker は以前は 1.x 系が使われていた。 1.x 系の使い方に関しては、このブログでも紹介したことがある。

blog.amedama.jp

1.x と 2.x 系の違いは、コンテナを管理する上で利用するコマンドが異なるところ。 1.x 系では docker コマンドをラップした nvidia-docker というコマンドが提供されていた。 それに対して 2.x 系では docker コマンドをそのまま利用できる。 その代わりとしてコンテナの実行時に --runtime=nvidia というオプションをつけることになる。

今回使った環境は次の通り。

$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.2 LTS"
$ uname -r
4.15.0-1032-gcp
$ nvidia-smi
Sun May 26 21:31:15 2019       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 430.14       Driver Version: 430.14       CUDA Version: 10.2     |
|-------------------------------+----------------------+----------------------+
| 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:04.0 Off |                    0 |
| N/A   35C    P0    72W / 149W |      0MiB / 11441MiB |    100%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

ここからは NVIDIA-Docker2 を利用するまでの手順を説明していく。

NVIDIA Graphics Driver をインストールする

まずはホストに NVIDIA の提供するグラフィックスドライバをインストールする。 なお、CUDA はバージョンによってサポートしているグラフィックスドライバのバージョンが異なる。 そのため、利用したい CUDA のバージョンに合わせてインストールするバージョンを選ばなければいけない。

CUDA がサポートしているグラフィックスドライバのバージョンについては以下に対応表がある。

github.com

なお、GPU のアーキテクチャにも利用できるグラフィックスドライバのバージョンは制約を受ける。 古い GPU を利用している場合には注意しよう。 GPU のアーキテクチャは Compute Capability という名称でも呼ばれており、以下のページで確認できる。

developer.nvidia.com

どの CUDA を利用するかは、利用したい機械学習のライブラリに依存する。 例えば TensorFlow が動作を確認している CUDA のバージョンについては以下に対応表がある。

www.tensorflow.org

今回は、現時点で最新の CUDA 10.1 を利用することを想定してドライバのバージョンに 418.39 以上のものを選んでみる。 利用する GPU は Tesla K80 なので Compute Capability は 3.7 となり、こちらも問題ない。

まずはグラフィックスドライバのリポジトリを追加する。

$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt update

これでパッケージシステムからインストールできるグラフィックスドライバが増える。

$ apt-cache search nvidia-driver
nvidia-384 - Transitional package for nvidia-driver-390
nvidia-384-dev - Transitional package for nvidia-driver-390
...(snip)...
xserver-xorg-video-nvidia-415 - NVIDIA binary Xorg driver
xserver-xorg-video-nvidia-418 - NVIDIA binary Xorg driver
xserver-xorg-video-nvidia-430 - NVIDIA binary Xorg driver

使っている GPU で利用できるドライバについては ubuntu-drivers-common をインストールして確認すると良い。

$ sudo apt-get -y install ubuntu-drivers-common

インストールできるドライバの一覧が ubuntu-drivers devices コマンドで確認できる。

$ ubuntu-drivers devices
== /sys/devices/pci0000:00/0000:00:04.0 ==
modalias : pci:v000010DEd0000102Dsv000010DEsd0000106Cbc03sc02i00
vendor   : NVIDIA Corporation
model    : GK210GL [Tesla K80]
manual_install: True
driver   : nvidia-driver-418 - third-party free
driver   : nvidia-driver-390 - distro non-free
driver   : nvidia-driver-396 - third-party free
driver   : nvidia-driver-410 - third-party free
driver   : nvidia-driver-415 - third-party free
driver   : nvidia-driver-430 - third-party free recommended
driver   : xserver-xorg-video-nouveau - distro free builtin

推奨 (recommended) になっているドライバに関しては以下のようにインストールできる。

$ sudo ubuntu-drivers autoinstall

もちろん、バージョンを指定してインストールするときは apt-get を使えば良い。 今回であれば 418.39 以上の条件を満たす 430 をインストールしておこう。

$ sudo apt-get -y install nvidia-driver-430

Docker CE (Community Edition) をインストールする

続いて Docker CE をインストールする。

もし、既にインストールされている Docker 関連のパッケージがあればアンインストールしておこう。

$ sudo apt-get remove docker docker-engine docker.io containerd runc

続いて、Docker CE のリポジトリを登録していく。 まずは必要なパッケージ類をインストールする。

$ sudo apt-get -y install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common

続いて GPG 鍵をインストールする。

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

そしてリポジトリを追加する。

$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

パッケージインデックスを更新したら Docker CE 関連のパッケージをインストールする。

$ sudo apt-get update
$ sudo apt-get -y install docker-ce docker-ce-cli containerd.io

インストールできたら docker version コマンドでクライアントとサーバが正常に稼働していることを確認しておこう。

$ sudo docker version
Client:
 Version:           18.09.6
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        481bc77
 Built:             Sat May  4 02:35:57 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.6
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       481bc77
  Built:            Sat May  4 01:59:36 2019
  OS/Arch:          linux/amd64
  Experimental:     false

また、動作確認用のコンテナを実行しておく。

$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete 
Digest: sha256:0e11c388b664df8a27a901dce21eb89f11d8292f7fca1b3e3c4321bf7897bffe
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

上記のようなメッセージが表示されれば良い。

NVIDIA-Docker2 をインストールする

続いては今回のメインとなる NVIDIA-Docker2 をインストールする。

まずは GPG 鍵をインストールしておく。

$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -

続いて NVIDIA-Docker2 のリポジトリを登録する。

$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
$ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | \
  sudo tee /etc/apt/sources.list.d/nvidia-docker.list

パッケージインデックスを更新したら NVIDIA-Docker2 をインストールする。

$ sudo apt-get update
$ sudo apt-get -y install nvidia-docker2

インストールできたら Docker のデーモンを再起動する。

$ sudo pkill -SIGHUP dockerd

これで NVIDIA-Docker2 を利用する準備ができた。

Docker コンテナを起動する

それではコンテナを起動してみよう。 NVIDIA-Docker2 を利用するときは、基本的には NVIDIA がリリースしているコンテナイメージを使うことになる。 利用できるイメージは以下で確認できる。

hub.docker.com

今回は CUDA 10.1 と cuDNN 7 をサポートしたコンテナとして nvidia/cuda:10.1-cudnn7-devel を使ってみよう。

次のようにしてコンテナを起動する。 ポイントは --runtime=nvidia を指定しているところで、これでコンテナから GPU を利用できるようになる。

$ sudo docker run --runtime=nvidia --rm -it nvidia/cuda:10.1-cudnn7-devel /bin/bash

コンテナ内で、GPU の状態を確認する nvidia-smi コマンドを実行してみよう。

root@ec7a7325a727:/# nvidia-smi
Sun May 26 20:48:28 2019       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 430.14       Driver Version: 430.14       CUDA Version: 10.2     |
|-------------------------------+----------------------+----------------------+
| 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:04.0 Off |                    0 |
| N/A   33C    P0    81W / 149W |      0MiB / 11441MiB |    100%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

上記のように、GPU の状態が表示されれば上手くいっている。 はて、CUDA Version が 10.2 になっているのはどうしてだろうか。

参考

今回は、次のようにして Google Compute Engine で環境を用意した。

$ gcloud compute instances create gce-gpu-k80 \
  --preemptible \
  --zone us-central1-a \
  --machine-type n1-standard-2 \
  --accelerator type=nvidia-tesla-k80,count=1 \
  --maintenance-policy TERMINATE \
  --restart-on-failure \
  --image-project ubuntu-os-cloud \
  --image-family ubuntu-1804-lts

blog.amedama.jp

いじょう。