やりたかったこと
DockerでGPUに対応したchainerの環境を作りたかった
環境
OS/Arch: linux/amd64
cuda: 11.0
Docker version: 19.03.13
nvidia-docker2
chainer: 7.7.0
やったこと
まず最初にchainer公式のDockerfileを参考に以下のようなDockerfileを作成しました.
(少し余計なライブラリも含まれています)
FROM nvidia/cuda:11.0-base
# Install basics
RUN apt-get update -y
RUN apt-get install -y --no-install-recommends \
python3-dev \
python3-pip \
python3-wheel \
python3-setuptools \
cmake \
wget \
g++
RUN rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*
# Install python library
RUN pip3 install -U pip
RUN pip install chainer==7.7.0
RUN pip install cupy-cuda110==8.4.0
このDockerfileをchainer
という名前でビルドして,
docker build -t chainer .
インタラクティブで起動します.この時--gpus=1
を指定してGPUが使えるようにします.
docker run --it --gpus=1 chainer
この状態でnvidia-smi
を叩くと
$ nvidia-smi
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 450.80.02 Driver Version: 450.80.02 CUDA Version: 11.0 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 A100-PCIE-40GB On | 00000000:41:00.0 Off | 0 |
| N/A 30C P0 32W / 250W | 0MiB / 40537MiB | 0% Default |
| | | Disabled |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
きちんとGPUがコンテナからみえていることがわかりました!
遭遇したエラー
続いてpythonを起動してchainerでGPUが使えるかを以下のように確認したところ,
$ python3
>>> import chainer
>>> chainer.print_runtime_info()
Platform: Linux-3.10.0-1160.6.1.el7.x86_64-x86_64-with-glibc2.29
Chainer: 7.7.0
ChainerX: Not Available
NumPy: 1.20.1
CuPy: Not Available
iDeep: Not Available
CuPy
がNot AvailableになっておりGPUが認識されていないようです.
試しにCuPy
をインポートできるか試したところ
$ python3
>>> import cupy
(途中略)
ImportError: libcublas.so.11: cannot open shared object file: No such file or directory
libcublas.so.11
が見つからないのでインポートできないと言われました.
libcublas.so.11
って何?という感じだったのですが,どうやらcuda関連のライブラリらしいです.
cuda関連のライブラリはコンテナ上の/usr/local/cuda/lib64
に置いてあるものらしいのですが(環境による?),確認してみてもlibcublas.so.11
は見つかりませんでした.
# コンテナ上
$ ls /usr/local/cuda/lib64
libcudart.so.11.0 libcudart.so.11.0.221
# libcublas.so.11が無い
そこで,ホストマシン上にlibcublas.so.11
があるかを確認したところ,
# ホストマシン上
$ ls /usr/local/cuda/lib64 | grep libcublas.so.11
libcublas.so.11
ホストマシン上にはlibcublas.so.11
は確かに存在していることが分かりました.
これをどうやってコンテナ上に持っていけば良いんだ?ボリュームを使ってマウントすれば良いのか?などと最初に考えました.(実際にボリュームを使ってみたらいけました.docker run -it -gpus=1 -v /usr/local/cuda:/usr/local/cuda chainer
)
しかしわざわざマウントするのは面倒で,何か他のやり方があるだろうと思って色々探した結果こんな情報を見つけました.
https://github.com/NVIDIA/nvidia-docker/issues/1160
nvccがコンテナから使えないのは何故?あとcudnn関連のファイルがコンテナにないのはなぜ?ということを質問している人がいて,
それに対する回答がCUDA devolopment toolsにアクセスするにはdevel
イメージを使わないといけない.ということでした.
もしかしてlibcublas.so.11
が見つからないのも同じ原因?と考えてDockerfileに記述していたイメージを以下のようにnvidia/cuda:11.0-base
からnvidia/cuda:11.0-devel
に変更しました.
# FROM nvidia/cuda:11.0-base baseではなくdevelにする
FROM nvidia/cuda:11.0-devel
そしてコンテナを起動して/usr/local/cuda/lib64
を確認したところlibcublas.so.11
が置いてありました!
# コンテナ上
$ ls /usr/local/cuda/lib64 | grep libcublas.so.11
libcublas.so.11
この状態でcupyをインポートしたところ,正常にインポートされました!
どうやらcudaのイメージにはbase
, runtime
, devel
の3種類のイメージがあるようです.
base
にはCUDAのランタイム,runtime
にはbase
+CUDAのMATHライブラリとNCCL, devel
にはruntime
+ヘッダーとCUDAのイメージをビルドするための開発ツールが含まれているようです.
詳細はdockerhub nvidia/cudaに書いてありました.
今回の場合,runtime
またはdevel
を選択すれば良かったようです.
これでcupyを使えるようになりました!
それでもchainerがcupyを認識できない
cupyは正しくimportできるのに,chainerからcupyを使えなかった
$ python3
>>> import cupy
>>> import chainer
>>> chainer.print_runtime_info()
Platform: Linux-3.10.0-1160.6.1.el7.x86_64-x86_64-with-glibc2.29
Chainer: 7.7.0
ChainerX: Not Available
NumPy: 1.20.1
CuPy: Not Available
iDeep: Not Available
これに関しては全く同じ現象に遭遇している方がいました.Chainer 7.7.0 のインストールでハマった話
cupyのversion 8.0以降の問題らしいので,それ以前のバージョンをインストールすればいいそうです.
pip install cupy-cuda110==7.8.0
上記コマンドでcupyをインストールしたところ,
$ python3
>>> import chainer
>>> chainer.print_runtime_info()
Platform: Linux-3.10.0-1160.6.1.el7.x86_64-x86_64-with-glibc2.29
Chainer: 7.7.0
ChainerX: Not Available
NumPy: 1.20.1
CuPy:
CuPy Version : 7.8.0
CUDA Root : /usr/local/cuda
CUDA Build Version : 11000
CUDA Driver Version : 11000
CUDA Runtime Version : 11000
cuBLAS Version : 11200
cuFFT Version : 10201
cuRAND Version : 10201
cuSOLVER Version : (10, 6, 0)
cuSPARSE Version : 11101
NVRTC Version : (11, 0)
cuDNN Build Version : None
cuDNN Version : None
NCCL Build Version : 2708
NCCL Runtime Version : 2708
CUB Version : Enabled
cuTENSOR Version : None
iDeep: Not Available
ようやくCuPyがchainerから認識されました!
Dockerfile完成系
最後に完成したDockerfileを書いておきます.
FROM nvidia/cuda:11.0-runtime
# Install basics
RUN apt-get update -y
RUN apt-get install -y --no-install-recommends \
python3-dev \
python3-pip \
python3-wheel \
python3-setuptools \
cmake \
wget \
g++
RUN rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*
# Install python library
RUN pip3 install -U pip
RUN pip install chainer==7.7.0
RUN pip install cupy-cuda110==7.8.0
まとめ
DockerでGPUに対応したchainerの実行環境を作成しようとしたところ,
- cupyが使えない
- chainerからcupyを使えない
という二つの問題が発生しました.
この二つの問題に対してそれぞれ以下のように対処を行いました.
- 誤ったcudaのイメージをベースにDockerfileを記述していたので,正しいcudaのイメージに修正
- cupyのバージョンの問題だったので,正しいバージョンをインストール
その結果無事にGPUに対応したchainer実行環境をDockerで作成することができました.
参考記事
NVIDIA Docker って今どうなってるの? (20.09 版)