ABCIで環境構築してMaskTrackRCNNを動かすまで

## 概要
最新のVideo Instance Segmentationタスクのベースラインとなっているモデルである[MaskTrackRCNN](https://github.com/youtubevos/MaskTrackRCNN)を[ABCI](https://abci.ai/ja/)で動かそうとした際に、度重なるエラーに悩まされたので、ABCIにおける環境構築からモデルの学習までの方法を備忘録として残しておきます。
最後に格闘したエラーとその解決方法をまとめて残しておきました。

## 前提
- 2021/01/15 時点の情報である。
- ABCIのアカウントを持っており、サーバにリモートアクセスできる。
- anaconda3を導入済である。

## 環境構築
- ABCIにsshでリモートアクセス
- GPUノードの起動
    以下はGPUを最小構成で最大1時間インタラクティブに利用するコマンド。

    ```bash
    qrsh -g gcc50560 -l rt_G.small=1 -l h_rt=1:00:00 -m abes
    ```

- 必要なモジュールのロード
    立ち上げたノードで以下のコマンドを実行し、必要なモジュールをロードしておく。

    ```bash
    module load cuda/9.0
    module load cudnn/7.6/7.6.2
    module load nccl/2.3/2.3.7-1
    ```

- 仮想環境の作成とセットアップ
    以下の`bash masktrackrcnn_env.sh` を実行してレポジトリのクローン、仮想環境構築を行う。

    ```masktrackrcnn_env.sh
    # clone MaskTrackRCNN
    git clone https://github.com/youtubevos/MaskTrackRCNN.git
    cd MaskTrackRCNN
    
    # create environment
    conda create -n MaskTrackRCNN python=3.7 -y
    
    # >>> conda init >>>
    __conda_setup="$(CONDA_REPORT_ERRORS=false '$HOME/anaconda3/bin/conda' shell.bash hook 2> /dev/null)"
    if [ $? -eq 0 ]; then
        \eval "$__conda_setup"
    else
        if [ -f "$HOME/anaconda3/etc/profile.d/conda.sh" ]; then
            . "$HOME/anaconda3/etc/profile.d/conda.sh"
            CONDA_CHANGEPS1=false conda activate base
        else
            \export PATH="$PATH:$HOME/anaconda3/bin"
        fi
    fi
    unset __conda_setup
    # <<< conda init <<<
    
    # activate environment
    conda activate MaskTrackRCNN
    
    # setup environment
    conda install -c pytorch pytorch=0.4.1 cudatoolkit=9.0 torchvision -y
    conda install -c conda-forge  opencv -y
    conda install numpy cython -y
    conda install -c psi4 gcc-5 -y
    conda install libgcc -y
    pip install git+https://github.com/youtubevos/cocoapi.git#"egg=pycocotools&subdirectory=PythonAPI"
    bash compile.sh
    pip install . --user
    
    pip uninstall mmcv -y
    pip install mmcv==0.2.0
    ```

- ライブラリの修正
    ここまでで必要な環境は整ったが、このままでは学習時に[不都合](#mmcv)があるので最後に一つ修正を加える。
[python_lib_path]/site-packages/mmcv/runner/checkpoint.py の39行目を以下に変更する。
※ [python_lib_path] には、`which python`が返すパスを入れれば良い。

    ```checkpoint.py
    print('While copying the parameter named {}, '
          'whose dimensions in the model are {} and '
          'whose dimensions in the checkpoint are {}.'
          .format(name, own_state[name].size(),
                  param.size()))
    ```

- 環境構築完了!!
## データセットの準備
- データとラベルのダウンロード
    [ここ](https://youtube-vos.org/dataset/vis/)からデータとラベルをダウンロードしておく。
- データセットの配置
    以下の構成になるようにシンボリックリンクを貼る。

    ```
    MaskTrackRCNN
    ├── mmdet
    ├── tools
    ├── configs
    ├── data
    │   ├── train
    │   ├── val
    │   ├── annotations
    │   │   ├── instances_train_sub.json
    │   │   ├── instances_val_sub.json
    ``` 

    ラベルは元々`train.json`, `valid.json`というファイル名で与えられるので、（コピーして）改名しておくと良い。configのファイル名を変更しても良い。

    ```sh
    # シンボリックリンクの貼り方の一例 $MaskTrackRCNN は MaskTrackRCNNレポジトリのルートまでのパス
    mkdir $MaskTrackRCNN/data
    ln -s /path/to/original/data_dir/train $MaskTrackRCNN/data/train
    ln -s /path/to/original/data_dir/valid $MaskTrackRCNN/data/val
    ln -s /path/to/original/data_dir/annotations $MaskTrackRCNN/data/annotations
    ```

## モデルの学習
- GCC7.4のロード
    `module load gcc/7.4.0`
- 仮想環境のアクティベート
    `conda activate MaskTrackRCNN`
- いざ学習
    `python tools/train.py configs/masktrack_rcnn_r50_fpn_1x_youtubevos.py`
    以下のようなログが出ていれば正しく学習されていると思われます。このままだと学習に24時間くらいかかりそうですが。

    ```
    2021-01-15 13:36:50,620 - INFO - Epoch [1][50/7669]	   lr: 0.00199, time: 0.774, data_time: 0.045, loss_rpn_cls: 0.0609, loss_rpn_reg: 0.0465, loss_cls: 0.9336, acc: 84.5996, loss_reg: 0.2753, loss_match: 0.4937, match_acc: 89.2641, loss_mask: 0.7734, loss: 2.5835
    2021-01-15 13:37:27,818 - INFO - Epoch [1][100/7669]	lr: 0.00233, time: 0.744, data_time: 0.028, loss_rpn_cls: 0.0469, loss_rpn_reg: 0.0442, loss_cls: 0.7820, acc: 84.7695, loss_reg: 0.3567, loss_match: 0.2895, match_acc: 88.3957, loss_mask: 0.6092, loss: 2.1286
    2021-01-15 13:38:04,878 - INFO - Epoch [1][150/7669]	lr: 0.00266, time: 0.741, data_time: 0.026, loss_rpn_cls: 0.0342, loss_rpn_reg: 0.0342, loss_cls: 0.7171, acc: 85.1309, loss_reg: 0.3467, loss_match: 0.2588, match_acc: 89.5726, loss_mask: 0.5057, loss: 1.8968
    ```

    configs/masktrack_rcnn_r50_fpn_1x_youtubevos.py をいじればエポック数等学習のハイパーパラメータを変更できそうです。

## 格闘したエラーまとめ

- #### unable to execute 'nvcc': No such file or directory
    実行コマンド：`bash masktrackrcnn_env.sh`
    原因：cuda のロードがうまくできていない
    解決方法：`module load cuda/{version}` を実行すれば解決するはず。シェルスクリプト(masktrackrcnn_env.sh)中にこのコマンドを書いてもうまくいかなかったが、普通にシェルで実行したらうまくいった。

- #### AttributeError:module 'torch.nn' has no attribute 'SyncBatchNorm
    実行コマンド：  `python tools/train.py configs/masktrack_rcnn_r50_fpn_1x_youtubevos.py`（学習用スクリプト）
    原因：torchのversionが1.1未満（でも著者はversion0.4.1で実行しているはず。）
    解決方法：mmcvのバージョンを0.2.0に下げる。

    ```
    pip uninstall mmcv
    pip install mmcv==0.2.0
    ```

    ```エラー詳細
    Traceback (most recent call last):
      File "tools/train.py", line 4, in <module>
        from mmcv import Config
      File "/home/acb11854zq/.local/lib/python3.7/site-packages/mmcv/__init__.py", line 4, in <module>
        from .fileio import *
      File "/home/acb11854zq/.local/lib/python3.7/site-packages/mmcv/fileio/__init__.py", line 4, in <module>
        from .io import dump, load, register_handler
      File "/home/acb11854zq/.local/lib/python3.7/site-packages/mmcv/fileio/io.py", line 4, in <module>
        from ..utils import is_list_of, is_str
      File "/home/acb11854zq/.local/lib/python3.7/site-packages/mmcv/utils/__init__.py", line 29, in <module>
        from .env import collect_env
      File "/home/acb11854zq/.local/lib/python3.7/site-packages/mmcv/utils/env.py", line 12, in <module>
        from .parrots_wrapper import get_build_config
      File "/home/acb11854zq/.local/lib/python3.7/site-packages/mmcv/utils/parrots_wrapper.py", line 79, in <module>
        _BatchNorm, _InstanceNorm, SyncBatchNorm_ = _get_norm()
      File "/home/acb11854zq/.local/lib/python3.7/site-packages/mmcv/utils/parrots_wrapper.py", line 71, in _get_norm
        SyncBatchNorm_ = torch.nn.SyncBatchNorm
    AttributeError: module 'torch.nn' has no attribute 'SyncBatchNorm'
    ```

<a id="gcc"></a>

- #### ImportError: /home/acb11854zq/.local/lib/python3.7/site-packages/mmdet/ops/nms/gpu_nms.cpython-37m-x86_64-linux-gnu.so: undefined symbol: __cudaPopCallConfiguration

    実行コマンド：`python tools/train.py configs/masktrack_rcnn_r50_fpn_1x_youtubevos.py`
    原因：ビルド時のCUDAのバージョン
    解決方法：ビルド時にCUDA9.2 -> CUDA9.0にすれば直る ([source](https://github.com/jwyang/faster-rcnn.pytorch/issues/190)) 。この時、CUDA9.0はGCC<6.0を要求することに注意。

<a id="mmcv"></a>

- #### RuntimeError: While copying the parameter named bbox_head.fc_cls.weight, whose dimensions in the model are torch.Size([41, 1024]) and whose dimensions in the checkpoint are torch.Size([81, 1024]).
    実行コマンド：`python tools/train.py configs/masktrack_rcnn_r50_fpn_1x_youtubevos.py`
    原因：モデルの`bbox_head.fc_cls.weight`の次元がチェックポイントのモデルのそれと違う。
    解決方法：[python_lib_path]/site-packages/mmcv/runner/checkpoint.py の39行目を以下に変更する（[参考１](https://github.com/youtubevos/MaskTrackRCNN/issues/1)、[参考２](http://carina.cse.lehigh.edu/MaskTrackRCNN-Lihao/installation.html)）。

    ```checkpoint.py
    print('While copying the parameter named {}, '
          'whose dimensions in the model are {} and '
          'whose dimensions in the checkpoint are {}.'
          .format(name, own_state[name].size(),
                  param.size()))
    ```

- #### Segmentation fault

    実行コマンド：`python tools/train.py configs/masktrack_rcnn_r50_fpn_1x_youtubevos.py`
    原因：[issue](https://github.com/youtubevos/MaskTrackRCNN/issues/22)に依るとbuild時にGCC<4.9.2だったことが問題らしい。
    解決方法：`conda install -c psi4 gcc-5`conda に gcc を入れる([source](https://gist.github.com/goldsborough/d466f43e8ffc948ff92de7486c5216d6))。というのも、[これ](#gcc)の解決方法と矛盾しないように、4.9.2<=GCC<6.0 を使いたいけどABCIにその選択肢がない 。
        結果：ビルドには成功しているのでおそらくSegmentation faultの問題は解決できているが、新たにopencvの[import error](#cv2_conda)が出ている。

<a id="cv2_conda"></a>

- #### ImportError: /home/acb11854zq/anaconda3/envs/test_gcc/bin/../lib/libstdc++.so.6: version `GLIBCXX_3.4.22' not found (required by /home/acb11854zq/.local/lib/python3.7/site-packages/cv2/cv2.cpython-37m-x86_64-linux-gnu.so)

    実行コマンド：`python tools/train.py configs/masktrack_rcnn_r50_fpn_1x_youtubevos.py`
    原因：condaのlibstdc++のバージョンが低い?
    解決方法： `conda install libgcc` でとりあえずこの問題は解決するっぽいが、今度はシステムのlibstdc++に関して[import error](#cv2_system)が出る。

    ```エラー詳細
    Traceback (most recent call last):
      File "tools/train.py", line 4, in <module>
        from mmcv import Config
      File "/home/acb11854zq/anaconda3/envs/test_gcc/lib/python3.7/site-packages/mmcv/__init__.py", line 5, in <module>
        from .opencv_info import *
      File "/home/acb11854zq/anaconda3/envs/test_gcc/lib/python3.7/site-packages/mmcv/opencv_info.py", line 1, in <module>
        import cv2
      File "/home/acb11854zq/.local/lib/python3.7/site-packages/cv2/__init__.py", line 5, in <module>
        from .cv2 import *
    ImportError: /home/acb11854zq/anaconda3/envs/test_gcc/bin/../lib/libstdc++.so.6: version `GLIBCXX_3.4.22' not found (required by /home/acb11854zq/.local/lib/python3.7/site-packages/cv2/cv2.cpython-37m-x86_64-linux-gnu.so)
    ```

<a id="cv2_system"></a>

- #### ImportError: /lib64/libstdc++.so.6: version `CXXABI_1.3.8' not found (required by /home/acb11854zq/.local/lib/python3.7/site-packages/cv2/cv2.cpython-37m-x86_64-linux-gnu.so)

    実行コマンド：`python tools/train.py configs/masktrack_rcnn_r50_fpn_1x_youtubevos.py`
    原因：おそらくシステムのlibstdc++が古い？ CXXABI_1.3.8はどうやらGCC4.9から導入されている。
    解決方法：モデルの学習時に`module load gcc/7.4.0`としてシステムにGCC7.4をロードすることで無理矢理解消できる。`bash compile.sh`によるビルドが終わってからでないとビルド時に[エラー](#gcc)が出るので注意。

   ```エラー詳細
   Traceback (most recent call last):
      File "tools/train.py", line 4, in <module>
        from mmcv import Config
      File "/home/acb11854zq/.local/lib/python3.7/site-packages/mmcv/__init__.py", line 5, in <module>
        from .image import *
      File "/home/acb11854zq/.local/lib/python3.7/site-packages/mmcv/image/__init__.py", line 2, in <module>
        from .colorspace import (bgr2gray, bgr2hls, bgr2hsv, bgr2rgb, bgr2ycbcr,
      File "/home/acb11854zq/.local/lib/python3.7/site-packages/mmcv/image/colorspace.py", line 2, in <module>
        import cv2
      File "/home/acb11854zq/.local/lib/python3.7/site-packages/cv2/__init__.py", line 5, in <module>
        from .cv2 import *
    ImportError: /lib64/libstdc++.so.6: version `CXXABI_1.3.8' not found (required by /home/acb11854zq/.local/lib/python3.7/site-packages/cv2/cv2.cpython-37m-x86_64-linux-gnu.so)
   ```