物体検出SSD-3 : 物体検出で使う用語の整理(3)

# 修正
* SSDの出力の項目で書くべきところがNon Maximum Suppressionのところにあったので修正しました(2024 12/14)

# 参考文献

* 新納浩幸『PyTorchによる物体検出』オーム社, 2020年
* Wei Liu, et al. "SSD: Single Shot MultiBox Detector", ECCV, pp. 21-37, 2016.

# 前回の内容
* SSDのネットワークモデル
* VGG
* L2Normalization
* 補足1: 局所的な情報とグローバルな情報の両方を得るとは
* 補足2: 膨張畳み込み層

https://qiita.com/Syota-Ymauchi/items/465cb10e67fd249ee79a

前回分を見ていない方はこちらから。

# SSDの原論文
https://arxiv.org/pdf/1512.02325

原論文はこちらから

# 今回の内容
* IoU
* SSDの損失関数
* Non Maximum Suppression

# IoU
* 物体検出の精度を評価するための指標で予測領域と実際の正解領域の重なり具合を測る

```math
IoU =  \frac{A∧Bの面積}{A∨Bの面積}
```
![スクリーンショット 2024-12-03 103854.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3897045/72dd9f7f-63e1-b612-9925-83ea15c5a023.png)
* 重なった部分(緑)÷(赤と青の面積の和-重なった部分(緑))というイメージ
* 1に近いほど重なり度合いが高い
* 1に近いほど物体が検出されていると考える
* 座標情報も考慮している(この後具体例で説明)
### IoUの計算例
![スクリーンショット 2024-12-03 114101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3897045/502f7ddd-d05e-16b2-fdc7-3edd3728a217.png)


* 重なり部分(緑)について
* 左端 : max(2,4) = 4
* 右端 : min(7,9) = 7
* 上端 : min(6,8) = 6
* 下端 : max(3,4) = 4

重なり部分(緑)の幅と高さは
幅 : 7 - 4 = 3
高さ : 6- 4 = 2
→ よって、重なり部分の面積は3×2=6 ...(1)
* 和集合は
* オレンジの面積 : (6-3)×(7-2) = 15
* 青の面積 : (8-4)×(9-4) = 20
* 和集合: 20(オレンジ) + 15(青) - 6(重なり部分の緑) = 29 ...(2)
* IoU = オレンジ∧青 / オレンジ∨青 = (1) / (2) = 6 / 29 = 0.207となる
* 今回、物体はないと判断するのが妥当(1よりかなり低いため)

# SSDの損失関数
* クラス分類のロス + オフセットの予測誤差=SSDでのloss
* まず各画像データでの正解データを作成する
#### 正解データ作成
* 画像データの正解データには各物体のBBox(バウンディングボックス)の座標が書かれている
* まずは、この座標を[0, 1]に正規化
* データには1セルにDBoxが複数あり(4or6)全てのDBoxとBBoxとのIoUを計算する
* ある1セルの中のDBoxとBBoxとのIoU値が一番高いもの選び、そのセルの対応するBBoxとする
* そしてそのセルとBBoxとのIoUの値がある値(0.5など)を越えていたらそのDBoxはPositive DBoxとなり、IoUが閾値未満ならNegative DBox(背景)となる
* Positive DBoxとBBoxとのオフセットが計算され,そのオフセットとBBoxのクラス分類用のラベルが教師データとなる

### 実装面では
loc_t : 8732個のオフセットを格納する。
conf_t : 8732個の要素それぞれにクラスラベルを格納する
物体があると判定される閾値は0.5とする
どれも最初は0で初期化
* ある画像に3つのBBox1,BBox2, BBox3が存在していて、対応するクラスラベルとしてlabel1, label2, label3があるとする(正解データにはBBoxの座標と、そのBBoxに対応するクラスラベルが与えられている)
* あるセルの各DBox(4 or 6個)と3つのBBoxとのIoUを求める。一番高いものがそのDBoxと対応するBBoxとlabelとなる。今回はあるk番目のDBoxを着目していて、対応するBBox(3つのBBoxの中でIoUが一番高い)はBBox2でIoUは0.6であったとする
* 対応するBBoxとのIoUの値が閾値(0.5)以上なのでPositive DBoxとなる。閾値未満であればNegative DBoxとなる
* 8732個のDBoxの内のk番目のDBoxがPositive DBoxであればloc_t[k]に対応するBBoxとのオフセットd0、クラスラベルをconf_t[k]に代入。今回はオフセットd0と対応するクラスラベルlabel1が格納される
* なお、Negative DBoxにはconf_tに0(背景)を代入、オフセットは0のまま(オフセットの損失を計算する時にオフセットが0以外で損失を計算するため)
![スクリーンショット 2024-12-06 135243.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3897045/548f1f46-ce5f-37a2-2a59-2678a1c74f99.png)


