Chainer 1.6以降で、この記事の問題の大部分は解消しました
Chainer 1.5で、外部の依存状況が大きく変わりました。その結果、幾つかの要因でインストールが難しくなりました。この記事では、その対策を書きます。
主な原因
- Cythonを使うようになりました。ソースの一部は.pyxファイルになり、.cppを生成して.soにビルドしています(1.5.1でcythonize済みの.cppファイルを同梱しています)
- CUDAやcuDNNなどの共有ライブラリ(.soファイル)もCythonから使うようになりました。今までは、ctypesを使っていました。
- h5pyなど、共有ライブラリを必要とするパッケージを利用するようになりました。
順に、何が問題になるのか説明します。
Cythonの利用
Cythonは.pyxで記述したファイルを、.cppに変換(コンパイル)してから、.soファイルを作り、それを呼び出すことによって高速化するツールです。CuPyの速度が遅い理由の1つが、Pythonインタプリタが遅すぎることだったので、Cythonによる高速化が求められました。
まず、Cythonが必要になります。これはpipで勝手にインストールします。.cppができるということは、それをビルドするC++コンパイラが必要になります。これは、gcc(g++)や、WindowsならMSVCが必要になります。これらがない環境ではビルドができません。
v1.5.1からCython済みの.cppファイルを同梱しているため、Chainer自体はCythonに依存しなくなりました。一方で、h5pyがCythonを要求するため、依然としてCythonが必要です。
ctypesからCythonへ
外部の共有ライブラリを使うには、これらにアクセスする必要があります。今まではctypesというライブラリを使っていましたが、ctypesは動作が遅く、ここもまたボトルネックの一つになっていました。
ctypesは.so中のシンボルに直接アクセスします。つまり、.hファイル相当の情報がChainerの.pyソース中に暗に記述されていました。Cythonの場合は、.cppにして静的にビルドするため公式の.hファイルをインクルードして使う、ある意味正しい使い方になりました。一方で、v1.5では.hファイルの場所や.soファイルの場所が、 インストール時 に指定する必要があります。そのため、インストール時にnvccにパスが通っていたり(そこからCUDAのディレクトリを逆算します)、cudnn.hやcudnn.soの場所がCPATHやLIBRARY_PATHで指定されている必要があります(cuDNNには公式のインストール先やインストーラがありません)。
また、CuPyのインストール後にCUDAやcuDNNを入れただければ動きません(ctypesの場合は、soファイルさえ見つけられればよかった)。そのため、これらの場所が変わったり、バージョンが上がってバイナリ互換性が崩れた場合は、再インストールの必要があります。
h5pyへの依存
シリアライズに使っているHDF5は、h5pyから使っています。このh5pyはlibhdf5.soを使っているため、このライブラリがインストールされている必要があります。こうした制約は、pillowからjpegファイルを使う時と同様です(一度libjpegがない状況でpip pillowしてみると状況がわかります)。
ライブラリは通常pipでは管理されていませんから、Ubuntuならlibhdf5-devなどを予めインストールしておかないとh5pyのインストールに失敗します。・・・といっても、この制約はChainerではなくてh5pyの制約です。
個別の問題と対処法
依存ツール・ライブラリ群を予めインストールする
アップグレード前に、依存ツール・ライブラリをインストールします。Ubuntuならg++やlibhdf5-devを入れて下さい。
特に、
...h5py/h5py/api_compat.h:27:18: fatal error: hdf5.h: No such file or directory
#include "hdf5.h"
こういうエラーメッセージがでたら、これはlibhdf5-devがない証拠です(h5pyのインストールに失敗しています)。
CUDAも予めインストールして、nvccをPATHに通してください。cuDNNも、適当なディレクトリに展開して、CPATHにcudnn.hがあるディレクトリを、LIBRARY_PATHとLD_LIBRARY_PATHにcudnn.soがあるディレクトリをそれぞれ追加します。ちなみに、cuDNN v2は解凍すると無造作に.hと.soが入っており、cuDNN v3はそれぞれcuda/includeとcuda/lib64というディレクトリに展開されます。
pipを最新にする
完全に原因を特定していませんが、pipが古いとh5pyのインストールに失敗することが有ります。
pip install -upgrade pip
してください。これは、h5pyのバージョンが上がると解消されるかもしれません。
setuptoolsを最新にする
同様にsetuptoolsが古いと失敗することが有ります。これもh5pyのバージョンが上がると解消されるかもしれません。
pip install -U setuptools
Cythonを先にインストールする
Cythonを使ったライブラリのインストールは、全体的に(?)失敗しやすくなっているようです。Cythonは利用時はもとより、インストール 時 に必要になります。.pyxファイルを.cppに変換する必要があるからです。
h5pyのsetup.pyに問題がある(?)ようで、masterブランチでは直っていますが、2.5.0ではsetup_require
にCythonがありません。そのせいで、ビルド時にCythonを見つけられずに失敗することが有ります(何らかの要因でCythonの方が先に入って、成功することも有ります)。
先に、
pip install cython
すると解消される可能性があります。
メモリが足りなくなる [未解決]
Cythonのsetup.py中で無限ループが発生して、メモリがなくなることが原因と考えられています。Cythonを直接インストールするとこの問題が発生しないことが知られているので、直接入れると解決する可能性があります。
pip install -U cython
この発生原因は、まだ完全にはわかっていません。Chainerのsetup.pyがCythonに依存していると、先にCythonをアップグレードするためにCythonのソースを落としてきて、その中のsetup.pyを実行しようとしますが、setuptoolsはこのときにeval
メソッドを使って実行するようです。そのために、一度importしたモジュールを開放してからsetup.pyの中身をeval
しているようですが、そこで問題が発生しているように見えます。直接の原因は、同名のモジュールとクラスが混在した状態になって(reloadするまえのオブジェクトが、reload後のclassとisinstance関係ではなくなってしまうのと同じような状況)、unpickleできなくなって無限ループが発生する現象を確認しています。
sudoに気をつける
sudoは環境変数を引き継ぎません。そのため、一生懸命上記の環境変数をセットしたつもりが、sudoの中では無視されます。envコマンドを駆使するか、rootになって作業して下さい。
しかし、そもそも論として個人的にはpyenvなどでユーザー固有のPython環境を構築するか、--user
オプションを付けてローカルにインストールすることをおすすめします(これはChainerに限った話ではないですが)。研究室などで勝手にアップデートすると、締め切り直前の先輩に怒られますよ。
一般的になぜこの問題がおこらないかというと、普通は ./configure
は一般ユーザーで行って必要な情報をファイルに書きだして、 make
だけ sudo
するからです。pipではそのようなプロセスがありません。
masterでは指定がなければ /usr/local/cuda
を直接参照するようにしています。
Chainerがたくさんいる
Chainerが沢山インストールされている事があります。アンインストール時は、pip uninstall chainer
を、警告が出なくなるまで繰り返してください。
何かゴミが残っている
site-package
ディレクトリにChainerの残骸が残っている事があります。pip uninstall
しても消えません。私はドキドキしながら手動で消したりしています。正しい対応方法などはよくわかりません。
キャッシュに嵌らないようにする
キャッシュを見てしまってインストールが失敗する現象が散見されます
pip install chainer --no-cache
を試して下さい。
pycudaはもういらない
pycudaにはもう依存していません。インストールの必要はありません。
chainer-cuda-depsはもういらない
chainer-cuda-depsは以前のバージョンでpycudaなどの、CUDA動作に必要な依存ライブラリをインストールするためのものでした。もういりません。
環境変数あれこれ
- CPATH: gccがインクルードファイルを探す先。ビルド時に必要。
- LIBRARY_PATH: gccがライブラリファイルを探す先。ビルド時に必要。
- LD_LIBRARY_PATH: dlopenがライブラリファイルを探す先。実行時に必要(な場合がある)。
- DYLD_LIBRARY_PATH: Mac(BSD系?)でdlopenがライブラリファイルを探す先。実行時に必要(な場合がある)。
- CUDA_PATH: Windows版CUDAをインストールすると、インストール先として勝手にセットされる。
- CUDA_ROOT: PyCUDAで使われているが、別にnVidia公式の環境変数ではない気がする。
- CUDA_HOME: TensorFlowで使われているが、別にnVidia公式の環境変数ではない気がする。