YOLOやSSDより速いと噂のM2Detを試してみた

# はじめに
先日、このような投稿を見つけました。→[最新最強の物体検出技術M2Det](https://qiita.com/kzykmyzw/items/1831f70dcade04db2210)
M2Detの論文の著者の方がソースコードを公開しているようなので実際に動かしてみました。
[GitHub](https://github.com/qijiezhao/M2Det)のREADME通りにやっても動かなかったので、自分の備忘録として記事に残します。


# 実行環境
OS：Ubuntu16.04
GPU：GTX 1050Ti (CPUだけでも問題ないと思います)
CUDA：9.2
Python：2.7

# 必要なものをインストール
## pytorch
著者の方はpytorchを使ってM2Detのニューラルネットを記述していました。
なので、pytorchをインストールします。
OSやpythonのバージョンで微妙に変わるので、公式サイトを参考にしてインストールしてください。
`pip install torch`

## torchvision
`pip install torchvision`

## cython
`pip install cython`

## その他
`pip install opencv-python`
`pip install tqdm`
（他にあるかも）

# リポジトリのダウンロード
適当な場所にクローンしてください。
`git clone https://github.com/qijiezhao/M2Det.git`

#コンパイル
M2Detの中に移動してください。
`cd M2det/`

コンパイルしてください
`sh make.sh`

私の環境では`warninig`が３つほど出ました。
不安なのでもう一度コンパイルすると、

```terminal
running build_ext
skipping 'nms/cpu_nms.c' Cython extension (up-to-date)
skipping 'nms/gpu_nms.cpp' Cython extension (up-to-date)
skipping 'pycocotools/_mask.c' Cython extension (up-to-date)
```

と出力されました。
上手くコンパイルできたっぽいので次に進みます。

# weightファイルの準備
はじめに、weightファイルを保存するフォルダを作ります。
`cd M2Det/ && mkdir weights`

著者の方がすでに学習済みのweightファイルを用意してくれています。
[ここ](https://drive.google.com/file/d/1NM1UDdZnwHwiNDxhcP-nndaWj24m-90L/view)からダウンロードしてください。

ダウンロードできたweightファイルを先ほど作った`M2Det/weights/`の中に保存してください。

# Demoの実行...
READMEに従って、`demo.py`を実行してみます。
`python demo.py -c=configs/m2det512_vgg.py -m=weights/m2det512_vgg.pth --show`

しかし、エラーが出てしまいました。

```terminal
Traceback (most recent call last):
  File "demo.py", line 7, in <module>
    from configs.CC import Config
ImportError: No module named configs.CC
```

どうやらmoduleのimportが上手く行っていないみたいです。
他にいい方法があるかもしれませんが、次のようなファイルを作成して、`M2Det/configs/`の中に保存します。

```__init__.py
from . import CC
from . import default_settings
from . import m2det320_resnet101
from . import m2det320_vgg
from . import m2det512_vgg
from . import m2det704_vgg
from . import m2det800_vgg
```

これでimportのエラーは消えましたが、別のエラーが出ました。

```terminal
~
SyntaxError: Non-ASCII character '\xe2' in file /home/rg26/M2Det/utils/box_utils.py on line 61, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
```

`M2Det/utils/box_utils.py`と`M2det/layers/modules/multibox_loss.py`の１行目に、

```.py
# coding: utf-8
```

を追加すれば解決します。

がしかし、またしてもエラーが出てしまいました。

```terminal
Traceback (most recent call last):
  File "demo.py", line 38, in <module>
    priors = priorbox.forward()
  File "/home/rg26/M2Det/layers/functions/prior_box.py", line 36, in forward
    for i, j in product(range(f), repeat=2):
TypeError: range() integer end argument expected, got float.
```

`M2Det/layers/functions/prior_box.py`の36行目を、

```prior_box.py
35 for k, f in enumerate(self.feature_maps):
36     for i, j in product(range(int(f)), repeat=2):
37         f_k = self.image_size / self.steps[k]
```
上の用に変更してください。

# そしてついに！

```terminal
 ----------------------------------------------------------------------
|                       M2Det Demo Program                             |
 ----------------------------------------------------------------------
The Anchor info: 
{'aspect_ratios': [[2, 3], [2, 3], [2, 3], [2, 3], [2, 3], [2, 3]], 'clip': True, 'feature_maps': [64.0, 32.0, 16.0, 8.0, 4.0, 2.0], 'min_dim': 512, 'min_sizes': [30.72, 76.8, 168.96, 261.12, 353.28, 445.44], 'steps': [8, 16, 32, 64, 128, 256], 'max_sizes': [76.8, 168.96, 261.12, 353.28, 445.44, 537.6], 'variance': [0.1, 0.2]}
===> Constructing M2Det model
Loading resume network...
===> Finished constructing and loading model
pos:(2.0,146.5,36.2,273.8), ids:person, score:0.972
pos:(41.9,124.6,118.1,344.2), ids:person, score:0.913
pos:(123.3,142.2,181.3,355.8), ids:person, score:0.667
pos:(94.8,148.4,134.6,264.5), ids:person, score:0.506
pos:(43.7,141.8,70.7,191.0), ids:person, score:0.447
pos:(94.2,145.9,111.8,166.7), ids:person, score:0.128
~
```

成功しました。
`M2Det/imgs/`の中に入っている画像が次々と認識されます！

![result-2019-03-09_20.40.48.gif](https://qiita-image-store.s3.amazonaws.com/0/246881/214f6814-771c-6b3d-fffa-0117a0e0caff.gif)


# 終わりに
M2Detを試すことができました。
今後はYOLOやSSDより速いのかどうか実際に計測してみたいと思います。