![スクリーンショット 2024-12-06 135316.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3897045/767fbf65-32b9-1d2d-9899-ed26fda26146.png)

### 損失の計算
* オフセットではPositive DBoxのオフセットのみで損失を計算する
* クラス分類の損失はPositive DBoxのクラス分類の結果の損失とPositive DBoxの定数倍(3倍など)の数のNegative DBoxのクラス分類損失で損失を計算する

### 利用するNegative DBoxの数
* 正解のクラスラベル(conf_t)はほとんど背景
* 仮に全てのconf_tを使用するとする
* ほとんどが背景なのでlossを最小化することを考えると背景ばかり選ばれてしまう
* これを回避するために使用するNegative DBoxの数はPositive DBoxの定数倍に制限する(3倍など)
* 実際に使用するNegative DBoxは損失の大きいNegative DBox(背景なのに背景以外のあるクラスと分類されたNegative DBox)
* 損失の大きいNegative DBoxをソートして先頭からPositive DBoxの数の定数倍だけ選ぶ
### SSDの出力
* 各DBoxの検出結果
* conf_out : 8732個のDBoxの予測クラスラベル(logits値)
* loc_out : 8732個のBBoxとのオフセット。Positive DBoxにはオフセットの値、Negative DBoxは0になっている
* DBoxの座標情報(8732, 4(cx,cy,h,wで4つの値))
### 損失計算
* クラス分類のロス + オフセットの予測誤差
* オフセットの予測誤差 : SmoothL1loss
* クラス分類 : CrossEntropy
### CrossEntropy
```math
-log(\frac{exp(conf_{out}[conf_t[k]])}{\sum_{i=1}exp(conf_{out}[k])})
```
* logの中身はsoftmax関数で正解データをどの確率で予測したかを計算している
* 簡単に式の意味を説明
* 正解クラスラベルをどれだけ高い確率で予測出来ていたかで損失を計上
* 高い確率で正解データを予測していた : 損失は少ない
* 低い確率で正解データを予測していた : 損失は多い
#### SmoothL1loss(オフセットの予測誤差)
x_iはloc_t(正解オフセット),y_iはloc_out(予測オフセット)でnはPositive DBoxの数
```math
loss(x, y) = \frac{1}{n}\sum_{i=1}^{n} z_i
```
```math
where
```
```math
|loc_t - loc_{out} < 1|の時
0.5(x_i - y_i)^2
```
```math
otherwise
```

```math
|x_i - y_i|-0.5
```
* 誤差が小さい場合はL2損失に似た挙動、大きい場合はL1損失に似た挙動
* SmoothL1Lossを使う理由
* 小さい誤差に対して：L2損失の特性
* 誤差が小さい範囲では二乗項を使うため、勾配がスムーズになり学習が加速、微小な位置ずれを効率的に最適化できる
* 大きい誤差に対して：L1損失の特性
* 特に初期段階で誤差が大きい場合や異常値が混在する場合に有効
* L1とL2の良い部分を組み合わせた挙動により、効率的で安定した学習を実現
# Non Maximum Suppression
* ここからはテストデータを適用する時の処理の説明に移る

### Non Maximum Suppressionの処理の概要
* 適切な検出結果を取り出すにはconf_outのクラスラベルの確信度(確率)の高いものを取り出せばよいと思うが、それだけでは不十分
* 同じ物体に対して複数のBBoxが適用されてしまうことがあるから
* つまり、同じ物体に対して複数のBBoxがあるなら、一番確率の高いものを表示すれば良い
### Non Maximum Suppressionの処理
* logits値にSoftmaxを適用
* loc_outから、確信度が閾値(0.01)以上のDBoxに対してBBoxを作成
* それらのBBoxのIoUが閾値(0.5)以上であれば同じ物体に対するBBoxであると判断する(IoUは座標情報も考慮する。)
* 同じ物体に対するBBoxを集め、その中で一番確信度(確率)が高いものをその物体のBBoxとする


# 次回
コーディングに移ります