この３D物体検出動くぞ...! PointPillarsの訓練から評価まで

今回は、自動運転にも使えるPointPillarsを実際に動かして訓練から評価までをやっていきます。
自動運転のこと知りたい人はフォロー、Likeお願いします！

PointPillarsって何？
３D点群から物体を高速で検出するネットワークのこと、詳細はこちらへ！
[PointPillars論文解説](https://qiita.com/chin_self_driving_car/items/362772f5078c0cbe4c0d)

この記事では、こんな質問に答えていくぞ！

* PointPillarsを訓練するデータセットはどうやって揃える！？
* PointPillarsを動かすのに必要なパッケージは？
* 学習の設定はどのように変える？
* 訓練結果はどのように出力される？

![Screenshot from 2019-10-04 10-45-50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388647/c8c3fec0-3575-e21d-fa2c-e707d0452c1b.png)



## この記事ですること
* PointPillarsで訓練と評価
    * データセットの用意
    * 必要なパッケージインストール
    * PointPillarsの準備
    * 訓練開始！
    * 評価

※github repoを参考にしながら、補足、エラーの出る箇所の対策をしていきます

論文リンク　発表は2018年末
[PointPillars: Fast Encoders for Object Detection from Point Clouds](https://arxiv.org/abs/1812.05784)

使用するgithub repo：
下記２つを使います。多機能版を中心に足りないところはオリジナルの情報を使いながら補足します。
[nutonomy/second.pytorch(オリジナル)](https://github.com/nutonomy/second.pytorch)
[traveller59/second.pytorch(多機能版)](https://github.com/traveller59/second.pytorch)

## データセットの用意

PointPillarsはもともとKITTIデータセットを読み込んで訓練、評価できるように作られているので(作者神...)
下記のようにKITTIデータセットを用意する。

```bash
└── KITTI_DATASET_ROOT
       ├── training    <-- 7481 train data
       |   ├── image_2 <-- for visualization
       |   ├── calib
       |   ├── label_2
       |   ├── velodyne
       |   └── velodyne_reduced <-- empty directory
       └── testing     <-- 7580 test data
           ├── image_2 <-- for visualization
           ├── calib
           ├── velodyne
           └── velodyne_reduced <-- empty directory
```

はて...? KITTIデータセットにこんなデータがあるのだろうか？ image_2. label_2ってなんなんだ...
そういえば論文では3D Object Detectionのランキングに言及していたので、そのデータをダウンロードすればいいのかな...?
![Screenshot from 2019-10-27 20-46-37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388647/5f8734ea-73ff-259c-7ae9-583a20478edf.png)


どれをダウンロードすればいいのやら、しかもどれも大量のギガを消費する...!
燃える自動運転エンジニア、バッチリダウンロードしました（自宅回線爆死）

[ダウンロードリンク]
http://www.cvlibs.net/datasets/kitti/eval_object.php?obj_benchmark=3d

ダウンロードしなくてはならないものが上図でハイライトしている:

1. Left Color images of object data set(12GB)
2. Velodyne point clouds(29GB)
3. camera calibration matrices(16MB)
4. training labels of object data set(5MB)

これだけ知っておけば、無駄なダウンロードはしなくてすむ。
それぞれ解凍すると、training, testingと別れており、あとは指示通りフォルダを構成すれば完了

## 必要なパッケージインストール

では、実際にPointpillarsを動かすために必要なパッケージは下記でまとめてインストール

```bash
pip install shapely pybind11 protobuf scikit-image numba pillow scipy matplotlib
conda install pytorch torchvision -c pytorch
conda install google-sparsehash -c bioconda
pip install fire tensorboardX protobuf opencv-python
pip install --upgrade pip
```
### numbaのパス設定

上でインストールしたnumbaを使えるようにしておく。

```bash
export NUMBAPRO_CUDA_DRIVER=/usr/lib/x86_64-linux-gnu/libcuda.so
export NUMBAPRO_NVVM=/usr/local/cuda/nvvm/lib64/libnvvm.so
export NUMBAPRO_LIBDEVICE=/usr/local/cuda/nvvm/libdevice
```


### sparseconvnetのインストール

次に、sparseconvnetのインストール
PointpillarsはSECONDというPointNetを使用したネットワークをベースに作られている。
そしてSECONDはsparseconvnetという別のネットワークをバックボーンに使っているので、こちらも入れる必要がある。

どうやら本家sparseconvnetはfacebookが作ったネットワークのようで下記URLからgit cloneできる、が
https://github.com/facebookresearch/SparseConvNet
が、動かすことが出来なかった。

なので、[nutonomy/second.pytorch(多機能版)](https://github.com/traveller59/second.pytorch)でも推奨している、[spconv](https://github.com/traveller59/spconv)を使用する。spconvは本家の軽量化版らしい。

では入れていこう。
このrepoでは、whlファイルをcmakeで生成し、それをpip installする手順をたどる。
つまり、pipパッケージで　spconvが最終的にインストールされるイメージ。


```bash
git clone https://github.com/traveller59/spconv --recursive
```
ここで滅茶苦茶大事なのは、recursiveを忘れないこと。このrepoはサードパーティであるpybindがサブモジュールになっているので、recursive指定しないと、それらがクローンできずにエラーが出る。

そして、cmake>=3.13.2以上であることを確認しよう。バージョンが足りなければ自分でアップデートすること。

```bash
cmake --version
```

```bash
cd spconv
python setup.py bdist_wheel
cd ./dist
pip install spconv-1.1-cp36-cp36m-linux_x86_64.whl  #生成されたwhlファイルの名前
```

これで必要なパッケージのインストールは全て終わった。


## PointPillarsの準備
それでは、PointPillarsのrepoを入れて、訓練の準備をしていく。

今回使うのは、オリジナル版ではなく、多機能版を使う。

理由としては下記の２つ：

* オリジナル版ではsparseconvnetを使うが、ビルドが出来ない。spconvがビルドできる多機能版を使用する
* 多機能版では、car, cyclist, pedestrianの3種類の認識が同時にできる。オリジナルでは片方ずつのコンフィグファイルしか存在しない。


```bash
git clone https://github.com/traveller59/second.pytorch.git
cd ./second.pytorch/second
```

###パスを通す
SECOND, Pointpillarsで使用する関数を呼べるようにPYTHONPATHを設定する
bashrcに書き込む

```bash
gedit ~/.bashrc
```

```bash
#書き込み内容
PYTHONPATH=/home/hakusho/testrepo/pointpillars_traveller59/second.pytorch:$PYTHONPATH
export PYTHONPATH
```

### データローダの準備
PointPillarsの訓練＆評価には、KITTIデータセットを使う。
KITTIデータセットのパスをPointPillarsに伝える必要がある。

```bash
python create_data.py kitti_data_prep --root_path=KITTI_DATASET_ROOT
#KITTI_DATASET_ROOTは先程準備したフォルダになる
```

これで何ができるのかというと、下図のハイライトされたフォルダとファイルが生成される。
訓練、評価用のファイルリストを示すpklファイルと、真値のデータベース
![Screenshot from 2019-10-27 20-59-26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388647/21f16554-6485-893b-0c01-61c5484f1393.png)

ん、gt_database, 真値のデータベースってなんぞや？
前回の論文紹介でも話した、data augmentation時に使われる。
あるワンシーンの点群に、別シーンの物体データを召喚する！ときに使うもの。
車、歩行者などだけが切り取られて、物体点群図鑑のようなものがこのフォルダで生成されている。

### configファイルの設定

訓練時の設定ファイルを編集する。
repoを覗くと、configファイルが下記のように複数個ある。
今回使うのは、configs/pointpillars/pp_pretrain.config、これを編集していこう。
![Screenshot from 2019-11-03 10-06-23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388647/d501a51c-e280-191b-d443-4885e4f029f9.png)

pp_pretrain.configは前述の3クラス(car, pedestrian, cyclist)の物体すべてを読み込んで訓練する。
目的のファイル以外のconfigは変更の必要がない。
必要な変更点は下記の青字。それぞれ対応するファイル、フォルダのパスを更新しよう。



```bash
train_input_reader: {
  ...
  database_sampler {
    database_info_path: "/path/to/dataset_dbinfos_train.pkl" 
    ...
  }
  dataset: {
    dataset_class_name: "DATASET_NAME"
    kitti_info_path: "/path/to/dataset_infos_train.pkl"
    kitti_root_path: "DATASET_ROOT"
  }
}
...
eval_input_reader: {
  ...
  dataset: {
    dataset_class_name: "DATASET_NAME"
    kitti_info_path: "/path/to/dataset_infos_val.pkl"
    kitti_root_path: "DATASET_ROOT"
  }
}
```

また、訓練の長さを変えたいときは下記の項を調節

```bash
  steps: 296960 # 92800 # 1856 steps per epoch * 160 epochs →このステップ分学習する 
  steps_per_eval: 37120 # 9280 # 1856 steps per epoch * 5 epochs
  #↑のステップが経過すると途中状態の評価を行う、これをステップ数と同じにすると時間節約できるが途中経過がわからなくなる
  save_checkpoints_secs : 1800 # half hour →この時間が経過すると途中経過を保存する
```

RTX2080環境では、200 steps/min,　終了まで約８時間半
評価ステップにも時間がかかるので９時間をみるとよさそう。（電気代...!!!

学習のステップ数に関しては、正直勘所がわからないので、各自調整しよう。


## 訓練開始！

そうさこの時を待っていたんだ、準備は整った、さあ訓練の開始だ！

```bash
cd /second.pytorch/second
python ./pytorch/train.py train --config_path=./configs/pointpillars/pp_pretrain.config --model_dir=/path/to/model_dir
#modelディレクトリのパスを自分で設定する。ここで大事なのは、フォルダまで作らないこと。
#フォルダを作らずに上記のコードを走らせると、フォルダを自動生成してくれる。
#フォルダが存在してる状態では、フォルダの中身に存在するはずのtckptファイルを探しに行く。
#が、初回ではもちろんないので訓練が始まらない仕様
```

そして訓練が始まる！

【訓練中のGPU】:VRAMを６GBほど使用、唸れGPU!!!!
![Screenshot from 2019-10-27 19-12-54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388647/0b755453-98ce-6638-eded-69ad82daa613.png)

【訓練中の出力】:step数を見ると、現状の進行状況がわかる
![Screenshot from 2019-10-27 19-13-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388647/84aad0d3-4a4e-2fea-8e4f-134ea9d1e2df.png)

ちなみに、訓練中にも一定ステップ内で評価が行われる。（これがなかなか時間食うので、設定でオフにしちゃってもいい）
３０分後の途中評価結果はこちら

![Screenshot from 2019-10-27 19-54-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388647/e4c77e2e-a86f-784a-ad36-7af03237d89b.png)

車以外成績がポンコツ。。。
第１チェックポイントの結果なので今後は伸びていくはず。

訓練中では、指定したmodelフォルダが下記の内容になっていく
tckptや、評価結果のresult, tensorboardXで出力するsummary,その他ログが吐かれていく。

![Screenshot from 2019-10-27 21-25-35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388647/33ad1c74-158a-9e59-6020-0971aa9f4ef2.png)


## 評価

評価は途中チェックポイントで行われるが、改めて評価したい場合は下記のように行う。

```bash
python ./pytorch/train.py evaluate --config_path=./configs/all.fhd.config --model_dir=/path/to/model_dir --measure_time=True --batch_size=1
```

## まとめ
以上がPointPillars訓練から評価まででした。

githubのインストラクションに沿いながら、困った部分を補足しました。

え、可視化がないからなんか物足りないって？
KITTI viewerがあるんだけど時間切れで動かせなかったのさ...

次回以降はこんなことをしていくぞ！（一度でまとめてやるわけではないぞ！）

* 訓練結果の可視化どうするんだよ！
* Waymo Open Datasetで訓練するにはどうするんだよ！
* PointPillars論文内容はコードのどこに実装されているのか？
* PointPillarsの訓練コードはどのように実装されているのか？
* 俺NETを作るためには、どこを改造するのが良さそうか？

それでは〜