Ubuntu18.04: CUDA+Docker セットアップ

Takami Torao Ubuntu 18.04 CUDA 9.0 GTX-1050TI #ubuntu #nvidia #cuda
  • このエントリーをはてなブックマークに追加

概要

Ubuntu 18.04 (bionic beaver) の Docker コンテナ上からホストに設置されている GPU を使用するための環境構築手順を記述する。

機械学習をはじめとする昨今の計算科学は非常に速い過渡期にあり目的によって様々なモデルを試す事のできる環境を必要としている。Fig 1 に示す NVIDIA Docker は各コンテナがホストの GPU とドライバを共用し、コンテナごとに異なる CUDA Toolkit や cuDNN、OS、プログラミング言語を利用できる構成となる。つまり機械学習のフレームワーク、ライブラリやミドルウェア、プログラミング言語を実行環境と疎結合にして環境ごとの構築/共存/問題切り分けや GPU の共有を容易にする利点がある。

この手順の具体的なゴールは Docker コンテナ上で TensorFlow を使った開発や Jupyter Notebook など CUDA を使用するアプリケーションを利用できるようにすることである。大まかな手順は以下のように示される。

  1. まず Ubuntu が標準で NVIDIA 製 GPU カードに使用する OSS の Nouveau ドライバを無効化し NVIDIA 製の CUDA ドライバを導入する。
  2. 次に Docker CE と NVIDIA Container Runtime for Docker 2.0 を導入し Docker コンテナ上の CUDA からホストの GPU を利用できるようにする。
  3. 最後に dockerd をリモートからも利用できるように構成する。
Fig 1. NVIDIA Container Runtime for Docker

この操作によって Ubuntu のパッケージ管理で標準的に使用されているグラフィックドライバや docker.io が削除されブートイメージが再構築される。つまり Ubuntu 18.04 の標準的な環境とは少し異なる環境となることから、システムは以後のライブラリインストールやバージョンアップに注意を払う必要がある。

Nouveau ドライバの無効化

Ubuntu の標準的なインストールでは NVIDIA GPU カード向けに nouveau と呼ばれるオープンソースのドライバが導入される。しかし nouveau がカーネルにロードされている間は NVIDIA ドライバがロードできず CUDA が使用できないため nouveau を無効化する必要がある。以下 FAQ より引用:

nouveau はカーネルで実行される。カーネルがフレームバッファコンソールを表示するために使用しているため、X が実行されていなくても nouveau を無効化することは難しい。nouveau が使用されている限りカーネルモジュールをアンロードすることができず NVIDIA カーネルモジュールのロードが妨げられる。

nouveau モジュールの無効化を行うに先立ってまずシステムで nouveau がロードされていることを確認する。

torao@cobalt:~$ lsmod | grep nouveau
nouveau              1716224  1
mxm_wmi                16384  1 nouveau
wmi                    24576  2 mxm_wmi,nouveau
video                  40960  1 nouveau
i2c_algo_bit           16384  1 nouveau
ttm                   106496  1 nouveau
drm_kms_helper        167936  1 nouveau
drm                   401408  4 nouveau,ttm,drm_kms_helper

nouveau は (やっかいなことに) Ubuntu 起動時に読み込まれるブートイメージに含まれていることから、これを無効化するにはシステムのモジュールローダー構成ディレクトリに nouveau のロードを無効化する設定ファイルを追加しブートイメージを再構築する必要がある。

torao@cobalt:~$ cat /etc/modprobe.d/disable-nouveau.conf
blacklist nouveau
options nouveau modeset=0

上記の設定ファイルを新規に作成したら update-initramfs を使用してブートイメージを再構築する。

torao@cobalt:~$ sudo update-initramfs -u
update-initramfs: Generating /boot/initrd.img-4.15.0-23-generic

これでシステムを再起動すれば nouveau が無効化された状態で起動する。まず最初に以前より解像度の低い起動画面になったことに気づくだろう。

torao@cobalt:~$ sudo shutdown -r now

前述のコマンドを入力して何も表示されていなければ nouveau がカーネルにロードされていないことが確認できる。

torao@cobalt:~$ lsmod | grep nouveau
torao@cobalt:~$

