CCCマーケティング データベースマーケティング研究所の Tech Blog

研究所スタッフによる格闘記録やマーケティング界隈についての記事など

LinuxサーバーでGPU環境を構築してみた

こんにちは。技術開発チームの矢澤です。

以前このブログの記事で、WindowsノートPCでGPU環境を構築する方法を紹介しました。 適切なバージョンのツールをインストールすることで、深層学習のモデルをGPUで動かせるようになりました。 しかしその後、今度は社内の分析サーバーでGPUが使用できなくなる問題が発生し、環境の再構築を行いました。 そこで今回は、LinuxマシンでのGPU環境構築方法として、実際に行った手順を説明したいと思います。

背景

初めに、今回の環境再構築に至った経緯を簡単にお話しします。

技術開発チームでは、これまで共有の分析サーバー上でGPUを使ってモデルの検証などを行っていましたが、ある日GPUが使えなくなっていることに気がつきました。 具体的には、nvidia-smi(GPUの使用状況を確認するコマンド)を実行しても、エラーとなりGPUの情報が得られなくなりました。 原因として、Dockerコンテナ内でCUDAの設定を行った際に、誤ってホスト側の環境を壊してしまったことなどが考えられます。

また分析サーバーでは元々、NVIDIAドライバーのバージョンが古く、最新のライブラリ(TensorFlow 2系など)を使えないという問題がありました。 そこで、これを機に最新のドライバーを再インストールすることとしました。

※ 余談ですが、弊社では年に一度、ビルの電源設備点検のための全館停電があり、マシンの再起動の必要性や万が一起動しなくなったときに電源を入力する手間などを考えて、環境構築のタイミングを停電の前日に合わせたかったという理由もあります。

さらに、上記のサーバーではNvidia Docker経由でGPUを使用しており、Dockerのバージョンが古いという問題もあったため、併せてDockerのアップグレードを行いました。

今回使用した分析サーバーのOSおよび、インストールしたツールのバージョン等は以下の通りです。

  • OS:CentOS Linux 7.5
  • NVIDIAドライバー:396.44 -> 440.64
  • Docker:18.09 -> 19.03
  • Nvidia Docker: NVIDIA Container Toolkit (2.2.1)
  • Dockerイメージ: tensorflow/tensorflow:latest-gpu
  • CUDA:10.1 -> 10.2(未実行)
  • TensorFlow:2.2

以降で、詳細を順に説明していきたいと思います。

環境構築方法

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

分析サーバー上でGPUを使えるように、最新のNVIDIAドライバーをインストールします。

まずは、コマンドラインから必要なパッケージをインストールします。

$ sudo yum -y update
$ sudo yum -y install kernel-devel kernel-headers gcc make git pciutils tmux

自分の環境では、yumのアップデート時にいくつかエラーが出ましたが、無視して進めていきました。 以下のように、指定したパッケージがインストールされればOKだと思います。

~
検証中 : kernel-headers-3.10.0-862.14.4.el7.x86_64 27/29
検証中 : gcc-4.8.5-36.el7_6.2.x86_64 28/29
検証中 : libquadmath-4.8.5-36.el7_6.2.x86_64 29/29

インストール:
kernel-devel.x86_64 0:3.10.0-1127.el7 tmux.x86_64 0:1.8-4.el7

依存性関連をインストールしました:
libevent.x86_64 0:2.0.21-4.el7

更新:
gcc.x86_64 0:4.8.5-39.el7 kernel-headers.x86_64 0:3.10.0-1127.el7 make.x86_64 1:3.82-24.el7

依存性を更新しました:
cpp.x86_64 0:4.8.5-39.el7 gcc-c++.x86_64 0:4.8.5-39.el7 gcc-gfortran.x86_64 0:4.8.5-39.el7 libgcc.x86_64 0:4.8.5-39.el7 libgfortran.x86_64 0:4.8.5-39.el7 libgomp.x86_64 0:4.8.5-39.el7
libquadmath.x86_64 0:4.8.5-39.el7 libquadmath-devel.x86_64 0:4.8.5-39.el7 libstdc++.x86_64 0:4.8.5-39.el7 libstdc++-devel.x86_64 0:4.8.5-39.el7

