pytorch を ROCm でコンパイルにチャレンジします.
2018 年 7 月 27 日時点まとめ
乱数ライブラリ(hcrng)の対応が過渡期のためか, いろいろ頑張ってコンパイルはできても, strace で確認すると乱数ライブラリを呼ぶところで seg fault することがわかりました.
しばらく様子見ですね.
https://github.com/ROCmSoftwarePlatform/pytorch/pull/41
https://github.com/ROCmSoftwarePlatform/pytorch/pull/80
以下, メモ...
Ubuntu 16.04 + ROCm 1.8.2 で環境を整えているものとします.
途中まではうまく行きますが, caffe2/proto/caffe2.pb.h
ヘッダが見つからないというエラーがでて, うんうんと悩んで原因調べてみたところ, CMake generator expression の挙動でうまくコンパイルできないことがわかりました.
pytorch repo の cmake/Dependency.cmake
で
set(Caffe2_HIP_INCLUDES
${hip_INCLUDE_DIRS} ${hcc_INCLUDE_DIRS} ${hsa_INCLUDE_DIRS} ${rocrand_INCLUDE_DIRS} ${hiprand_INCLUDE_DIRS} ${rocblas_INCLUDE_DIRS} ${miopen_INCLUDE_DIRS} ${thrust_INCLUDE_DIRS} $<INSTALL_INTERFACE:include> ${Caffe2_HIP_INCLUDES})
というのがあります.
ここの $<INSTALL_INTERFACE:include>
は CMake generator expression であり,
基本的には特定の cmake コマンド(e.g. target_include_directories
)でしか値が展開できないようになっています(他の環境では値が展開されません(要検証))
pytorch rocm ポートでは, HIP でコンパイルするために, hip_include_directories() に include path を渡し, それを外部コマンドへの引数に渡しているため, ここで問題があります.
apt で入る HIP(/opt/rocm/hip
) はいくらか古いため, opt/rocm/hip/cmake/FindHIP.cmake
において, hip_include_directories
の定義は以下のようになっています.
macro(HIP_INCLUDE_DIRECTORIES)
foreach(dir ${ARGN})
list(APPEND HIP_HIPCC_INCLUDE_ARGS_USER -I${dir})
endforeach()
endmacro()
generator script は展開されると空文字になるため(要検証), これだと
-I$<INSTALL_INTERFACE:include> -I/path/to/protobuf/src
となり, これが展開されて HIP コンパイラには以下が渡ります.
-I -I/path/to/protobuf/src
ここで, gcc/clang では, 空の -I
があると, 後続の -I/path/to/protobuf/src
をサーチパスとして認識する挙動になっているため, これにより /path/to/protobuf/src
にパスが通らずにコンパイルが失敗します.
では, Caffe2_HIP_INCLUDES
から $<INSTALL_INTERFACE:include>
を除けばいいのかといういうと, 実際には gloo や gtest などの submodule でも include path に $<INSTALL_INTERFACE:include>
を使うような cmake 記述があり, pytorch/caffe2 ではこれらの変数も参照していますから, FindHIP をやはり修正しないとダメです.
最新の FindHIP.cmake をみますと
list(APPEND HIP_HIPCC_INCLUDE_ARGS_USER $<$<BOOL:${dir}>:-I${dir}>)
となり, この generator expression による空の -I
問題が解決されています.
pytorch の Docker + Jenkins ビルドスクリプトでは, そのための work around の記述があります.
build cofiguration についても修正がありますね.
(2018 年 7 月 27 日時点, ここまで)
以下, 作業メモ...
環境
- (mini)conda
- その他, で apt や pip パッケージを入れているとします
Docker 用のビルドスクリプト
を参考にします.
pytorch 本家での CI サーバのビルド状態も確認しておきましょう.
py2-clang3.8-rocmnightly-ubuntu16.04-test など, rocmnightly の文字があるターゲットになります.
hipblas https://github.com/ROCmSoftwarePlatform/hipBLAS を入れます.
$ sudo apt-get install hipblas
ROCm(HIP)版 Thrust をインストールします.
apt package は無いので git clone. /opt/rocm/Thrust にインストールするものとします. Thrust はヘッダファイル集なのでビルドは不要です.
cub-hip が submodule になっているので, 忘れずに submodule も checkout しておきます.
$ git clone --recursive https://github.com/ROCmSoftwarePlatform/Thrust
$ sudo mv Thrust /opt/rocm/
を clone します.
$ git clone --recursive https://github.com/ROCmSoftwarePlatform/pytorch pytorch-rocm
(pytorch オフィシャルの repo だと, hcrnd, hcsparse が見つからないとエラーがでま)
python の環境を作ります. 今回は 3.6 にしました.
$ conda create -n py36 python=3.6
$ source activate py36
前処理として, hippify(CUDA コードの HIP 化?)をします.
(py27) $ cd pytorch-rocm
(py27) $ python tools/amd_build/build_pytorch_amd.py
1 分くらいかかりますのでしばらく待ちます(プログレスが出ないので少し不安になります)
一度実行していると, すでに patch が当たっていて fail するなどのエラーが出ます(変換自体には影響無い模様) 再実行するときは一度 git checkout しておくとよいかもしれません.
ROCm を on にしてビルドします.
USE_ROCM=1 を指定しないと, caffe2 自体は ROCm(HIP) 環境が見つかれば ROCm(HIP) 有効でビルドされますが, python binding のほうが ROCm 有効にならず, torch.cuda.is_available()
が false になってしまうので注意ください.
$ USE_ROCM=1 python setup.py install
libcaffe2_hip.so
のリンクにめちゃめちゃ時間がかかります. Ryzen2700X で 10~20 分くらい.
(ROCm clang opt
で最適化しているようですが, その最適化処理に時間がかかっています)
再ビルドでもなぜか hip カーネル周り再コンパイルになってつらい(hipcc を外部コマンドで呼び出すところはキャッシュされないから?)
setup_caffe2.py もありますが, これは少なくとも ROCm ビルドでは setup.py
から呼ばれるのを想定するようで, setup_caffe2.py で caffe2 だけビルドしようとしてもうまくいきませんでした.
実行時セットアップ
libcaffe2_hip.so は HIP clang でコンパイルされていますが, libcxx
がデフォルトになっているようで, import torch
とすると,
ImportError: libc++.so.1: cannot open shared object file: No such file or directory
と出ます...
libc++.so
は rocm パッケージ(prebult HIP パッケージ)に含まれていないので, 自前ビルドします...
(もしかしたら llvm.org で配布している prebuilt package でも動くかもしれません)
ROCm 1.8.2 の hcc では clang 7(ToT, top of trunk) ですが, 6.0.1 release でも大丈夫のようです.
libcxx, libcxxabi をインストールしておきます.
(default の /usr/local に install すると仮定. clang++/clang は hcc の clang++(e.g. /opt/rocm/hcc/clang++) を仮定)
$ cd libcxx
$ mkdir build
$ cd build
$ CXX=clang++ CC=clang cmake ..
$ make
$ (sudo) make install
$ cd libcxxabi
$ mkdir build
$ cd build
$ CXX=clang++ CC=clang cmake -DLIBCXXABI_LIBCXX_INCLUDES=/usr/local/include/c++/v1 ..
$ make
$ (sudo) make install
インストールした先の lib ディレクトリを LD_LIBRARY_PATH
に設定しておきます.
import torch
torch.cuda.is_available()
で True が返れば成功です!
TODO
pytorch の ROCm ビルド手順ドキュメントが無くてかなしい.
(web とか Jenkins CI のスクリプトを見るしかない)
の ThinLTO でリンクが早くなるかしら?
export KMTHINLTO=1