---
tags: 辨識模型
---
# YOLO notes (主要以 YOLO v3 為例)
### YOLO 基本概念
<a id="YOLO的座標系統"></a>
##### <font color=blue>:mag: YOLO 的座標系統</font>

Cx, Cy 是 feature map 中 grid cell 的左上角坐標,在 yolov3 中每個 grid cell 在 feature map 中的寬和高均為 1。如上圖情形,這個 bbox 邊界框的中心屬於第二行第二列的 grid cell,它的左上角坐標為(1,1),故 Cx=1,Cy=1。公式中的 Pw、 Ph 是預設的 anchor box 映射到 feature map 中的寬和高 (anchor box 原本設定是相對於 416 * 416 坐標系下的坐標,在 yolov3.cfg 文件中寫明了,代碼中是把 cfg 中讀取的坐標除以 stride 如 32 映射到 13 * 13 的 feature map 坐標系中)。
:star: 可以舉個例子嗎?我聽不懂QQ
如果有一個 object 落在 row 0 column 2,此時的 Cx = 0, Cy = 2。 如上圖標示,bx, by (object 中心點) 就是 $Cx + \sigma(t_x)$, $Cy + \sigma(t_y)$,也就是原點加上與原點的差。
bx, by, bw, bh 詳情請看:[邊匡預測](#邊匡預測)
##### <font color=blue>:mag: IOU / GIOU / DIOU / CIOU</font>
:star: IOU 會用在 YOLO 的什麼地方?
1. NMS (non-maximal supression),主要作用是 YOLO 會 predict 出很多 bounding box,需要把匡到同一個 object 選出 confidence score 最高的那個,排除 IOU 高於某個 threshold 的 bounding box (ex. threshold > 0.7),因為 IOU 大表示其實是同一個。
2. 計算 bounding box 的預測準確度 (傳統是看 x, y, w, h 的 L2 誤差),當作是 loss gradient 學習的方向。
:star: 各種 IOU 介紹 ([精華參考資料](https://medium.com/@jacksonchou/distance-iou-loss-faster-and-better-learning-for-box-regression-9df8fc627e8))
:crossed_swords: [IOU (intersaction over union)](https://www.pyimagesearch.com/2016/11/07/intersection-over-union-iou-for-object-detection/)
詳情直接參考標題連結,多說無益。
列個公式比較清楚:

* IOU 缺點:IOU-loss 只在 predict box 與 ground box有重疊的時候才會有 gradient ,在沒有重疊的情況下並不會有 gradient (因為 loss 都是 1)
:crossed_swords: GIOU (general IOU)
* 重點:對於 non-overlapping 的情況, GIOU 增加了上述式子最後一項懲罰, C 代表涵蓋 predict box 與 ground truth box 的最小 bounding box 不清楚的話看下圖例子

公式:

主要就是再加上一個不該被匡出的區域 Loss,這樣的話在 non-overlapping 的情況,也可以提供 gradient。
缺點:雖然改善了 non-overlapping 的情況,但如果 predict box 完全包含在 ground truth box 時, GIOU 就會退化成 IOU ,不知道學習的方向。
舉例:

在以上的情況下,不管是 IOU loss 還是 GIOU loss 都是一樣的,但 DIOU 還加入了中心點距離的因素,可以解決這個問題。
:crossed_swords: DIOU (distance IOU)
重點整理:

1. 與 GIoU loss 類似,DIoU loss 在與目標框不重疊時,仍然可以為邊界框提供移動方向。
2. DIoU loss 可以直接最小化兩個目標框的距離,因此比 GIoU loss 收斂快得多。
3. 對於包含兩個框在水平方向和垂直方向上這種情況,DIoU 損失可以使回歸非常快,而 GIoU 損失幾乎退化為 IoU 損失。
公式:

缺點:沒有考慮到邊匡的長寬比。
:star: GIOU vs DIOU gradient comparison

從上圖中我們可以看到,GIoU在回歸的過程中,從損失函數的形式我們發現,當IoU為0時,GIoU會先盡可能讓anchor能夠和目標框產生重疊,之後GIoU會漸漸退化成IoU回歸策略,因此整個過程會非常緩慢而且存在發散的風險。而DIoU考慮到anchor和目標之間的中心點距離,可以更快更有效更穩定的進行回歸。
:crossed_swords: CIOU (complete IOU)
* 一個好的目標框回歸損失應該考慮三個重要的幾何因素:重疊面積、中心點距離、長寬比。
GIoU:為了歸一化坐標尺度,利用 IoU,並初步解決 IoU 為零的情況。
DIoU:DIoU 損失同時考慮了邊界框的重疊面積和中心點距離。
然而,anchor 框和目標框之間的長寬比的一致性也是極其重要的。基於此,作者提出了 Complete-IoU Loss。
公式:



上述损失函数中,CIoU 比 DIoU 多出了阿尔法和 v 这两个参数。其中阿尔法是用于平衡比例的参数。v 用来衡量 anchor 框和目标框之间的比例一致性。从阿尔法参数的定义可以看出,损失函数会更加倾向于往重叠区域增多方向优化,尤其是 IoU 为零的时候。
缺點:暫無。
##### <font color=blue>:mag: feature map / receptive field</font>
:star: CNN 裡面說到的 feature map 是什麼?


:star: 什麼是 receptive field?

一个输入大小为 11×11的A, 经过一个过滤器大小为 3×3,步长为 1 的卷积核卷积之后,得到一个大为9×9的特征映射。可以看到在 B 中一个 3×3 的区域,在 A 中的感受视野为 5×5。B 经过一个大小为 3×3 ,步长为 1 的卷积核卷积之后,得到一个 7×7 的特征映射。因此在 B 中的一个 1×1 的区域在 A 中的视野就为 3×3。因此,C 中一个 1×1 的区域在 A 的视野就为 5×5。

计算公式为:
其中 [公式] 表示第 i 层输入的一个区域, [公式] 表示第 i 层的步长, [公式] 表示第 i 层卷积核的大小(filter size)。此计算不需要考虑 padding size。
##### <font color=blue>:mag: anchor box</font>
anchor box 是先驗匡,主要描述的是物件的長寬比例,讓 YOLO 在預測物件的長寬大小時,有一個比較好的初值,不會從零開始預測。
舉例來說在 coco dataset 中,要辨識的 object 有 80 種,但可能全部物件會出現的長寬比不外乎 1:1, 2:1, 1:2, 2:3...等,如果在模型預測物件長寬時,可以從這個比例為基礎去縮放長、寬,無論在 training or testing 都可以有比較好的結果。
:star: 怎麼得到 YOLO 使用的 anchor box 呢?
* 用 kmeans 的方法來計算出來的。
會先指定有幾個 centroid 讓演算法去算出所有圖中的長寬比的 cluster 歸類,最初是用一般的<span style="color:yellow">歐式距離</span>來衡量 bounding boxs 跟 cluster 的距離,但使用歐氏距離會讓大的 bounding boxes 比小的 bounding boxes 產生更多的 error,而我們希望能通過 anchor boxes 獲得好的IOU scores,並且IOU scores是與box的尺寸無關,所以衡量距離的方式被改成<span style="color:yellow">「IOU 的值」</span>。
:star: anchor box 在 YOLO 模型中怎麼被使用?
YOLO3 default 的 anchor 數量是 9 個,會由小排到大。YOLO3 理論是將輸入圖像分成 SxS 個格子(有三處進行檢測,分別是在 52x52, 26x26, 13x13 的 feature map 上,即 S 會分別為 52, 26, 13),若某個物體 Ground truth 的中心位置的坐標落入到某個格子,那麼這個格子就負責檢測中心落在該柵格中的物體。([詳情參考這裏]())
:pushpin: 通常用 convolution 做 feature 的萃取會越卷積越小,感受視野 (receptive field) 也就越大,在 YOLO 的三次檢測中,每次對應的感受野不同,32 倍降採樣的感受野最大 (13x13),適合檢測大的目標,每個 cell 的三個 anchor box 為 (116 ,90); (156 ,198); (373 ,326)。 16 倍 (26x26) 適合一般大小的物體,anchor box 為 (30,61); (62,45); (59,119)。 8 倍的感受野最小 (52x52),適合檢測小目標,因此 anchor box 為 (10,13); (16,30); (33,23)。
參考資料:[這裡](https://blog.csdn.net/qq_40728805/article/details/103522839?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159431130719724839228730%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=159431130719724839228730&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v3~pc_rank_v2-4-103522839.first_rank_ecpm_v3_pc_rank_v2&utm_term=anchor+target+yolo)
##### <font color=blue>:mag: bounding box</font>
在 feature map 用 x, y, w, h (x,y,寬,高) 中表示的框,又稱作邊界框,範例可以參考[YOLO 的座標系統](#YOLO的座標系統)。(跟 anchor box 是不一樣的東西喔!)
### YOLO 模型架構 ([超詳細介紹](https://blog.csdn.net/dz4543/article/details/90049377?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-14.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-14.nonecase))
##### <font color=blue>:mag: backbone</font>
:star: darknet53 (作者自幹的 framework,覺得 Resnet 不讚)
1. 相較於 YOLOv2 的 darknet19,YOLOv3 選擇使用深度較深的架構,提升了準確度但稍微犧牲了預測時間 (但還是可以進行 realtime prediction)。
2. 採用 Residual Block 的架構,可以讓模型變深但是 train的起來。
3. 整個 v3 結構裡面,是沒有池化層 (pooling) 和全連接層 (FC) 的。前向傳播過程中,張量的尺寸變換是通過改變卷積核的步長 (stride) 來實現的
:star: darknet53 structure

* 由五個 residual blocks 組成,旁邊的層數表示串了幾個 blocks。詳細圖說可以參考:[FPN_structure](#FPN_structure)
##### <font color=blue>:mag: Spatial Pyramid Pooling Block(SPP) and Dense Net Block</font>

看圖應該就知道了,就不多說囉~
:star: YOLOv3 哪裡有使用 SPP 跟 DC block?
基本上這兩招會接在 backbone 後面,也就是 darknet53 之後,更進一步的把特徵萃取出來。
<a id="FPN_structure"></a>
##### <font color=blue>:mag: Feature Pyramid Network (FPN) structure (13x13, 26x26, 52x52)</font>
如同前面也都有提到的,在 YOLOv3 的 bounding box 預測會從 darknet53 的不同層抽出 feature maps 出來做 convolution 再預測,以下有完整的模型架構圖讓大家可以清楚了解。

:pushpin: 需要注意的是,上圖中的 no. 不是模型的層數,而是 YOLO 每個 steps 的編號,紀錄每個步驟是在做什麼的東西,可以對照[這個網站](https://blog.csdn.net/dz4543/article/details/90049377?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-14.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-14.nonecase)中的紀錄。(<span style="color:yellow">紅色的字是小編辛苦的用眼睛對,自己編上去的註解</span>)
看懂上面的架構圖後,搜尋 YOLOv3 常常會看到的架構,就會看得很懂啦~~
不負責任的都貼上來:


### YOLO prediction
<a id="邊匡預測"></a>
##### 邊匡預測

:pushpin: 你知道 YOLO 預測的 x, y, w, h 到底是什麼嗎?
> YOLO 不是 predict bounding box 的絕對座標,而是 predit 偏移量,又稱 offsets (差值)!!
> 所以意思就是說,需要再透過轉換!
:star: Training time
對於訓練時用的 groundtruth 的4個坐標去做差值和比值得到tx, ty, tw, th,分別與網絡學習的偏移量 tx, ty, tw, th 做誤差分析,與 ground truth 匹配的 anchor box(如何匹配下面講)計算坐標誤差、置信度誤差(此時 target 為 1)以及分類誤差,而其它的anchor box只計算置信度誤差(此時 target 為 0)。
$t_x = G_x -C_x$
$t_y = G_y - C_y$
>其中 $t_x, t_y$ 可以直接求 bbox 中心距離 grid cell 左上角的坐標的偏移量
$t_w = log\frac{G_w}{P_w}$
$th = log\frac{G_h}{P_h}$
> 其中 tw, th 是物體所在邊框的長寬和 anchor box 長寬之間的比率
置信度誤差 pred_conf,如果某個 grid cell 無 object 則Pr(Object) = 0,否則 Pr(Object) = 1,然後分別與網絡輸出的 pred_conf(0-1之間)做誤差分析,類別誤差 pred_cls,通過判斷選取的最好的那個 anchor box 對應 ground truth 類別 (one-hot向量) 與預測 pred_cls(0-1之間)來做類別誤差分析。
:star: Inference time
在測試階段,將每個柵格的 conditional class probabilities 與每個 bounding box 的 confidence 相乘,這樣可得到每個 bounding box 的具體類別的 confidence score,乘積既包含了 bounding box 中預測的 class 的 probability 信息,也反映了 bounding box 是否含有 Object 和 bounding box 坐標的準確度:
$Pr(Class_i|Object)∗Pr(Object)∗IOU(predGroundtruth)=Pr(Class_i)∗IOU(predGroundtruth)$
##### <font color=blue>:mag: YOLO bounding box prediction</font>

如上圖所示,以最大的邊匡預測舉例 (13 X 13),一張圖進入 darknet53 後,得到 feature map 後 (step 74),再進行幾次 convolution 轉換,最後得到 final feature map ,並進行 predict (step 82) ,可搭配[這裡](#FPN_structure)閱讀。
最後每個 13 X 13 的 grids 都會有相對應的 predict bounding boxes,以 YOLOv3 coco dataset 訓練資料為例,資料集有 80 個類別,每個 grid 會預測 3 個 bounding boxes,所以計算如下:
feature map 的一條抽出來(如上所示),會有 x, y, w, h, object(probability), class (probability / 80 類) > (5 + 80) * 3 (bboxs) = 255



##### <font color=blue>:mag: Non-Maximum Suppression (NMS)</font>
[這篇文章](https://medium.com/@chih.sheng.huang821/%E6%A9%9F%E5%99%A8-%E6%B7%B1%E5%BA%A6%E5%AD%B8%E7%BF%92-%E7%89%A9%E4%BB%B6%E5%81%B5%E6%B8%AC-non-maximum-suppression-nms-aa70c45adffa)寫的太好了,大家就直接看吧!
:star: 重點整理
:pushpin: NMS 核心概念
<span style="color:yellow">除去 bounding boxs 重複匡到的 object,選一個 object 信心水準最高的留下。</span>
:pushpin: NMS 處理步驟
1. 先看哪個 BBox 的信心程度最高,那個 BBox 會進去「確定是物件集合」(途中的 selected objects)內
2. 其他 BBox 和剛選出來的 BBox 算 IoU,然後算出來的 IoU 大於設定好的閾值的 BBox,那些 BBox 的信心度會被設定為 0 (也就是這個 BBox 重複計算要刪掉)。
然後在 Repeat 1 和 2 步驟直到所有的 BBox 都被處理完,這時候被存在「確定是物件集合」的物件就是最後結果。
:pushpin: 可調參數
1. object probability threshold: 這個閥值決定了多少被預測出來的 bounding box 會被排除,如果是 object 機率很低,連 NMS 的步驟都不會進去 (如參考示意圖的步驟 1 > 2)
2. IOU threshold: 選出有一定信心水準為 object 的 bbox 後,會以最高信心水準的 bbox 當基準,排除 IOU 太高的其他 bbox (這樣會被認為是匡到同一個 object)。所以如果有 2 個物件相鄰,太低的 IOU threshold 就有可能不小心把需要的 bbox 排掉。
:pushpin: 參考示意圖

### YOLO loss function
大家可以參考 [1. 這裡](https://blog.csdn.net/weixin_43384257/article/details/100986249?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param),[2. 那裡](https://blog.csdn.net/just_sort/article/details/106303979?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-5.channel_param),真的已經無力再寫了....
##### <font color=blue>:mag: classification</font>
##### <font color=blue>:mag: bounding box</font>