技術研究所のYKです。 今回、新たにGPU環境を構築する必要が生じたので、そのついでにPython3でのCaffe環境構築を試してみました。 以前もCaffeの環境構築を行いましたが、その時には、情報がより多く出回っているという理由からPython2.7を使用して環境構築を行いました。
しかし、普段の業務やプライベートではPython3系を使っている為、どうせならPython3系を使ってやってみよう!と思い立ったのがキッカケです。 Python2.7での環境構築では手間取らなかったようなところで手間取ったので、(私自身の備忘の為にも)試行錯誤した結果をメモしておきます。

下準備

  • 環境: AWS EC2上にGPUインスタンスを立てました。
    • インスタンスタイプ: g2.8xlarge
      • これまではg2.2xlargeのインスタンスを使っていましたが、今回はかなりスペックを上げてみました。 下記表は、 https://aws.amazon.com/jp/ec2/instance-types/ より引用しています。
        モデル GPU vCPU メモリ(GiB) SSDストレージ (GB)
        g2.2xlarge 1 8 15 1 x 60
        g2.8xlarge 4 32 60 2 x 120
  • OS: Ubuntu 16.04.2 LTS
  • アーキテクチャ: 64bit(x86_64)
  • 導入したライブラリ
    • CUDA 8.0
    • cuDNN 5.1
    • Python
      • 今後TensorFlowやChainer等を導入することが見込まれる為、pyenvを利用してAnacondaの導入を行いました。
      • Anacondaのバージョン: Python 3.6.0 :: Anaconda 4.3.1
      • pyenv
        • Pythonのバージョン管理システム 複数のバージョンのPythonを共存させたり、用途に応じて利用するPythonのバージョンを切替えたりできる
          pyenv GitHub
  • Anaconda
    • Continuum Analyticsが提供している、Pythonと科学計算向けのライブラリが同梱されたPythonのパッケージ
      Linux版、macOS版、Windows版が提供されており、それぞれPython2.7、Python3.6向けが提供されている
  • 環境構築で手間取ったところ

    手間取った箇所のログと、その対策を記載しておきます。

    Caffeのmake時に出たエラー

    1. pyconfig.h: No such file or directory

    In file included from /usr/include/boost/python/detail/prefix.hpp:13:0,
    from /usr/include/boost/python/args.hpp:8,
    from /usr/include/boost/python.hpp:11,
    from src/caffe/layer_factory.cpp:4:
    /usr/include/boost/python/detail/wrap_python.hpp:50:23: fatal error: pyconfig.h: No such file or directory
    • 原因
      • 導入したAnacondaのパスをMakefile.configに設定していなかったことに因ります。
    • 対策
      • Makefile.configを以下のように修正しました。
    # 72行目: コメントアウトを外す & パスの書換え
    ## 変更前
    # ANACONDA_HOME := $(HOME)/anaconda
    ## 変更後</code> <code>ANACONDA_HOME := $(HOME)/.pyenv/versions/anaconda3-4.3.1/

    2. libcaffe.so, not found

    /usr/bin/ld: warning: libpython3.6m.so.1.0, needed by .build_release/lib/libcaffe.so, not found (try using -rpath or -rpath-link)
    • 原因
      • Makefile.config内のANACONDA_INCLUDEに、libcaffe.soが格納されているディレクトリのパスが記載されていなかったことに因ります。
  • 対策
    • Makefile.configを以下のように修正しました。
  • # 79 ~ 80行目: コメントアウトを外す & パスの書換え・追加
    # 併せて、導入したPythonのバージョンに合わせる修正も実施
    ## 変更前
    # PYTHON_INCLUDE := /usr/include/python3.5m \
    # /usr/lib/python3.5/dist-packages/numpy/core/include
    ## 変更後
    PYTHON_INCLUDE := $(ANACONDA_HOME)/include \
    $(ANACONDA_HOME)/lib \
    $(ANACONDA_HOME)/include/python3.6m \
    $(ANACONDA_HOME)/lib/python3.6/site-packages/numpy/core/include

      ここまでで、一旦make all -> make test -> make runtest -> make pycaffeが全て通るようになりました。

    import caffe時に出たエラー

    makeが全て通ったのでPythonインタプリタ上で import caffe を叩いてみましたが、まだまだエラーが出ました。

    1. gccランタイムライブラリのバージョンミスマッチ

    import caffe
    Traceback (most recent call last):
    File "", line 1, in
    File "$HOME/caffe/python/caffe/__init__.py", line 1, in
    from .pycaffe import Net, SGDSolver, NesterovSolver, AdaGradSolver, RMSPropSolver, AdaDeltaSolver, AdamSolver, NCCL, Timer
    File "$HOME/caffe/python/caffe/pycaffe.py", line 13, in
    from ._caffe import Net, SGDSolver, NesterovSolver, AdaGradSolver, \
    ImportError: $HOME/.pyenv/versions/anaconda3-4.3.1/bin/../lib/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by $HOME/caffe/python/caffe/_caffe.so)
    • 原因
      • libstdc++に含まれるGLIBCのバージョンが適切でないことによるエラーであり、 $HOME/.pyenv/versions/anaconda3-4.3.1/bin/../lib/libstdc++.so.6に、GLIBCXX_3.4.21が含まれていないことに起因するものでした。
    • ※ 合致するバージョンを含むlibstdc++やlibgompが見つからなかった場合はcondaコマンド等を利用して更新する必要がありますが、今回は割愛致します。
  • 対策
    • 以下の手順で対策を行いました。
  • (1) libstdc++.so.6に含まれるGLIBCのバージョンを確認する

    strings $HOME/.pyenv/versions/anaconda3-4.3.1/bin/../lib/libstdc++.so.6 | grep GLIBCXX
    # 確かに、GLIBCXX_3.4.21が無い
    GLIBCXX_3.4
    ...
    GLIBCXX_3.4.18
    GLIBCXX_3.4.19
    GLIBCXX_FORCE_NEW
    GLIBCXX_DEBUG_MESSAGE_LENGTH
    ls -al $HOME/.pyenv/versions/anaconda3-4.3.1/bin/../lib/libstdc++.so.6
    # 実体はlibstdc++.so.6.0.19
    lrwxrwxrwx 1 caffe-user caffe-user 19 May 8 18:45 libstdc++.so.6 - libstdc++.so.6.0.19

    (2) libstdc++が付くファイルを検索する

    sudo find / -name "libstdc+*"
    $HOME/.pyenv/versions/anaconda3-4.3.1/pkgs/libgcc-4.8.5-2/lib/libstdc++.so.6
    ...
    $HOME/.pyenv/versions/anaconda3-4.3.1/lib/libstdc++.so.6
    $HOME/.pyenv/versions/anaconda3-4.3.1/lib/libstdc++.so
    $HOME/.pyenv/versions/anaconda3-4.3.1/lib/libstdc++.so.6.0.19
    /usr/lib/x86_64-linux-gnu/libstdc++.so.6 # ここら辺使えそう
    /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21 #

    (3) 見つけたlibstdc++に含まれるGLIBCのバージョン確認

    • (1) と同様の手順で、内包しているランタイムのバージョンを確認します。
    strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX
    GLIBCXX_3.4
    ...
    GLIBCXX_3.4.19
    GLIBCXX_3.4.20
    GLIBCXX_3.4.21 # あった!
    GLIBCXX_DEBUG_MESSAGE_LENGTH
    • 見つけたlibstdc++がシンボリックリンクか否か確認します。
    ls -al /usr/lib/x86_64-linux-gnu/libstdc++.so.6
    # シンボリックリンクかファイルの実体かを確認
    lrwxrwxrwx 1 root root 19 Nov 3 2016 /usr/lib/x86_64-linux-gnu/libstdc++.so.6 - libstdc++.so.6.0.21

    (4) シンボリックリンクを張り直す

    • 念の為、元のlibstdc++.so.*をバックアップした上で行いました。
    ln -s /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21 $HOME/.pyenv/versions/anaconda3-4.3.1/bin/../lib/libstdc++.so.6
    ln -s /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21 $HOME/.pyenv/versions/anaconda3-4.3.1/bin/../lib/libstdc++.so.6.0.21

    (5) import caffeしてみる

    • 再度Pythonインタプリタを起動し、import caffeを実行してみました。
      • 当方の環境では、今度はlibgomp.so.1が存在しないというエラーが出ましたが、 (1) ~ (4)の対象をlibgomp.so.1に読み替えて対応し、解消しました。

    2. boost.pythonに起因するエラー

    import caffe
    Traceback (most recent call last):
    File "", line 1, in
    File "$HOME/caffe/python/caffe/__init__.py", line 1, in
    from .pycaffe import Net, SGDSolver, NesterovSolver, AdaGradSolver, RMSPropSolver, AdaDeltaSolver, AdamSolver, NCCL, Timer
    File "$HOME/caffe/python/caffe/pycaffe.py", line 13, in
    from ._caffe import Net, SGDSolver, NesterovSolver, AdaGradSolver, \
    ImportError: $HOME/caffe/python/caffe/_caffe.so: undefined symbol: _ZN5boost6python6detail11init_moduleER11PyModuleDefPFvvE
  • 対策
    • 以下の手順で対策を行いました。
  • (1) Python3向けのboost.pythonを有効化

    • Makefile.config内の以下の部分で、boost.python等のバージョン指定を行っている為、 当該行のコメントアウトを外します。
    # 78行目
    ## 変更前
    # PYTHON_LIBRARIES := boost_python3 python3.5m
    ## 変更後
    PYTHON_LIBRARIES := boost_python3 python3.5m

    (2) インストール済のlibboost.python, libpythonの検索とバージョンの確認

    sudo find / -name "libboost_python*"
    /usr/lib/x86_64-linux-gnu/libboost_python-py27.a
    /usr/lib/x86_64-linux-gnu/libboost_python.a
    /usr/lib/x86_64-linux-gnu/libboost_python-py35.a
    /usr/lib/x86_64-linux-gnu/libboost_python-py35.so
    ...
    /usr/lib/x86_64-linux-gnu/libboost_python-py27.so.1.58.0
    sudo find / -name "libpython3*"
    $HOME/.pyenv/versions/anaconda3-4.3.1/pkgs/python-3.6.0-0/lib/libpython3.so
    ...
    /usr/lib/python3.5/config-3.5m-x86_64-linux-gnu/libpython3.5m.so
    /usr/lib/python3.5/config-3.5m-x86_64-linux-gnu/libpython3.5.so
    /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
    /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1

    上記の出力から、libpython3.5とlibboost_python-py35.soが存在することが確認できます。

    • 対策: Makefile.configの修正
      • PYTHON_LIBRARIESにてライブラリの名称が指定されており、また、PYTHON_LIBRARIESはLIBRARY_DIRSを参照していると考えられる為、LIBRARY_DIRSに対して両ファイルが格納されているディレクトリのパス(/usr/lib/x86_64-linux-gnu)を追加しました。
    # 95行目
    ## 変更前
    LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib
    ## 変更後
    # 最後のパスはhdf5を利用する為の指定であり、今回の問題への対策とは無関係
    LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/hdf5/serial
  • ※ Makefile.configの修正箇所を極力少なくする為にlibpython3.5m.soを利用しましたが、libpython3.6m.soを利用した方が良いかもしれません。
  • (3) シンボリックリンクを張る

    ln -s /usr/lib/x86_64-linux-gnu/libboost_python-py35.so /usr/lib/x86_64-linux-gnu/libboost_python3.so
    ln -s /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0 /usr/lib/x86_64-linux-gnu/libpython3.5m.so
    ls -al /usr/lib/x86_64-linux-gnu/ | grep -E "libboost_python*|libpython*"
    lrwxrwxrwx 1 root root 23 May 9 11:18 libboost_python3.so --- libboost_python-py35.so
    ...
    lrwxrwxrwx 1 root root 46 May 9 11:22 libpython3.5m.so --- /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
    lrwxrwxrwx 1 root root 20 Nov 18 04:23 libpython3.5m.so.1 ---libpython3.5m.so.1.0
    -rw-r--r-- 1 root root 4547880 Nov 18 04:23 libpython3.5m.so.1.0

    3. dateutilに起因するSyntaxError

    import caffe
    Traceback (most recent call last):
    File "", line 1, in
    File "$HOME/caffe/python/caffe/__init__.py", line 1, in
    from .pycaffe import Net, SGDSolver, NesterovSolver, AdaGradSolver, RMSPropSolver, AdaDeltaSolver, AdamSolver, NCCL, Timer
    File "$HOME/caffe/python/caffe/pycaffe.py", line 15, in
    import caffe.io
    ...
    import matplotlib.dates as File "$HOME/.pyenv/versions/anaconda3-4.3.1/lib/python3.6/site-packages/matplotlib/dates.py", line 125, in
    from dateutil.rrule import (rrule, MO, TU, WE, TH, FR, SA, SU, YEARLY,
    File "$HOME/.pyenv/versions/anaconda3-4.3.1/lib/python3.6/site-packages/dateutil/rrule.py", line 55
    raise ValueError, "Can't create weekday with n == 0"
    ^
    SyntaxError: invalid syntax
    • 原因
      • Anacondaに含まれるmatplotlibライブラリに起因する問題
        • Caffeがmatplotlibに依存しており、また、そのmatplotlibがimportしているdateutilのバージョンが古い為に発生していると見られます。
  • 対策
    • 下記の通り、dateutilを更新することで解消しました。
  • pip install python-dateutil --upgrade

    その他雑記

    • makeを叩く際には以下のように呼び出すのがおすすめです。
    make all -B -j8
    # オプションの説明
    # -B: 丸々リビルドし直す(事前にmake cleanしておけば特に指定する必要はなし)
    # -j8: 8並列でmakeの処理を実行する(任意の数を指定可能、CPUのコア数に合わせるように指定すると処理が速い)

    まとめ

    • 細かなところで手こずりましたが、何とかPython3.6からCaffeを呼び出せるようになりました。 g2.2xlargeインスタンスと比べ、どれほど学習が速くなるかを検証してみようと思います。