SSDのDefault Box作成方法を実装してわかったこと

# SSDのDefault Box作成方法を解析してみた

数ヶ月前ぐらいにSSD (Single Shot Multibox Detector) の細かいところの知識不足を少し悩んできたので、論文とGithubなどで見つけた実装をみながら少しずつ自分のSSDを構築して行こうと決めました。正直、まだ終わってないんですが、SSDに対して重要な機能、Default Box (Prior) の作成方法がだいたいわかったので皆さんに共有したいと思いました。

### Default Boxとは？

この記事を読んでいるなら、だいたいDefault Boxがどういうことかわかっていると思いますが、念のために少しだけ説明します。SSDは、画像を処理する時にFeature Mapという、畳み込みされた画像を出力します。Feature Mapと数とサイズはモデル設定で指定しますが、基本的に五つか六つぐらいです。そのFeature Mapから物体を認識するために物体か現れそうな領域を指定してします、その領域はDefault Box（Priorと呼ぶ場合もあります）と呼ばれて、分類や回帰を行うために使われています。

一つのDefault Boxのセットを可視化してみるとこんな感じです。私のモデルの設定だと合計で8732個が作成されます。
![example.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686250/cb1a7265-ffe2-6e55-2b84-5a1ec1e3fe2d.png)
COCO Dataset 2017の画像です。

### SSD論文のDefault Boxの計算説明

論文の説明によるとDefault Boxを計算するために、Scale（具体的な定義はないが、物体の規模のようなもの、Aspect Ratios (Default Boxの縦横比）とFeature Mapのサイズが必要です。

論文では、scaleはこの関数で定義されています。mはfeature mapの数でkは何番目のfeature mapです。そしてs_minとs_maxは画像内にある物体のサイズによって決めるものです。決める方法があると言いたいんですが、特になさそうです。

関数自体は若干複雑に見えますが、簡単にいうとs_minとs_maxの間をfeature mapの数と同じ量に平等に分けています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686250/ca987c57-7941-68da-6d39-b52a375858ca.png)
例えば s_min = 0.2、s_max = 0.9と m = 6 の場合では、s_k は [0.2, 0.34, 0.48, 0.62, 0.76, 0.9] になります。各scaleは平等に0.14に離れています。

Aspect Ratios（縦横比）も s_min と s_max と同じように物体によって決めることです。論文では、{1, 2, 3, 1/2, 1/3} の Aspect Ratio が使われたと書かれています。論文見るだけで少し不明だったけど、(2, 1/2) と (3, 1/3) はコンビみたいなものなので、Aspect Ratio を減らすという話であれば基本的に 3 と 1/3 の Aspect Ratio を使わないという意味です。

Feature Mapsは一番（個人的に）わかりやすい部分でしたが、単純にSSDの中の分類と回帰ヘッドに渡す畳み込み層の出力のサイズです。例えば、私のモデルでは最初の出力は 38 x 38 で、最後の出力は 1 x 1 です。

上記の必要な部分が揃えば、Default Box を計算できます。Default Box の縦横をこの関数で計算します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686250/c8632477-bfcd-b97b-20a1-34e295843791.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686250/3f240779-ed26-3bdc-5ed4-2d9ca2615507.png)

そして Default Box の真ん中のポイントのcxとcy点をこれで計算できます。ここの f_k 単純にfeature mapのサイズです（38など）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686250/af62dde2-8862-cca8-0e5d-ff4066740906.png)

ちなみに、Default Boxを表す時に [cx, cy, w, h] というパターンは一般です。

### Default Box作成

上記で説明された cx, cy と w, h の計算は各 feature map の各 aspect ratio のために行います。但し、1 は少し例外です。1 の 場合は二つの Default Box を計算します。普通の scale で計算した Default Box ともう一つ scale で計算したものです。もう一つの scale の計算方法は下記の関数で定義されています。現状の feature map の scale と一個上の scale で計算できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/686250/ed08b89c-ad80-554b-e52c-46a01c7b2ddc.png)

1の Aspect Ratio の Default Box は一つずつです。{1, 2, 3, 1/2, 1/3} の場合は、各ブロックによって六つの Default Box が作成されます。{1, 2, 1/2} の場合は、四つが作成されいます。

### SSD論文とSSD実装の異なるところ

Default Box をどうやって作成するのを理解するために、いくつかの実装を見てきたんですが、論文を読んでもわからないところがいつかありました。

まずは、stepsという変数がよく見かけます。f_kは、画像サイズをstepで割ることで計算しています。特にどこにも説明がなくて、論文にも書かれていないんですが、steps は画像のサイズをfeature mapのサイズで割って計算したものです。例えば 300 を 38 で割ると 7.89 -> 8 になります。
`steps: [8, 16, 32, 64, 100, 300]`

他の引っかかったところはAspect Ratioの設定です。このような書き方が多いです。
`aspect_ratios: [[2], [2,3], [2,3], [2,3], [2], [2]]`
1/2 とか 1/3 がないので「なんじゃこれ」と思ったけど、単純に 2 と 1/2 を 2 だけで洗わせて、3 と 1/3 を 3 だけで表せています。[2,3] はつまり {1, 2, 3, 1/2, 1/3} という意味です。

scalesはこのような設定の書き方が普通です。
`scales: [30, 60, 111, 162, 213, 264, 315]`
これは、すでに計算したs_kを画像サイズにかけたものです。s_k が 0.1 の場合であれば scales の値は 30 となります。

最後に、これは人によって当たり前に見えるかもしれませんが、2 と 1/2 の Default Box を計算する時に 2 の w と h のみを計算して、1/2 の Default Box に 2 の h を w として使って、w を h として使います。なぜかというと `sqrt(2) == 1 / sqrt(1/2)` と `sqrt(1/2) == 1 / sqrt(2)` だからです。

### 最後に

最後まで読んでいただきありがとうございます！私は母国語は日本語ではないので、うまく説明できてないところや変な言い方を使ったところはいくつかあるかもしれません。わからないところなどあれば、コメントいただけたらできるだけ回答しようとします！

SSDを実装しながらどんどん投稿して行きたいと思っていますので、次の投稿も楽しみにしておいてください！

※ この投稿に載っている関数は全てSSD論文からとったスクリンショットです。
(https://arxiv.org/pdf/1512.02325.pdf)