物体検出SSD詳しく紹介(二)DefaultBoxesの変形と信頼度の生成

###背景
前章はSSDとはなんですか、SSDモデルが訓練と推論する時に使う材料になるDefaultBoxesを紹介しました。特にDefaultBoxesを生成する方法について紹介しました。

**目標はバウンディングボックスを表示させたり、物体名を表示させたりすることです。**
DefaultBoxesはSSDモデルから出力したものではない、我々は入力した300*300*3の画像からたくさんの均等分に分けて、作られたものです。
ではSSDモデルから出力したものはどんなものでしょうか?
->答えは:
1. SSDモデルは8732個のデフォルトボックスに対して、8732個Offset情報セットを出力します
2. SSDモデルは8732個のデフォルトボックスに対して、8732個信頼度情報セットを出力します
![SSD物体検出.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/23f51a8a-6613-bd59-5900-207e27aa00fe.jpeg)

1個Offset情報セットは一個デフォルトボックスを変形させます。
1個信頼度情報セットは一個デフォルトボックスがすべてのカテゴリーに対して信頼度を表します。
![SSD物体検出.002.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/805e1aca-3195-3fc2-c607-0083fff614ee.jpeg)

###SSDモデルから8732個のデフォルトボックスに対してoffset情報セットと信頼度情報セットの生成###
1個offset情報セットは長さ4の配列(△cx,△cy,△w,△h)になります、すべてのoffset情報セットは(8732,4)になります
1個信頼度情報セットは長さ21の配列(20種類+背景種類)になります、すべての信頼度情報は(8732,21)になります
では(8732,4)offset情報と(8732,21)信頼度情報をどうやって生成されてますか?
->答えは：
SSDモデルから生成しています

まずは、vgg16のbackboneを用意します
![SSD物体検出.003.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/d365fbf4-7cc6-b1f9-fa5e-76c93a86a16a.jpeg)
そこで図のように、vgg16の途中の出力を獲得してsource1としまして、vgg16の最後の出力を獲得してsource2とします
source1は(512,38,38)です　　----> デフォルトボックス38*38*4のために用意したものです
source2は(1024,19,19)です　----> デフォルトボックス19*19*6のために用意したものです

次に、vgg16とは別にextra layerをよういします。
![SSD物体検出.004.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/340d41f9-b7c8-1a1f-31dd-77181278270d.jpeg)
入力はvgg16の出力source2です。
そこで、extra layer途中に生成されたと最後の出力を獲得して、それぞれsource3,source4,source5,source6にします
source3は(512,10,10)です----> デフォルトボックス10*10*6のために用意したものです
source4は(256,5,5)です----> デフォルトボックス5*5*6のために用意したものです
source5は(512,3,3)です----> デフォルトボックス3*3*4のために用意したものです
source6は(512,1,1)----> デフォルトボックス1*1*6のために用意したものです
![SSD物体検出.005.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/0a92879f-f5c2-e24e-66a1-db5377227870.jpeg)
extra layerを詳しくみると、source2からsource3に流されました。
経緯はまずsource2(1024,19,19)をConv(pad=0,kernelSize=1,stride=1,input=1024,output=256)のconv layerを経由して、(256,19,19)になります。
そじて(256,19,19)をConv(pad=1,kernelSize=3,stride=2,input=256,output=512)のconv layerを経由して、(512,10,10)のsource3になります

***conv layerによる、WとHは以下の計算式で算出できます***
W = (Prev_W + 2*pad - kernelSize)/stride + 1
H = (Prev_H + 2*pad - kernelSize)/stride + 1

***いまの目的はすべてのデフォルトボックスに対してOffset情報と信頼度情報を作成することです。ここは目的地を見えましたが、またrawのOffset情報と信頼度情報です***

####**1.Offset情報**###
Offset　layerを用意して、rawのoffset情報(source1,source2,source3,source4,source5,source6)をoffset1,offset2,offset3,offset4,offset5,offset6に変換します

![SSD物体検出.006.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/1403fb3e-8610-671f-a6e7-0a129f83e31e.jpeg)

offset1は(4*4,38,38)です
offset2は(6*4,19,19)です
offset3は(6*4,10,10)です
offset4は(6*4,5,5)です
offset5は(4*4,3,3)です
offset6は(4*4,1,1)です

ここで、source1からoffset1まで変換するながれを詳しくみてみましょう
![SSD物体検出.007.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/bedec6d0-ff61-1190-8b3e-49053706c31c.jpeg)

source1は(512,38,38)
convはConv(pad=1,kernelSize=3,stride=1,input=4*4,output=512)
offset1は(4*4,38,38)

ここで、(38,38)は元画像を38*38個均等分ポイントに対して38*38個のoffset情報を提供するわけです。
4*4の意味は左側と右側にわけてみてみましょう
左側の4：元画像からわけられた38*38個均等分ポイントに対して、各ポイントの４個のデフォルトボックスを指しています。
右側の4:各デフォルトボックスに対して、offset(△cx,△cy,△w,△h)をさしています。