カーネルのバージョンアップでブートイメージが更新されたときは再びこの操作を行う必要があるかもしれない (未確認)。

NVIDIA ドライバのインストール

実行環境の Ubuntu 18.04 が CUDA 対応の NVIDIA GPU を認識しているかを確認する。

torao@cobalt:~$ lspci | grep -i nvidia
01:00.0 VGA compatible controller: NVIDIA Corporation GP107 [GeForce GTX 1050 Ti] (rev a1)
01:00.1 Audio device: NVIDIA Corporation GP107GL High Definition Audio Controller (rev a1)

対応カードが設置されているにも拘らず lspci で表示されない場合は /sbin/update-pciids を実行して PCI ハードウェアデータベースを更新する必要がある。

ここで表示された GPU カードのモデルが CUDA GPUs に掲載されていれば CUDA を利用することができる。例えば現時点で最新の CUDA 9.x の Minimum Compute Capability は 3.0 であることから Compute Capability 6.1 の GeForce GTX 1050 Ti は CUDA 9.x を利用できる。

Ubuntu 16.04 (xenial xerus) を使用している場合は apt を使用して公式リポジトリや PPA からインストールする方法が手軽だろう (Ubuntu 16.04 LTSに NVIDIA 製ドライバーをインストールする3つの方法など参照)。ただし 2018/07 時点では 18.04 用のリポジトリに GTX 1050 Ti で利用できる NVIDIA ドライバが存在しないため手動でインストールを行う。

最新ドライバのインストールは NVIDIA ドライバダウンロードで適切な環境を選択してダウンロードしたインストーラーを使用して行う。例えば Ubuntu 18.04 + GTX 1050 Ti の組み合わせは LINUX X64 (AMD64/EM64T) DISPLAY DRIVER が該当する。

インストール時にはカーネルインターフェースのコンパイルが実行されるため Pre-install Actions を参考にコンパイラやカーネルソースをインストールする。

torao@cobalt:~$ sudo apt-get install -y linux-headers-$(uname -r) gcc make
...

次に NVIDIA ドライバダウンロードからダウンロードしたインストーラー NVIDIA-Linux-x86_64-xxx.xx.run を起動する。ここでは現時点での最新版 390.77 を使用している。

torao@cobalt:~$ ls
NVIDIA-Linux-x86_64-390.77.run

torao@cobalt:~$ sudo sh NVIDIA-Linux-x86_64-390.77.run
Verifying archive integrity... OK
Uncompressing NVIDIA Accelerated Graphics Driver for Linux-x86_64 390.77..............................

インストールが完了したら NVIDIA ドライバのユーティリティが使用できることを確認する。

torao@cobalt:~$ nvidia-smi
Sat Jul 21 17:22:09 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.77                 Driver Version: 390.77                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 105...  Off  | 00000000:01:00.0 Off |                  N/A |
|  0%   42C    P0    N/A /  75W |      0MiB /  4039MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

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

ここでは Docker ホストの構成を最小限にするため NVIDIA CUDA Toolkit は導入していない事に注意。

NVIDA Docker 2.0 インストール

NVIDIA Docker 2.0 は Docker CE のコンテナランタイムとして動作する。しかし Ubuntu の公式リポジトリから導入できる Docker は Ubuntu がカスタマイズした docker.io であるため Get Docker CE for Ubuntu を参考にして Docker CE を導入する。

docker.iodocker-engine がインストール済みの場合はアンインストールする必要がある。また古い nvidia-docker 1.0 がインストールされている場合はすべての GPU コンテナを削除する必要がある (Removing nvidia-docker 1.0 参照)

torao@cobalt:~$ sudo apt-get remove docker docker-engine docker.io

torao@cobalt:~$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common

torao@cobalt:~$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
OK

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

torao@cobalt:~$ sudo apt-get update

torao@cobalt:~$ sudo apt-get install docker-ce

もし、後述する nvidia-docker2 のインストール時に "The following packages have unmet dependencies: nvidia-docker2: Depends: docker-ce (= 18.06.0~ce~3-0~ubuntu) but it is not installable" というエラーが発生する場合は、システムに導入されている Docker CE のバージョンに互換性がない事を示している。表示されたバージョンを docker-ce に明示的に指定する必要がある。