完了しました!

続いて、Nouveauの無効化を行います。 Nouveauとはオープンソースのグラフィックスドライバーで、これが既に有効になっていると、新たなNVIDIAドライバーを正しくインストールすることができません。

Nouveauがロードされているかどうかは、以下のコマンドで確認することができます。

$ lsmod | grep nouveau

今回は、上記のコマンドを実行しても何も表示されず、Nouveauがロードされていないことが分かったので、無効化の必要はありませんでした。

次に、サーバーに内蔵されているGPUの型番を確認します。

$ lspci | grep -i nvidia
25:00.0 3D controller: NVIDIA Corporation GP102GL [Tesla P40] (rev a1)

Tesla P40というGPUが使われていることが分かります。

※ 自分は初めにVGAの方のビデオカードを見ていて( $ lspci | grep -i VGA )、対応するNVIDIAドライバーが見つからずにハマったのでご注意ください。

ドライバーのインストーラーは、Windowsの時と同様にNVIDIAの公式ページからダウンロードすることができます。

www.nvidia.co.jp

上記で確認したGPU(Tesla P40)用のドライバで、最新のCUDA(v10.2)に対応したものを選びます。

f:id:K_Yazawa:20200515172851p:plain
NVIDIAドライバー ダウンロードページ

ダウンロードが完了したら、適当なディレクトリにファイルを移動し、そのディレクトリ内で以下のコマンドを実行します。

sudo init 3
sudo systemctl stop nvidia-docker
sudo bash [インストーラーのファイル名]

するとインストーラーが起動し、以下のような青色の画面がターミナル上に表示されます。

f:id:K_Yazawa:20200515173352p:plain
NVIDIAドライバー インストール画面

今回は既に古いドライバー(396.44)が入っていたため、上書きして良いかどうかを確認されました。 上書きして問題ないため、「Continue installation」を選んでインストールを進めます。

その後、いくつかのメッセージが表示されるので、以下のように選択していきました。

Would you like to register the kernel module sources with DKMS? This will allow DKMS to automatically build a new module, if you install a different kernel later.*1
-> Yes

WARNING: nvidia-installer was forced to guess the X library path '/usr/lib' and X module path '/usr/lib/xorg/modules'; these paths were not queryable from the system. If X fails to find the NVIDIA X driver module, please install the pkg-config utility and the X.Org SDK/developmen package for your distribution and reinstall the driver.*2
-> OK

Install NVIDIA's 32-bit compatibility libraries?*3
-> No

最終的に、以下のようなメッセージが表示されればインストール完了です。

Installation of the kernel module for the NVIDIA Accelerated Graphics Driver for Linux-x86_64 (version 440.64) is now complete.

インストールが正しく行われたかどうかは、コマンドでも確認することができます。

$ nvidia-smi
Fri May 15 18:12:30 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.64.00 Driver Version: 440.64.00 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 P40 Off | 00000000:25:00.0 Off | N/A |
| N/A 35C P8 N/A / N/A | 0MiB / 22919MiB | 2% Default |
+-------------------------------+----------------------+----------------------+

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

Docker, Nvidia Dockerのアップグレード

続いて、Dockerの環境構築を行います。

既にインストールされているDockerのバージョンを以下のコマンドで確認すると、18.09が入っていることがわかりました。

$ docker --version

Dockerについては、バージョン19.03からGPUにネイティブ対応したとのことなので、今回は19.03にアップグレードします。

また、Dockerコンテナ内でGPUを使うためのツールとしてNvidia Dockerがありますが、こちらも何度か仕様変更が行われており、GPU対応コンテナを起動する際の引数などが変化しています。 例えば、最新のNVIDIA Container Toolkit(v2.2)では、--gpusオプションでGPUの設定を行います。

