高精度な物体検出器SNIPER+MXNetの環境構築

## はじめに

高精度な物体検出器のSoTA[^1]の1つとしてSNIPERがあります。
[^1]: 様々なテクニックが併用されているにも関わらず、単にベンチマークでトップ精度を達成しているものがstate-of-the-artと呼ばれ崇め奉られることの是非はさておき、ベースとして用いる実装の候補としては良いでしょう。

SNIPER: Efficient Multi-Scale Training [Bharat Singh+, NeurIPS2018] https://arxiv.org/abs/1805.09300

コードも公開されている( https://github.com/mahyarnajibi/SNIPER )のですが、フレームワークがMXNetな上、ビルド済みMXNetが使えず環境構築に難儀します。そこで本記事では、github上の最新のMXNetとSNIPERをマージして使用する際の環境構築手順をまとめます。不正確な部分もあるかと思いますが、一から調べて環境構築するよりかは辛みが軽減されると思いますのでご容赦下さい。

* 注意事項：
  * **SNIPERはPython 2.7**で実行[^2]して下さい。
  * 本記事では Ubuntu 18.04, CUDA 10.0 の使用を想定[^3]しております。バージョンの差異によって動作しなくなるかと思いますので、適宜リンク先をご参照下さい。
  * MXNetではCUDA 9.2が推奨されているため、MXNetのバグを踏みたくない場合はCUDA 9.2の方が良いかもしれません。
  * 各ライブラリについてはライセンスを読んだ上でご自身の責任でご使用下さい。

[^2]: [Deformable Convolutional Networks](https://github.com/msracver/Deformable-ConvNets)のコードがベースとなっているためかと思います。
[^3]: GCE の ubuntu-1804-bionic-v20181222 で検証しています。なお、colab上でもSNIPERの訓練・評価は可能です（特定のバージョンのCUDAが最初から入っていることが、本記事の内容との主な違いです）。


## Prerequisites
MXNetに必要なライブラリを事前にインストールします。環境によって、またMXNetのビルド設定によって不要なものもあるため、以下は一例です。condaは必須ではないですが、Python 2 と 3 を切り替えやすくする手段は用意した方が良いと思います。

```bash
# Install CUDA 10.0 to Ubuntu 18.04
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-repo-ubuntu1804_10.0.130-1_amd64.deb
sudo dpkg -i cuda-repo-ubuntu1804_10.0.130-1_amd64.deb
sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub
sudo apt-get update
sudo apt-get install -y cuda
rm cuda-repo-ubuntu1804_10.0.130-1_amd64.deb
echo 'export PATH=/usr/local/cuda/bin:${PATH}' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=/usr/local/cuda/lib64:${LD_LIBRARY_PATH}' >> ~/.bashrc
source ~/.bashrc

# Install cuDNN
wget http://developer.download.nvidia.com/compute/redist/cudnn/v7.4.1/cudnn-10.0-linux-x64-v7.4.1.5.tgz
tar -xf cudnn-10.0-linux-x64-v7.4.1.5.tgz
sudo cp -a cuda/lib64/* /usr/local/cuda/lib64/
sudo cp -a cuda/include/* /usr/local/cuda/include/
sudo ldconfig
sudo rm -r cuda cudnn-10.0-linux-x64-v7.4.1.5.tgz

# Install mkl
# TODO: try to run https://github.com/apache/incubator-mxnet/blob/master/ci/docker/install/ubuntu_mkl.sh
wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB
sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB
sudo wget https://apt.repos.intel.com/setup/intelproducts.list -O /etc/apt/sources.list.d/intelproducts.list
sudo apt-get update
sudo apt-get install -y intel-mkl-2019.1-053
rm GPG-PUB-KEY-INTEL-SW-PRODUCTS-2019.PUB

# Install NCCL
# See https://qiita.com/pst-ic/items/e01033dee4d389df3a5e
# TODO: Validating NCCL https://mxnet.incubator.apache.org/versions/master/install/build_from_source.html#validating-nccl
git clone https://github.com/NVIDIA/nccl.git
cd nccl
make -j
sudo mkdir /usr/local/nccl
sudo make PREFIX=/usr/local/nccl install -j
cd ../
sudo rm -r nccl
echo 'export NCCL_ROOT="/usr/local/nccl"' >> ~/.bashrc
echo 'export CPATH="$NCCL_ROOT/include:$CPATH"' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH="$NCCL_ROOT/lib/:$LD_LIBRARY_PATH"' >> ~/.bashrc
echo 'export LIBRARY_PATH="$NCCL_ROOT/lib/:$LIBRARY_PATH"' >> ~/.bashrc
source ~/.bashrc

# Install miniconda
wget https://repo.anaconda.com/miniconda/Miniconda2-latest-Linux-x86_64.sh
bash Miniconda2-latest-Linux-x86_64.sh -b
echo 'export PATH="$HOME/miniconda2/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
rm Miniconda2-latest-Linux-x86_64.sh 

sudo reboot
```


## Install MXNet
MXNetの最新版にSNIPER用のoperatorをマージした上でMXNetをビルドします。古き良きCaffeの時代を彷彿とさせますね。ビルドに時間がかかる時はmake coffeeしながら気長に待ちましょう。

```bash
# merge incubator-mxnet and SNIPER-mxnet
mkdir work
cd work
git clone --recursive https://github.com/apache/incubator-mxnet.git
git clone --recursive https://github.com/mahyarnajibi/SNIPER.git
# remove conflicting files. See https://github.com/mahyarnajibi/SNIPER-mxnet/commit/d640d3e92fb54daaf2eb427f3fcb5683ab60a005
rm incubator-mxnet/src/operator/contrib/multi_proposal* incubator-mxnet/src/operator/contrib/proposal*
# copy operators for SNIPER. See https://github.com/mahyarnajibi/SNIPER/issues/9
cp SNIPER/SNIPER-mxnet/src/operator/multi_proposal* incubator-mxnet/src/operator/

# Build MXNet from Source
# See https://mxnet.incubator.apache.org/versions/master/install/ubuntu_setup.html
#     https://mxnet.incubator.apache.org/versions/master/install/build_from_source.html
#	  https://github.com/apache/incubator-mxnet/blob/master/ci/docker/install/ubuntu_python.sh
sudo bash incubator-mxnet/ci/docker/install/ubuntu_core.sh 
conda install numpy=1.15.2
pip install nose cpplint==1.3.0 pylint==1.9.3 nose-timer 'requests<2.19.0,>=2.18.4' h5py==2.8.0rc1 scipy==1.0.1 boto3

cd incubator-mxnet/
make -j $(nproc) USE_OPENCV=1 USE_LAPACK=1 USE_MKLDNN=1 USE_BLAS=mkl USE_CUDA=1 USE_CUDA_PATH=/usr/local/cuda USE_CUDNN=1 USE_NCCL=1 USE_NCCL_PATH=/usr/local/nccl

# https://mxnet.incubator.apache.org/install/ubuntu_setup.html
cd python
pip install -e .

# change path of MXNet in SNIPER/init.py
cd
cd work/SNIPER/
echo "import sys" > init.py
echo "sys.path.insert(0, 'lib')" >> init.py
echo "sys.path.insert(0, '../incubator-mxnet/python')" >> init.py
```


# Install SNIPER
ここまで来れば https://github.com/mahyarnajibi/SNIPER に従って動かせるかと思います。

```bash

pip install -r requirements.txt
bash scripts/compile.sh

echo 'export LD_LIBRARY_PATH="$HOME/work/incubator-mxnet/lib:${LD_LIBRARY_PATH}"' >> ~/.bashrc
source ~/.bashrc

# Running the demo
bash scripts/download_sniper_detector.sh
python demo.py
```

お疲れ様でした。