物体検出で遊んでみた♬～SSD500用のprior_boxes_ssd500.pklを作る～

物体検出。。。ここではSSD300を利用していて厄介なのは、入力画像のサイズを変更したいのに変更できないこと。。

まあ、じゃSSD500を使えばいいのでは？？
いやいや、そこは独自に変更したい

ということで、ググって、やってみました。

###create_prior_box.py♬がありました！
こちらのサイトにあるんですね。
[codingPingjun/create_prior_box.py](https://gist.github.com/codingPingjun/aa54be7993ca6b2d484cccf5a2c5c3d4)

でもコードは意地悪な感じがします。
ずばり、回答はないのです。
単に、自分が持っているダウンロードしたpickleファイルと同じことを検証するプログラム。

ということで、プログラムの構造を見てみましょう。
###create_prior_box.pyの構造
main()は以下のとおりです。

```
    boxes_paras = create_prior_box()
    priors = pickle.load(open('prior_boxes_ssd300.pkl', 'rb'))
    diff = boxes_paras - priors
    # pdb.set_trace()
    print("simi {}, max value {}, min value {}".format(diff.shape, diff.max(), diff.min()))
```

一番肝心なところは、最初の部分のようです。

```
img_width, img_height = 300, 300
box_configs = [
    {'layer_width': 38, 'layer_height': 38, 'num_prior': 3, 'min_size':  30.0,
     'max_size': None, 'aspect_ratios': [1.0, 2.0, 1/2.0]},
    {'layer_width': 19, 'layer_height': 19, 'num_prior': 6, 'min_size':  60.0,
     'max_size': 114.0, 'aspect_ratios': [1.0, 1.0, 2.0, 1/2.0, 3.0, 1/3.0]},
    {'layer_width': 10, 'layer_height': 10, 'num_prior': 6, 'min_size': 114.0,
     'max_size': 168.0, 'aspect_ratios': [1.0, 1.0, 2.0, 1/2.0, 3.0, 1/3.0]},
    {'layer_width':  5, 'layer_height':  5, 'num_prior': 6, 'min_size': 168.0,
     'max_size': 222.0, 'aspect_ratios': [1.0, 1.0, 2.0, 1/2.0, 3.0, 1/3.0]},
    {'layer_width':  3, 'layer_height':  3, 'num_prior': 6, 'min_size': 222.0,
     'max_size': 276.0, 'aspect_ratios': [1.0, 1.0, 2.0, 1/2.0, 3.0, 1/3.0]},
    {'layer_width':  1, 'layer_height':  1, 'num_prior': 6, 'min_size': 276.0,
     'max_size': 330.0, 'aspect_ratios': [1.0, 1.0, 2.0, 1/2.0, 3.0, 1/3.0]},
]
```
これがSSD300のものです。ということは、これを最初に動かすと、差分は０が出力されてそれが証明されます。

では、SSD500だとどこを変更すればいいのでしょう。

よく見ると、それぞれのlayer_width:38, layer_height:38, num_prior:3というのは、ちょうどネットワークの大きさとプログラムの変数num_priors=3と一致しているようです。
そして、その下の値10なども同じように、mbox_～を構成している以下のような～_mbox_～ の要素の大きさのようです。

```
conv4_3_norm_mbox_loc (Conv2D)  (None, 38, 38, 12)   55308       conv4_3_norm[0][0]
__________________________________________________________________________________________________
fc7_mbox_loc (Conv2D)           (None, 19, 19, 24)   221208      drop7[0][0]
__________________________________________________________________________________________________
conv6_2_mbox_loc (Conv2D)       (None, 10, 10, 24)   110616      dropout_6[0][0]
__________________________________________________________________________________________________
conv7_2_mbox_loc (Conv2D)       (None, 5, 5, 24)     55320       dropout_7[0][0]
__________________________________________________________________________________________________
conv8_2_mbox_loc (Conv2D)       (None, 3, 3, 24)     55320       dropout_8[0][0]
__________________________________________________________________________________________________
```
ということで、SSD500だとすると、input_shape = (500, 500, 3)として、ネットワークの構造を見ると、答えがわかりました。
ということで、上記部分を以下のように変更しました。

```
img_width, img_height = 500, 500
box_configs = [
    {'layer_width': 63, 'layer_height': 63, 'num_prior': 3, 'min_size':  30.0,
     'max_size': None, 'aspect_ratios': [1.0, 2.0, 1/2.0]},
    {'layer_width': 32, 'layer_height': 32, 'num_prior': 6, 'min_size':  60.0,
     'max_size': 114.0, 'aspect_ratios': [1.0, 1.0, 2.0, 1/2.0, 3.0, 1/3.0]},
    {'layer_width': 16, 'layer_height': 16, 'num_prior': 6, 'min_size': 114.0,
     'max_size': 168.0, 'aspect_ratios': [1.0, 1.0, 2.0, 1/2.0, 3.0, 1/3.0]},
    {'layer_width':  8, 'layer_height':  8, 'num_prior': 6, 'min_size': 168.0,
     'max_size': 322.0, 'aspect_ratios': [1.0, 1.0, 2.0, 1/2.0, 3.0, 1/3.0]},
    {'layer_width':  4, 'layer_height':  4, 'num_prior': 6, 'min_size': 322.0,
     'max_size': 400.0, 'aspect_ratios': [1.0, 1.0, 2.0, 1/2.0, 3.0, 1/3.0]},
    {'layer_width':  1, 'layer_height':  1, 'num_prior': 6, 'min_size': 400.0,
     'max_size': 550.0, 'aspect_ratios': [1.0, 1.0, 2.0, 1/2.0, 3.0, 1/3.0]},
]
```
と変更して、あとはpickleの出力です。
ちなみに、画像の最小サイズと最大サイズは適当に決めました。
特徴量は繰り込みしたサイズの逆数位の領域をカバーすると考えると、パラメータの逆数比あたりが正解かもですが、。。。
確かにSSD300のmin_sizeの比は最初の３つについては

```
38x30=19x60=10x114
```
という関係になっています。しかし、逆に大きい方から考えるとちょっとそういう関係にはなっていません。。。
また、アスペクト比も同じとしました。
そして、pickleの出力は以下のとおりです。

```
with open('prior_boxes_ssd500.pkl', mode='wb') as f:
        pickle.dump(boxes_paras, f)
```
ということで、さて動くでしょうか（笑）
###プログラムの起動とTraining
動きました！
以下のように、収束しつつあります。

```
47/47 [==============================] - 24s 515ms/step - loss: 6.6887 - acc: 0.1159 - val_loss: 5.5055 - val_acc: 0.1660
Epoch 2/10
47/47 [==============================] - 19s 409ms/step - loss: 4.7266 - acc: 0.2611 - val_loss: 5.3892 - val_acc: 0.2086
Epoch 3/10
47/47 [==============================] - 19s 408ms/step - loss: 4.6260 - acc: 0.3257 - val_loss: 5.3557 - val_acc: 0.3597
Epoch 4/10
47/47 [==============================] - 19s 409ms/step - loss: 4.5354 - acc: 0.3075 - val_loss: 5.4594 - val_acc: 0.3618
Epoch 5/10
47/47 [==============================] - 19s 410ms/step - loss: 4.4130 - acc: 0.3058 - val_loss: 5.3044 - val_acc: 0.2029
Epoch 6/10
47/47 [==============================] - 19s 412ms/step - loss: 4.3050 - acc: 0.2427 - val_loss: 5.1801 - val_acc: 0.1846
Epoch 7/10
47/47 [==============================] - 19s 411ms/step - loss: 4.1679 - acc: 0.2301 - val_loss: 5.0223 - val_acc: 0.1713
Epoch 8/10
47/47 [==============================] - 19s 411ms/step - loss: 4.1607 - acc: 0.2429 - val_loss: 5.0603 - val_acc: 0.1948
Epoch 9/10
47/47 [==============================] - 19s 410ms/step - loss: 4.1070 - acc: 0.2740 - val_loss: 5.0489 - val_acc: 0.1904
Epoch 10/10
47/47 [==============================] - 19s 411ms/step - loss: 4.0728 - acc: 0.2859 - val_loss: 5.0729 - val_acc: 0.3526
Epoch 1/10
47/47 [==============================] - 20s 436ms/step - loss: 4.0857 - acc: 0.3447 - val_loss: 4.9194 - val_acc: 0.3551
Epoch 2/10
47/47 [==============================] - 19s 412ms/step - loss: 4.0768 - acc: 0.3297 - val_loss: 4.9600 - val_acc: 0.3545
Epoch 3/10
47/47 [==============================] - 19s 412ms/step - loss: 3.9967 - acc: 0.2836 - val_loss: 4.8309 - val_acc: 0.1962
Epoch 4/10
47/47 [==============================] - 19s 412ms/step - loss: 3.9929 - acc: 0.2687 - val_loss: 4.8110 - val_acc: 0.1883
Epoch 5/10
47/47 [==============================] - 19s 411ms/step - loss: 3.9495 - acc: 0.2577 - val_loss: 4.6568 - val_acc: 0.2199
Epoch 6/10
47/47 [==============================] - 19s 412ms/step - loss: 3.9215 - acc: 0.2945 - val_loss: 4.7109 - val_acc: 0.3587
Epoch 7/10
47/47 [==============================] - 19s 410ms/step - loss: 3.8711 - acc: 0.3122 - val_loss: 4.5972 - val_acc: 0.3526
Epoch 8/10
47/47 [==============================] - 19s 410ms/step - loss: 3.8640 - acc: 0.3186 - val_loss: 4.6226 - val_acc: 0.3530
```
###コード
全体のコードは以下のとおりです。
[SSD / create_prior_box.py](https://github.com/MuAuan/SSD/blob/master/create_prior_box.py)

###結果
ごめんなさい、そこはまだまだ収束中です。
何せ、素からのフィッティングになってます。

ところで、SSD512みたいですね。。。性能もいいです。
[CNNを用いた物体検出アルゴリズムの性能比較](https://qiita.com/tokkuman/items/3fabd04a1a524843bea5)
また、以下の記事では、先ほどのボックスのサイズの話やアスペクト比の話もあるので、次回は参考としたいと思う。
[SSD:Single Shot Multibox Detector](https://qiita.com/de0ta/items/1ae60878c0e177fc7a3a)