$ docker run --gpus all ...

一方、一つ前のバージョンであるNVIDIA Container Runtime for Docker(v2.1)では上記の方法に加えて、以下のようにコンテナを起動することもできます。

$ docker run --runtime nvidia ...
$ nvidia-docker run ...

今回は、できるだけ最新の環境を使いたいものの、以前の書き方も使えるようにしたいと思い、一つ前のNvidia Dockerを使用したいと考えました。

※ 実際は、Dockerのアップグレード時に最新のNVIDIA Container Toolkitがインストールされてしまったため、そちらを使い続けることにしました。

ここからは、Docker 19.03のインストール方法を説明します。

初めに、必要なパッケージをyumでインストールします。

$ yum install -y yum-utils device-mapper-persistent-data lvm2

続いてDockerのリポジトリを追加し、インストールします。

$ yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
$ yum -y install docker-ce docker-ce-cli containerd.io

ここで以下のようなエラーが発生しました。

Error downloading packages:
nvidia-container-toolkit-1.0.5-2.x86_64: [Errno 256] No more mirrors to try.
nvidia-docker2-2.2.2-1.noarch: [Errno 256] No more mirrors to try.
nvidia-container-runtime-3.1.4-1.x86_64: [Errno 256] No more mirrors to try.

この状態でDockerのバージョンを確認したところ、18.09のままであったため、以下のページを参考に、yumの鍵を削除してから再度インストールを行いました。

github.com

$ sudo gpg --homedir /var/lib/yum/repos/x86_64/7/libnvidia-container/gpgdir --delete-key F796ECB0
$ sudo gpg --homedir /var/lib/yum/repos/x86_64/7/nvidia-container-runtime/gpgdir --delete-key F796ECB0
$ sudo gpg --homedir /var/lib/yum/repos/x86_64/7/nvidia-docker/gpgdir --delete-key F796ECB0
$ yum -y install docker-ce docker-ce-cli containerd.io

このとき上述したように、Dockerと一緒に最新のNvidia Docker(nvidia-container-toolkit)もインストールされてしまったようです。

検証中 : nvidia-container-runtime-2.0.0-1.docker18.09.0.x86_64 26/28
検証中 : 1:docker-ce-cli-18.09.0-3.el7.x86_64 27/28
検証中 : selinux-policy-3.13.1-192.el7_5.6.noarch 28/28

インストール:
nvidia-container-toolkit.x86_64 0:1.0.5-2

更新:
containerd.io.x86_64 0:1.2.13-3.1.el7 docker-ce.x86_64 3:19.03.8-3.el7 docker-ce-cli.x86_64 1:19.03.8-3.el7

依存性を更新しました:
container-selinux.noarch 2:2.119.1-1.c57a6f9.el7 libsemanage.x86_64 0:2.5-14.el7 libsemanage-python.x86_64 0:2.5-14.el7 nvidia-container-runtime.x86_64 0:3.1.4-1 nvidia-docker2.noarch 0:2.2.2-1
policycoreutils.x86_64 0:2.5-34.el7 policycoreutils-python.x86_64 0:2.5-34.el7 selinux-policy.noarch 0:3.13.1-266.el7 selinux-policy-targeted.noarch 0:3.13.1-266.el7 setools-libs.x86_64 0:3.3.8-4.el7
置換:
nvidia-container-runtime-hook.x86_64 0:1.4.0-2

色々と試行錯誤していたため定かではないのですが、Dockerの前にNvidia Dockerをインストールしようとして失敗していたことが、原因かもしれません。 今回は、古いバージョンのNvidia Dockerの再インストールが面倒であったことと、いずれサポートされなくなると考え、ひとまずこのまま最新のバージョンを使うこととしました。

