- できること
- 経緯
- dockerを使ったほうが良いケース
- インストール
- 一般的な環境構築
- 機械学習に特化した環境構築
- ビルドする
- イメージを使う
- エイリアスを登録
- nohupなどバックグラウンドで計算を回し続けたいとき(2017/10/22追記)
- 最後に
できること
この記事では、次のことができるようになります。
- dockerを使ったディープラーニング(chainer)環境構築
経緯
名前だけは知っていたものの、手を出していなかったdockerですが、試してみたらとても便利だったのでまとめてみます。巷にはdockerに関する記事はたくさんあるのですが、ただインストールするだけだったり、本当にこの環境で機械学習をやっているの?と疑ってしまうような環境だったりで、満足いくものがなかったので、試行錯誤してみました。
この記事では、コンテナやイメージなど、dockerの用語の解説は最小限に抑え、快適な機械学習環境を自分で構築できることを目指します。
dockerを使ったほうが良いケース
例えば2つのテーマで研究を並行していて、それぞれchainerのv1系とv3系を使っているくらいのケースであれば、condaなどで仮想環境を作るだけで事足りると思います。やはりdockerを使うべきはGPUを使いたい環境でCUDA周りの面倒な設定をしたくないときです。もちろん、前述のケースでdockerを使うのもありですが、そのメリットを感じられるほど私はまだdockerを使いこなしていません。ということで、以降はGPUがある環境でdockerを使うことを想定します。
インストール
インストールするのは3つです。
- nvidia driver
- docker
- nvidia-docker
dockerではドライバーまで扱うことができないため、GPU用のドライバーは予めインストールする必要があります。dockerは主役なので絶対に必要です。最後にnvidia-dockerですが、dockerはそのままではGPUを認識しません。色々と手を加えると認識するようですが、そこを自動化してくれるのがnvidia-dockerです。コマンドも互換性があり、dockerをnvidia-dockerに置き換えるだけで(知っている限り)全てのコマンドが動きます。インストールの手順は他にも多くの情報があるので、そちらを参照してください。なお、普段使用しているユーザーをdockerグループに追加しておいてください。後で必要になります。
一般的な環境構築
dockerでは、Dockerfileというファイルに構築したい環境を書いていきます。例えばchainerの公式dockerを見てますと
見ていただくとなんとなく分かるかと思いますが、順に説明していきます。
FROM
ベースにする環境です。上のコードはchainerのgithubから引用しているので、コードが更新されると変わりますが、ブログ執筆時はnvidia/cuda:7.5-cudnn5-develが指定されています。これは、nvidiaが提供しているcudaという環境のうち、7.5-cudnn5-develというタグがついているものをベースにしているということです。そのタグ名通り、CUDA7.5/cuDNN5が入っている環境です。これでGPU周りの環境構築は済みました。今までの苦労が嘘のようです。
RUN
環境構築に必要なコマンドです。主にaptやpipで、自分が必要なパッケージをインストールするのに使います。
ということで、基本的にはこのDockerfileを書き換えるか、FROMでchainer/chaierを指定したDockerfileを作ればいいのですが、1つ問題がありました。それはCUDAとcuDNNのバージョンが古いことです。比較はしていませんが、どちらも最新版のほうが高速化されているはずなので、できれば最新版を使いたいところです。しかも、chainer v3ではCUDA9.0/cuDNN7まで対応しているのに公式dockerはCUDA7.5/cuDNN5です。そこで、CUDA9.0/cuDNN7に対応したDockerfileを作りました。
実はFROMの仮想環境を単純に変えるだけでは動かなかったので、多少変更を加えています。python3系しか用意していないので、もし2系が必要な方がいればgithubでPRお待ちしています。
機械学習に特化した環境構築
dockerの用途として、プロダクト用のコードが環境に依存せずに動くようにすることがあります。逆に言うと、そうした用途では機械学習のように色々なコードを試行錯誤しながら動かすことは稀で、基本的には1Dockerfileで1プログラムだけ動かします。その場合は気にならないのですが、機械学習だと気になることがあります。それは、dockerは基本的にrootで動かすということです。つまり、何も設定をしないとrootで全てのプログラムが実行されます。そのため、学習プログラムが吐き出したログの所有権がrootにあり、削除できなかったり編集できなかったりといったことが起きます。正直とても不便です。私は次のようなDockerfileを用意することで解決しています。
FROM dhgrs/chainer:latest RUN pip install matplotlib==2.1.0 librosa==0.5.1 Pillow==4.3.0 pandas==0.20.3 ARG uid ARG gid ARG user RUN echo "${user}:x:${uid}:${gid}:${user},,,::/bin/bash" >> /etc/passwd && \ echo "${user}:x:${uid}:" >> /etc/group RUN mkdir /.cupy && \ chown ${user}:${user} /.cupy USER ${user}
自分で作ったchainer環境をFROMで持ってきて、RUNでpipするところまでは良いかと思います。このファイルでは新しい文法が2つ出てきます。
ARG
Dockerfileから環境を作ることをビルドといいます。ビルドの際に引数に指定したものを使うと明示しています。
USER
どのユーザーで実行するか明示しています。
このファイルを簡単に解説します。USERで指定するユーザーはあくまでdocker内のユーザーであり、例えばここで既存のユーザー名を指定してもログの所有権はそのユーザーにはなりません。これは、ユーザー名は実は名前だけでなくユーザーIDで管理されているからです。つまりユーザーIDが異なると、ユーザー名が一緒でも別ユーザーと認識されます。そこで、docker内外でユーザーIDを一緒にすることで、ログの所有権を既存ユーザーにすることができます。そのコマンドが1つ目のRUNです。2つ目のRUNは、cupyが学習時にキャッシュ用のディレクトリを作るのですが、ルートディレクトリに作るため、rootでないとアクセスできなくてエラーが出るので、予め作成しておきます。
ビルドする
実際に環境を構築するビルドは、構築する環境の名前をbuildとして、Dockerfileがあるディレクトリで次のコマンドでできます。
cat Dockerfile | docker build -t develop --build-arg uid=`id -u` --build-arg gid=`id -g` --build-arg user=`whoami` -
正常にビルドができると、ビルドした環境一覧に表示されます。次のコマンドで確認できます。
docker images
imagesというオプションで分かるかと思いますが、この構築した環境のことをイメージと呼びます。
イメージを使う
先ほどビルドしたdevelopというイメージを使うときは、次のコマンドです。
nvidia-docker run -v /home/$USER:/home/$USER -it develop /bin/bash -
少し補足すると、イメージを使うのはGPUを使うときなので、必ずdockerではなくnvidia-dockerを使います。また、docker内では基本的にdocker外のファイルにアクセスできません。-vオプションで明示的にマウントする必要があります。今回はホームディレクトリをマウントする例です。
エイリアスを登録
毎回上記のコマンドを打つのは面倒なので、私はエイリアスに登録しています。ubuntuであれば、次のコマンドでエイリアスに登録ができます。
echo "alias develop=\"nvidia-docker run -v /home/$USER:/home/$USER -it develop /bin/bash -\"" >> ~/.bashrc
nohupなどバックグラウンドで計算を回し続けたいとき(2017/10/22追記)
大事なことを書き忘れていました。深層学習など、学習に時間がかかる手法を動かすときは、nohupコマンドを使って次のようにやることが多いと思います。
nohup python train.py -g 0 &
しかし、docker上でこのコマンドを打ち、ターミナルを消したりdockerを終了したりすると、プロセスも死にます。なぜなら、dockerは仮想環境なので、dockerが終了するとプロセスが動く環境がなくなるからです。ではどうしたら良いかというと、Ctrl+p, Ctrl+qです。これで、docker環境を起動したまま抜けることができます。一度抜けた環境に戻る場合は、
docker ps
で環境のID(CONTAINER ID)を調べます。例えばIDが1234だとすると、
docker attach 1234
のようにして再度環境に入ることができます。
最後に
dockerは一度環境構築さえやってしまえば後は非常に楽です。とはいえその一度が大変というのはよく分かりました。この記事で少しでもdockerのハードルを下げられればと思います。