物体検出で遊んでみた♬～SSD224を作ってみた～

前回、[SSD500用のprior_boxes_ssd500.pkl](https://qiita.com/MuAuan/items/a53ba374a7ce417a790f)を作ったので、今回はより軽量なSSD224を作成した。
環境が貧弱なので大きなモデルはフィッティングもメモリオーバーになるし、何より時間がかかっていろいろ試せないが、軽量バージョンならお試しには都合がよい。

###prior_boxes_SSDの構造
とにかく、prior_boxesはタイルのように張り巡らすために、段階的な大きさでしかもアスペクト比と取り揃えて、画像全体をカバーしつつ大きさの違う画像に対応しようとするものである。
逆に言えば、全体サイズが異なってもそれらはほぼ相似形になるべきであり、SSD300の形状が判明しているので、それに倣ってSSD224のBoxesのサイズを決めればよい。

SSD300のパラメータの構造は以下のとおりであった。

| Layer_width,height | min_size |    max_size|
|:-------------:|:-------------:|:----------:|
| 38 x 38         |30           |        None|
| 19 x 19         |60           |         114|
| 10 x 10         |          114|         168|
| 5  x  5         |          168|         222|
| 3  x  3         |          222|         276|
| 1  x  1         |          276|         330|
SSD224も上と相似形だとすれば以下のような形状が好ましい。
※ただし、平面をカバーすればいいので、あまり厳密ではないだろう

最初のmini_sizeが決まれば、あとは上段３個は逆数比が一定ということで、決定する。
その後は、ほぼ等間隔という法則のようなので、ほぼその形状をまねる。
Layer_width,heightはnetworkの構造から決まってしまう。

| Layer_width,height | min_size |    max_size|
|:-------------:|:-------------:|:----------:|
| 28 x 28       |22             |        None|
| 14 x 14       |44             |          88|
| 7  x  7       |88             |         128|
| 4  x  4       |            128|         168|
| 2  x  2       |            168|         208|
| 1  x  1       |            208|         248|
max_sizeの方で、layer_widthの倍々を考えると、三つめは132となる。
ということで、ここは間をとって、130とした。
あとは上をいくつが妥当かを考えると切れのいい250とした。
なので、ちょっと変則的だが今回は以下のような形状とした。
※小さいサイズと大きなサイズのところの相似形を重視したといったところ

| Layer_width,height | min_size |    max_size|
|:-------------:|:-------------:|:----------:|
| 28 x 28       |22             |        None|
| 14 x 14       |44             |          88|
| 7  x  7       |88             |         130|
| 4  x  4       |            130|         160|
| 2  x  2       |            160|         200|
| 1  x  1       |            200|         250|

以上で一応回したところで、そもそも論文だとどうなっているのか興味があって、以下確認した。

###論文での説明
[SSD: Single Shot MultiBox Detector](https://arxiv.org/abs/1512.02325)
 Wei Liu, Dragomir Anguelov, Dumitru Erhan, Christian Szegedy, Scott Reed, Cheng-Yang Fu, Alexander C. Berg
(Submitted on 8 Dec 2015 (v1), last revised 29 Dec 2016 (this version, v5))

以下が、論文の該当箇所

 Feature maps from different levels within a network are known to have different (empirical) receptive ﬁeld sizes [13]. Fortunately, within the SSD framework, the default boxes do not necessary need to correspond to the actual receptive ﬁelds of each layer. 

最初の話（*Networkの異なる層からの特徴マップは異なる（経験的な）受容野の大きさを持つことが知られている*）は、想定内ですが、(*幸運にも、SSDフレームワークでは、デフォルトボックスは、各々の層の実際の受容野に対応している必要はない*）というのは、ある程度第一文を考えれば、一定のカバー範囲になるということは想定すべきである。

ということで、彼らは以下としている。

 We design the tiling of default boxes so that speciﬁc feature maps learn to be responsive to particular scales of the objects. 

（*それぞれの特徴マップは、特定の大きさの物体に関して学習するようにデフォルトボックスをタイル状に配置する*）
って、ことで妥当な話である。

Suppose we want to use m feature maps for prediction. 

（ここでは、m個の特徴マップを使う）

The scale of the default boxes for each feature map is computed as:


```math
s_{k} = s_{min} +(s_{max} −s_{min})/(m−1)(k−1), k ∈ [1,m] (4) 
```

where ```s_{min}``` is 0.2 and ```s_{max}``` is 0.9, meaning the lowest layer has a scale of 0.2 and the highest layer has a scale of 0.9, and all layers in between are regularly spaced. 

デフォルトボックスは最小スケール0.2、最大スケール0.9として、あとは等間隔で配置で設計したとあります。
デフォルトボックスのスケールの計算式から計算すると以下の表となる。
					
| k | sk | 300 | 224 | 500 |
|:-:|:-:|:-:|:-:|:-:|
| 1  |0.2  |60    |44    |100   |
| 2  |0.34 |102   |76    |170   |
| 3  |0.48 |144   |107   |240   |
| 4  |0.62 |186   |138   |310   |
| 5  |0.76 |228   |170   |380   |
| 6  |0.9  |270   |201   |450   |
ここから、計算したデフォルトボックスの大きさはちょっと上記とは異なっています。
もし合わせるとすると以下のようになります。

| k | sk | 300 | 224 | 500 |
|:-:|:-:|:-:|:-:|:-:|
| 1  |0.1  |30   |22   |50   |
| 2  |0.2  |60   |45   |100  |
| 3  |0.38 |114  |85   |190  |
| 4  |0.56 |168  |125  |280  |
| 5  |0.74 |222  |166  |370  |
| 6  |0.92 |276  |206  |460  |

つまり、こちらは、k=1,2は、sk=0.1として等間隔、k=2～6を最大値k=6を0.92としてあとは等間隔としています。

以下はまた、論文引用。。。

We impose different aspect ratios for the default boxes, and denote them as ar ∈ {1,2,3, 1/2, 1/3}. We can compute the width (wa k = sk√ar) and height (ha k = sk/√ar) for each default box. For the aspect ratio of 1, we also add a default box whose scale is s0 k = √sksk+1, resulting in 6 default boxes per feature map location. We set the center of each default box to

```math
 (i+0.5)/|f_{k}| , (j+0.5)/|f_{k}| ), 
```

where ```|f_{k}|``` is the size of the k-th square feature map, i,j ∈ [0,```|f_{k}|```). In practice, one can also design a distribution of default boxes to best ﬁt a speciﬁc dataset. How to design the optimal tiling is an open question as well. 		

上記は、アスペクト比arを{1,2,3, 1/2, 1/3}として、幅と高さを決めています。
そして、大切なことは、最後の一文で、（*どのように敷き詰めるかはオープンクエスチョンである*）やはり最適解はないようだ。。。

				
###物体検出とSSD224のフィッティング
上記論文に、以前記載したように、以下論文引用のように、物体認識でNetworkをパラメータフィッティングされたVGG16モデルをベースにデータセットに対してFine-Tuningし、その後物体検出でフィッティングするということらしい。

Base network Our experiments are all based on VGG16 [15], which is pre-trained on the ILSVRC CLS-LOC dataset [16]. Similar to DeepLab-LargeFOV [17], we convert fc6 and fc7 to convolutional layers, subsample parameters from fc6 and fc7, change pool5 from 2 × 2 − s2 to 3 × 3 − s1, and use the `a trous algorithm [18] to ﬁll the ”holes”.
*このホール・アルゴリズムってちょっとわからないが、。。。fc6とfc7をconvolutional layerに変換して、pool5を2x2から3x3に変えるということらしい。*
※文献[17][18]を読まなくちゃ。。。

 We remove all the dropout layers and the fc8 layer. We ﬁne-tune the resulting model using SGD with initial learningrate 10−3, 0.9 momentum, 0.0005 weight decay, and batch size 32. The learning rate decay policy is slightly different for each dataset, and we will describe details later. The full training and testing code is built on Caffe[19] and is open source at: https://github.com/weiliu89/caffe/tree/ssd .

ということで、224×224で物体認識を実施すればよいが、入力画像をどうすればよいかできなかったので、無理やり物体検出でNetworkもフィッティングしてみた。
結果的には、一応物体検出できるところまでは行ったがVOC2007のデータ（4000個位）でもかなり時間とパワーを要した。
やはり、データ作成と入力方法を変更した方がよさそうである。

ということで、今後種々改善するが、とりあえずSSD224の結果を示す。

###SSD224による物体検出の結果
![1524369310jx9741N6VJyKHfP1524369306.gif](https://qiita-image-store.s3.amazonaws.com/0/233744/24295a7f-51f6-cefe-1a51-fa7ce93c3c36.gif)

###まとめ
・今回はSSD224のprior_boxを作成して物体検出まで試してみた
・原理的な裏付けが見えたので今後いろいろ改善したい
・SSDの今回のコードだと、カテゴリを変更しようとするとエラーが出るので改善したい

・原理学習時点はともかく、Fine-Tuningが基本のようなので、現在だと各フレームワークにSSDモデルまで用意されているので、それを使うべきだろう
・学習がFine-Tuningが基本とならざるをえず、学習計画（手法と学習データ、そして学習順序）を計画する必要がある

以下蛇足だが、
　物体検出では、[平面充填](https://ja.wikipedia.org/wiki/%E5%B9%B3%E9%9D%A2%E5%85%85%E5%A1%AB)みたいな平面敷詰めの問題や、そもそものターゲット画像の分布分析して、それに基づいて最適解だすとかありそうである。
特に、現在はデフォルトがボックスとなっているが、そもそもLayerはだいたいの特徴マップの大きさであり、画像認識も含めて円（circle）はやってみる価値があると思う。