※ ただし、なぜか docker run --runtime nvidia ... コマンドは引き続き使えるみたいです。

改めてDockerのバージョンを表示すると、確かに19.03にバージョンアップしていることが分かりました。

$ docker --version
Docker version 19.03.8, build afacb8b

Dockerイメージのダウンロード

続いて、TensorFlow GPUが動くDockerイメージを用意します。 方法は簡単で、公式のイメージをDocker Hub上のレポジトリからダウンロードするだけです。

docker pull tensorflow/tensorflow:latest-gpu

※ タグ(latest-gpu)をつけないと、CPU版のイメージとなってしまいます。

ダウンロードが完了したら、以下のコマンドでイメージの存在を確認できます。

$ docker images | grep tensor
tensorflow/tensorflow latest-gpu f5ba7a196d56 7 days ago 3.84GB

本イメージには、

  • Ubuntu: 18.04
  • CUDA: 10.1
  • Python: 3.6
  • TensorFlow GPU: 2.2

が入っています。

以降の手順は、上記のDockerイメージのコンテナに入って行います。

$ docker run -it --gpus all --name gpu_test tensorflow/tensorflow:latest-gpu /bin/bash

CUDAのアップグレード(未実行)

上記の通り、ダウンロードしたDockerイメージにはCUDA v10.1がインストールされているため、これを最新のv10.2にバージョンアップしたいと考えました。 しかし、aptによるインストールが何度やってもうまくいかず、結局CUDA 10.2をインストールすることは諦めました。

NVIDIAの開発者用のページを確認すると、Ubuntsu 18.04では対応するカーネルのバージョンが4.15となっています。

docs.nvidia.com

f:id:K_Yazawa:20200515192755p:plain
CUDA 10.2 のLinux対応表

一方、今回使用したイメージはカーネルがv3.10であるため、サポート対象外なのかもしれません。

/# uname -r
3.10.0-862.14.4.el7.x86_64

どうしても最新のCUDAを使いたい場合は、以下のようなCUDA 10.2がインストールされたDockerイメージを基に、TensorFlowなどの必要なライブラリをインストールすれば良いのではないかと思います。

hub.docker.com

GPU使用確認

環境の構築が完了したので、Dockerコンテナ内で実際にGPUを使用してみます。

まずはコンテナ内でnvidia-smiコマンドを使用して、GPUが認識できることを確認します。 ホストで実行したときと同じ結果が得られれば、問題ありません。

続いて、TensorFlowでGPUを使用できるかどうか確認します。 Pythonを起動して、以下のコマンドを実行します。

from tensorflow.python.client import device_lib
device_lib.list_local_devices()

使用可能なデバイス一覧に「GPU」が含まれていれば成功です。

[ ~
, name: "/device:GPU:0"
device_type: "GPU"
memory_limit: 22437165824
locality {
bus_id: 1
links {
}
}
incarnation: 387074657355343966
physical_device_desc: "device: 0, name: Tesla P40, pci bus id: 0000:25:00.0, compute capability: 6.1"
]

あとは、TensorFlowのプログラムなどを実装して、GPUを思う存分使うことができます。

終わりに

今回は、Linuxの分析サーバーでGPUを使うための環境を再構築しました。

GPU用のツール類については、日々バージョンアップしており、新たな機能の追加やバグの修正などが行われています。 今後も、常に最新の状況に目を配り、ライブラリの仕様の大幅な変更などがあった場合は、今回の経験を元に適宜アップデートしていきたいと思います。

*1:カーネルモジュールをDKMS(Dynamic Kernel Module Support )に登録しておくことで、OSカーネルのアップデート時に新しいドライバーが自動的にインストールされます。

*2:X Window System(Linux用のGUI環境構築システム)がインストールされていないとWARNINGが表示されますが、無視して問題ないようです。

*3:32bit互換ライブラリをインストールするかどうか聞かれますが、32bit版のツールを使わない場合は不要だと思います。