![SSD物体検出.008.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/ad69b62f-47a7-810d-bebc-99c7ac539cbe.jpeg)
この図のように、38*38*4のデフォルトボックス[一番右側の４個のデフォルトボックス]に対して、16個のoffset情報を提供しています


![SSD物体検出.009.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/f1007159-e92b-34ab-74e4-53ce99067ec1.jpeg)

この図のように、38*38*4のデフォルトボックス[一番右側の４個のデフォルトボックス][一番手前のデフォルトボックス]に対して、４個のoffset情報(△cx,△cy,△w,△h)を提供しています。デフォルトボックすは座標情報(cx_d,cy_d,w_d,h_d)を持ち、offset情報(△cx,△cy,△w,△h)を使い、赤いボックスに変形します
変形する算式は

```text
cx = cx_d+0.1*△cx*w_d)
cy = cy_d+0.1*△cy*w_h)
w = w_d*exp(0.2*△w)
h = h_d*exp(0.2*△h)
```

![SSD物体検出.010.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/8500dcf0-fbf5-126a-c254-ed8ccdf3d48a.jpeg)
この図のように、38*38*4のデフォルトボックス[一番右側の４個のデフォルトボックス][２番目手前のデフォルトボックス]に対して、４個のoffset情報(△cx,△cy,△w,△h)を提供しています。デフォルトボックすは座標情報(cx_d,cy_d,w_d,h_d)を持ち、offset情報(△cx,△cy,△w,△h)を使い、赤いボックスに変形します

![SSD物体検出.011.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/4b6c16f2-83b9-b0fa-638e-840581f2e404.jpeg)
このように各デフォルトボックスは自分専用なoffset情報を使って、変形します

38*38*4のデフォルトボックス
![SSD物体検出.011.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/27fef6a3-50a9-d77b-03f8-c0e634770275.jpeg)


19*19*6のデフォルトボックス
![SSD物体検出.012.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/d2ce70ac-041c-d1c8-1c9d-e58a1dc74e1a.jpeg)



![SSD物体検出.013.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/adfc1391-00e7-367c-002a-7d95918d0fdf.jpeg)

####**2.信頼度情報**###
![SSD物体検出.013.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/9757cc8a-8e3f-46bb-15fc-8c5502cc06eb.jpeg)
confidence　layerを用意して、rawの信頼度情報(source1,source2,source3,source4,source5,source6)をconfidence1,confidence2,confidence3,confidence4,confidence5,confidence6に変換します
confidence1は(4*21,38,38)です
confidence2は(6*21,19,19)です
confidence3は(6*21,10,10)です
confidence4は(6*21,5,5)です
confidence5は(4*21,3,3)です
confidence6は(4*21,1,1)です
ここは21は検出種類数(20種類の物体+背景))を表しています
２１のところはoffsetのところにいったら4になります

![SSD物体検出.014.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/1fe457dc-6586-7cf8-7a35-608b933bce56.jpeg)
ここで、(38,38)は元画像を38*38個均等分ポイントに対して38*38個の信頼度情報を提供するわけです。
4*21の意味は左側と右側にわけてみてみましょう
左側の4：元画像からわけられた38*38個均等分ポイントに対して、各ポイントの４個のデフォルトボックスを指しています。
右側の21:各デフォルトボックスに対して、検出物体の信頼度を表しています。

![SSD物体検出.015.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/bfb755f7-f3ba-8115-fa2a-6737f76385e0.jpeg)
この図のように、一つのデフォルトボックスに対して、21個の信頼度情報(background,aeroplane,bicycle,bird....person)を提供しています。それぞれの可能な物体の信頼度を数値で表しています


![SSD物体検出.016.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/bd5c0872-c7cc-33ef-3f42-0ed3dd1e7587.jpeg)
この図のように、38*38*4のデフォルトボックス[一番右側の４個のデフォルトボックス][一番手前のデフォルトボックス]に対して、21個の信頼度情報(background,aeroplane,bicycle,bird....person)を提供しています。それぞれの可能な物体の信頼度を数値で表しています

![SSD物体検出.017.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191439/2f5f0959-9e73-ed00-17a0-e8007483cc90.jpeg)
この図のように、38*38*4のデフォルトボックス[一番右側の４個のデフォルトボックス][２番目手前のデフォルトボックス]に対して、21個の信頼度情報(background,aeroplane,bicycle,bird....person)を提供しています。それぞれの可能な物体の信頼度を数値で表しています

###ソースコード###
このコードは「PyTorchによる発展ディープラーニング」という本からさんこうにしました。
####1.vgg1６ layeを生成します####
vgg16 はsource1,source2を生成するものです。