torao@cobalt:~$ sudo apt-get install docker-ce=18.06.0~ce~3-0~ubuntu

Docker CE をインストールしたら nvidia-docker2 のパッケージリポジトリを追加する。

torao@cobalt:~$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
OK

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

torao@cobalt:~$ sudo apt-get update

nvidia-docker2 をインストールする。

torao@cobalt:~$ sudo apt-get install -y nvidia-docker2

dockerd を再起動する。

torao@cobalt:~$ sudo pkill -SIGHUP dockerd

Docker コンテナから nvidia-smi のようなユーティリティが利用できれば動作確認は完了。

torao@cobalt:~$ sudo docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi
Unable to find image 'nvidia/cuda:latest' locally
latest: Pulling from nvidia/cuda
3620e2d282dc: Downloading [=================>                                 ]  15.42MB/43.19MB
ef22f5e4b3b2: Download complete
...
Sat Jul 21 18:44:35 2018
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.77                 Driver Version: 390.77                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 105...  Off  | 00000000:01:00.0 Off |                  N/A |
|  0%   38C    P0    N/A /  75W |      0MiB /  4039MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

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

torao@cobalt:~$ sudo docker run --runtime=nvidia --rm nvidia/cuda nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2017 NVIDIA Corporation
Built on Fri_Sep__1_21:08:03_CDT_2017
Cuda compilation tools, release 9.0, V9.0.176

Docker コンテナで CUDA 9.0 が動作し GTX 1050 Ti が認識できていることを確認した。

Docker のリモート実行

Docker コンテナの起動や停止のような操作を Windows などのリモート端末から行うことができるように構成する (この章の内容は CUDA とは関係ない)。

まず Docker の起動オプションを変更して dockerd を再起動する。以下の構成ではポート 2376 で接続するように構成している。よりセキュアにクライアント認証を用いたい場合は Docker デーモンのソケットを守るを参照。

torao@cobalt:~$ sudo vim /lib/systemd/system/docker.service

# ExecStart=/usr/bin/dockerd -H fd://
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2376 -H fd://

torao@cobalt:~$ sudo systemctl daemon-reload
torao@cobalt:~$ sudo systemctl restart docker
torao@cobalt:~$ netstat -an | grep 2376
tcp6       0      0 :::2376                 :::*                    LISTEN

Windows マシンから Docker ホスト (この場合 cobalt) に対して CUDA を使用するコンテナを実行する。

C:\Users\Takami Torao>docker -H tcp://cobalt:2376 run --runtime=nvidia --rm nvidia/cuda nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2017 NVIDIA Corporation
Built on Fri_Sep__1_21:08:03_CDT_2017
Cuda compilation tools, release 9.0, V9.0.176

Docker ホストで実行したときと同じ結果が得られれば成功。

なお -v でボリュームをマウントするように Docker コンテナにリソースを指定する部分では、docker コマンドを実行した端末ではなく Docker ホストのリソースを指定している意味になることに注意。

TensorFlow

Install TensorFlow on Ubuntu 利用可能なタグ (バージョン) はいくつかあるが利用する環境に制約がなければ latest-gpu-py3 を選択すれば良い。TensorFlow や PyTorch などのフレームワークを使用する場合は cuDNN を導入する必要がある。cuDNN の利用にはライセンス同意が必要で nvidia/cuda Docker イメージには含まれていない。NVIDIA cuDNN の DOWNLOAD cuDNN

torao@cobalt:~$ sudo nvidia-docker run -it tensorflow/tensorflow:latest-gpu-py3 bash

問題と対処

apt から nvidia-docker2 のインストールに失敗する場合は Docker CE の該当バージョンを入れ直す。

torao@cobalt:~$ sudo apt-get install -y nvidia-docker2
Reading package lists... Done
Building dependency tree
Reading state information... Done
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
 nvidia-docker2 : Depends: docker-ce (= 18.06.0~ce~3-0~ubuntu) but it is not installable or
                           docker-ee (= 18.06.0~ee~3-0~ubuntu) but it is not installable
E: Unable to correct problems, you have held broken packages.