TensorflowのFaster RCNN実装を試す

この記事は
===

* ちょっと前まで最速とされていた物体検出のディープニューラルネットであるFaster RCNNのTensorflow実装[Faster-RCNN_TF](https://github.com/smallcorgi/Faster-RCNN_TF)を使ってみたのでメモです
* 時代はSingle Shot Multibox Detector (SSD)らしいですが、Tensorflow実装は[こんな](https://github.com/seann999/ssd_tensorflow)開発中のしかないので一週遅れ感は否めませんが。


セットアップ
===

前提
---

* TITAN X (Pascal)
* ubuntu14.04.5 LTS
* python2.7
* Tensorflow v0.12
* その他cython, python-opencv, easydictなど適当にインストール

インストール
---

* README通りにセットアップしました。

```
# git clone --recursive https://github.com/smallcorgi/Faster-RCNN_TF.git
# cd ./Faster-RCNN_TF/lib
# make
```

デモが動かない
===

* 画像の物体検出をして、赤枠で囲って表示するというデモが準備されています
* [ここ](https://github.com/smallcorgi/Faster-RCNN_TF#demo)にデモを動かす手順があります
* しかし、この通りにやっても、訓練済みモデルファイルとソースのネットワーク構成がずれているようなエラーが出ます
* なんらかのバージョン問題なんだと思いますが、よくわからないのであきらめました
  * そもそもこのFaster RCNN実装が想定しているTensorflowのバージョンがいくつなのか不明だし・・・

自分でモデルをトレーニングする
===

* 仕方がないので自力でモデルをトレーニングして、それでデモを動かすことにしました。

画像データのダウンロード
---

* README通りに入手＆解凍＆配置

```
# wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtrainval_06-Nov-2007.tar
# wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtest_06-Nov-2007.tar
# wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCdevkit_08-Jun-2007.tar

# tar xvf VOCtrainval_06-Nov-2007.tar
# tar xvf VOCtest_06-Nov-2007.tar
# tar xvf VOCdevkit_08-Jun-2007.tar

# cd ~//data
# ln -s $VOCdevkit VOCdevkit2007

# wget https://www.dropbox.com/s/po2kzdhdgl4ix55/VGG_imagenet.npy?dl=1
# mv VGG_imagenet.npy $FRCN_ROOT/data/pretrain_model/VGG_imagenet.npy
```

学習回数の変更
---

* 学習回数がデフォルトで70000ステップに固定されています。
* 今回は何となくもっと回したかったので修正しました。

```
--- a/experiments/scripts/faster_rcnn_end2end.sh
+++ b/experiments/scripts/faster_rcnn_end2end.sh
@@ -27,7 +27,7 @@ case $DATASET in
     TRAIN_IMDB="voc_2007_trainval"
     TEST_IMDB="voc_2007_test"
     PT_DIR="pascal_voc"
-    ITERS=70000
+    ITERS=300000
     ;;
   coco)
     # This is a very long and slow training schedule
```

学習開始
---

* 下記のコマンドで学習開始です

```
# ./experiments/scripts/faster_rcnn_end2end.sh gpu 0 VGG16 pascal_voc
...(なんかいろいろ起動ログが出る）

iter: 10 / 300000, total loss: 2.1978, rpn_loss_cls: 0.3894, rpn_loss_box: 0.7754, loss_cls: 0.5617, loss_box: 0.4713, lr: 0.001000
speed: 0.448s / iter
iter: 20 / 300000, total loss: 2.7391, rpn_loss_cls: 0.3400, rpn_loss_box: 0.2858, loss_cls: 1.1327, loss_box: 0.9805, lr: 0.001000
speed: 0.441s / iter
iter: 30 / 300000, total loss: 1.5654, rpn_loss_cls: 0.3556, rpn_loss_box: 0.6474, loss_cls: 0.3408, loss_box: 0.2216, lr: 0.001000
speed: 0.464s / iter
```

* iterがだんだん増えて行きます
* 300000step回ると下記のファイルが出力されます


```
/root/Faster-RCNN_TF/output/faster_rcnn_end2end/voc_2007_trainval/VGGnet_fast_rcnn_iter_300000.ckpt
```

今一度デモを動かす
===

* 訓練済みモデルの自作ができたので、今度こそデモを動かしてみます

ちょっとソース修正
---

* デモは入力画像の物体認識をして、結果画像をXWindow上に表示するというものですが、今回はそもそもX入ってなくてエラーが出たので対処しました
* ついでにファイル出力するようにいじりました

```
--- a/tools/demo.py
+++ b/tools/demo.py
@@ -1,3 +1,6 @@
+import matplotlib
+matplotlib.use('Agg')
+
 import _init_paths
 import tensorflow as tf
 from fast_rcnn.config import cfg
@@ -83,6 +86,7 @@ def demo(sess, net, image_name):
         keep = nms(dets, NMS_THRESH)
         dets = dets[keep, :]
         vis_detections(im, cls, dets, ax, thresh=CONF_THRESH)
+    plt.savefig('/tmp/' + image_name)

```

実行
---

* 実行してみます

```
# python ./tools/demo.py --model /root/Faster-RCNN_TF/output/faster_rcnn_end2end/voc_2007_trainval/VGGnet_fast_rcnn_iter_300000.ckpt
...(なんかいろいろ起動ログが出る）
Loaded network /root/Faster-RCNN_TF/output/faster_rcnn_end2end/voc_2007_trainval/VGGnet_fast_rcnn_iter_300000.ckpt

Demo for data/demo/000456.jpg
Detection took 0.621s for 300 object proposals

Demo for data/demo/000542.jpg
Detection took 0.055s for 233 object proposals

Demo for data/demo/001150.jpg
Detection took 0.058s for 212 object proposals

Demo for data/demo/001763.jpg
Detection took 0.066s for 261 object proposals

Demo for data/demo/004545.jpg
Detection took 0.059s for 300 object proposals
```

* おお！なんか画像を読み込んでます
  * ちなみに入力画像は```data/demo/```の下にもともと格納されています
* 上記ソース改修で/tmpの下に画像ファイルが出力されてます

結果
===

* ↓こんな画像が出力されていました

![000456.jpg](https://qiita-image-store.s3.amazonaws.com/0/27361/78abdbe2-4985-33d8-dcfd-e8e54cf85a19.jpeg)
![000542.jpg](https://qiita-image-store.s3.amazonaws.com/0/27361/cbcd2782-7b03-a05b-3d51-65aadeda8ab6.jpeg)
![001150.jpg](https://qiita-image-store.s3.amazonaws.com/0/27361/e2a178d4-5a17-5012-b93a-b2b3ad2b28c2.jpeg)
![001763.jpg](https://qiita-image-store.s3.amazonaws.com/0/27361/826c08a3-163d-4a91-f3c6-c40c4a64f9d4.jpeg)
![004545.jpg](https://qiita-image-store.s3.amazonaws.com/0/27361/f32962e5-2917-8ee2-0c62-de82f0d2f1a0.jpeg)

終わりに
---

* だいたい１枚あたり0.06秒くらいで認識できてます
* 精度も申し分なさそうです
* SSDの実装が出てくるまでは、とりあえずTensorflowで物体検出にはこれ使うのがよさそうですね