```python
def make_vgg():
    layers = []
    in_channels = 3  # 色チャネル数

    # vggモジュールで使用する畳み込み層やマックスプーリングのチャネル数
    cfg = [64, 64, 'M', 128, 128, 'M', 256, 256,
           256, 'MC', 512, 512, 512, 'M', 512, 512, 512]

    for v in cfg:
        if v == 'M':
            layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
        elif v == 'MC':
            # ceilは出力サイズを、計算結果（float）に対して、切り上げで整数にするモード
            # デフォルトでは出力サイズを計算結果（float）に対して、切り下げで整数にするfloorモード
            layers += [nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)]
        else:
            conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)
            layers += [conv2d, nn.ReLU(inplace=True)]
            in_channels = v

    pool5 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
    conv6 = nn.Conv2d(512, 1024, kernel_size=3, padding=6, dilation=6)
    conv7 = nn.Conv2d(1024, 1024, kernel_size=1)
    layers += [pool5, conv6,
               nn.ReLU(inplace=True), conv7, nn.ReLU(inplace=True)]
    return nn.ModuleList(layers)
```

####2.extra layerを生成します####
extra layerはsource3,source4,source5,source6を生成するものです。

```python
def make_extras():
    layers = []
    in_channels = 1024  # vggモジュールから出力された、extraに入力される画像チャネル数

    # extraモジュールの畳み込み層のチャネル数を設定するコンフィギュレーション
    cfg = [256, 512, 128, 256, 128, 256, 128, 256]

    layers += [nn.Conv2d(in_channels, cfg[0], kernel_size=(1))]
    layers += [nn.Conv2d(cfg[0], cfg[1], kernel_size=(3), stride=2, padding=1)]
    layers += [nn.Conv2d(cfg[1], cfg[2], kernel_size=(1))]
    layers += [nn.Conv2d(cfg[2], cfg[3], kernel_size=(3), stride=2, padding=1)]
    layers += [nn.Conv2d(cfg[3], cfg[4], kernel_size=(1))]
    layers += [nn.Conv2d(cfg[4], cfg[5], kernel_size=(3))]
    layers += [nn.Conv2d(cfg[5], cfg[6], kernel_size=(1))]
    layers += [nn.Conv2d(cfg[6], cfg[7], kernel_size=(3))]
    
    # 活性化関数のReLUは今回はSSDモデルの順伝搬のなかで用意することにし、
    # extraモジュールでは用意していません

    return nn.ModuleList(layers)
```

####3.offset layerとconfidence layerを生成します####
offset layerはoffset情報offset1,offset2,offset3,offset4,offset5,offset6を生成します
confidence layerはoffset情報confidence1,confidence2,confidence3,confidence4,confidence5,confidence6を生成します

```python
def make_loc_conf(num_classes=21, bbox_aspect_num=[4, 6, 6, 6, 4, 4]):

    loc_layers = []
    conf_layers = []

    # VGGの22層目、conv4_3（source1）に対する畳み込み層
    loc_layers += [nn.Conv2d(512, bbox_aspect_num[0]
                             * 4, kernel_size=3, padding=1)]
    conf_layers += [nn.Conv2d(512, bbox_aspect_num[0]
                              * num_classes, kernel_size=3, padding=1)]

    # VGGの最終層（source2）に対する畳み込み層
    loc_layers += [nn.Conv2d(1024, bbox_aspect_num[1]
                             * 4, kernel_size=3, padding=1)]
    conf_layers += [nn.Conv2d(1024, bbox_aspect_num[1]
                              * num_classes, kernel_size=3, padding=1)]

    # extraの（source3）に対する畳み込み層
    loc_layers += [nn.Conv2d(512, bbox_aspect_num[2]
                             * 4, kernel_size=3, padding=1)]
    conf_layers += [nn.Conv2d(512, bbox_aspect_num[2]
                              * num_classes, kernel_size=3, padding=1)]

    # extraの（source4）に対する畳み込み層
    loc_layers += [nn.Conv2d(256, bbox_aspect_num[3]
                             * 4, kernel_size=3, padding=1)]
    conf_layers += [nn.Conv2d(256, bbox_aspect_num[3]
                              * num_classes, kernel_size=3, padding=1)]

    # extraの（source5）に対する畳み込み層
    loc_layers += [nn.Conv2d(256, bbox_aspect_num[4]
                             * 4, kernel_size=3, padding=1)]
    conf_layers += [nn.Conv2d(256, bbox_aspect_num[4]
                              * num_classes, kernel_size=3, padding=1)]

    # extraの（source6）に対する畳み込み層
    loc_layers += [nn.Conv2d(256, bbox_aspect_num[5]
                             * 4, kernel_size=3, padding=1)]
    conf_layers += [nn.Conv2d(256, bbox_aspect_num[5]
                              * num_classes, kernel_size=3, padding=1)]

    return nn.ModuleList(loc_layers), nn.ModuleList(conf_layers)

```

###まとめ
物体検出SSDモデルの出力offset情報と信頼度情報をどうやって生成することを紹介しました
->答え:
(vgg16+extra+offset+condfidence)

物体検出SSDモデルの出力offset情報と信頼度情報をどうやって生かせることを紹介しました
->答え:
デフォルトボックスを変形させること
デフォルトボックスの信頼度を表すこと

次の章は訓練を紹介したいとおもいます