Chainer 1.5のインストールがうまくいかない人への非公式なTips


*Chainer 1.6以降で、この記事の問題の大部分は解消しました*

Chainer 1.5で、外部の依存状況が大きく変わりました。その結果、幾つかの要因でインストールが難しくなりました。この記事では、その対策を書きます。

# 主な原因

1. Cythonを使うようになりました。ソースの一部は.pyxファイルになり、.cppを生成して.soにビルドしています（1.5.1でcythonize済みの.cppファイルを同梱しています）
2. CUDAやcuDNNなどの共有ライブラリ（.soファイル）もCythonから使うようになりました。今までは、ctypesを使っていました。
3. 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公式の環境変数ではない気がする。