模型畫的框不可能和人工標註(ground truth)分毫不差,所以要一個「差多少」的分數。最常用的是 IoU(Intersection over Union,也叫 Jaccard index):兩個框重疊的面積除以兩個框合起來的面積。完全重合是 1,完全沒碰到是 0。偵測比賽通常規定 IoU ≥ 0.5 才算「找到」。下面灰色是標註的框,你用滑鼠或手指拖出自己的框。
任務家族:講義從「只回答是什麼」排到「每個像素都要回答」。分類:整張圖一個標籤。分類 + 定位:一個物體,加一個框。物體偵測:多個物體,每個一個類別加一個框。語義分割(semantic):每個像素一個類別,但不分「哪一隻」,兩隻狗是同一片「狗」。實例分割(instance):每個物體各自一個遮罩,兩隻狗分得開。全景分割(panoptic):兩者合起來,可數的東西(thing:人、車)要分實例,不可數的區域(stuff:天空、道路)只要類別,每個像素剛好一個標籤。分割在 C5。
IoU 與 Dice:用像素的對錯來寫,IoU = TP / (TP + FP + FN),Dice = 2TP / (2TP + FP + FN)。Dice 分母裡 TP 算兩次,所以對錯誤比較寬容,數值通常 ≥ IoU;它在二分類時等於 F1。講義的建議:一般比賽用 IoU;小目標或極度不平衡(例如前景只佔 0.1%,醫療影像的腫瘤)用 Dice。
分類 + 定位:如果圖裡只有一個物體,最簡單的做法是一個 CNN(通常先在 ImageNet 預訓練)接兩個頭:一個頭輸出類別分數(softmax loss),一個頭直接回歸 4 個數字 (x, y, w, h)(L2 loss),兩個 loss 加起來一起訓練。問題在於每張圖的物體數不一樣:一隻貓要 4 個數字,三隻動物要 12 個,網路的輸出長度卻是固定的。這就是後面所有方法要繞過的根本困難。
人體姿態估計:同一個「回歸座標」的想法推廣到關節。講義引用 DeepPose(CVPR 2014):把人體表示成 14 個關節點,網路直接回歸 14 組 (x, y),每個點用 L2 loss。
拿 IoU 當 loss:早期框回歸用 L2,但 L2 小不代表 IoU 高。改用 IoU loss = 1 − IoU 之後,不重疊時 loss 恆為 1、沒有梯度。GIoU(CVPR 2019)多減一項 (C − A∪B) / C,C 是包住兩框的最小框,不重疊時也會隨距離變;但一個框被另一個整個包住時,C 就是大框本身,GIoU 退回 IoU。DIoU(AAAI 2020)改減「中心點距離² ÷ C 的對角線²」,直接把中心拉近,講義引用的實驗裡 GIoU 400 次迭代還沒收斂,DIoU 120 次就收斂。CIoU 再加一項長寬比一致性。講義的總結:好的框 loss 要看三件事,重疊面積、中心距離、長寬比。講義筆記也提到把 YOLOv3 的 loss 換成 CIoU,AP 約提升 6%、AP75 約提升 10%。
偵測器會在物體附近吐出很多個差不多的框,每個都有一個信心分數。人只要一個。NMS(non-maximum suppression,非極大值抑制)是一個很簡單的規則:分數最高的留下,和它重疊太多(IoU 超過門檻)的全部刪掉,再從剩下的裡面挑最高的,重複到沒有框為止。下面一步一步跑。
講義的例子:6 個框,分數 0.95、0.9、0.9、0.8、0.7、0.7。取 0.95 當第一個物體;剩下 5 個裡和它 IoU 大於 0.6(可以另外設)的刪掉,留下 0.9、0.8、0.7;再取 0.9 當第二個物體,重複到沒有框。最後選出 0.95 和 0.9 兩個。
NMS + score threshold:R-CNN 和 YOLO 的最後一步都是「先丟掉分數太低的,再跑 NMS」。上面實驗台的兩個滑桿就是這兩個門檻。
soft-NMS:講義的例子是兩匹馬,紅框 0.95、綠框 0.8,綠框和紅框重疊很多。傳統 NMS 直接把 0.8 變成 0;soft-NMS 問的是:與其刪掉,給它 0.4 是不是比較好?M 是目前分數最高的框,bi 和 M 的 IoU 越大,bi 的分數 si 降得越多。兩種寫法:
講義引用的結果:soft-NMS 在高 IoU 門檻評估時比傳統 NMS 好約 2%,而且同一組參數在不同評估門檻下都好;整體約 1% 的提升,不增加訓練和計算成本。
DIoU-NMS:YOLOv4 用的版本,把 NMS 裡的 IoU 換成 DIoU,多考慮兩框中心的距離。中心離很遠的兩個框,即使重疊多,也比較可能是兩個不同的物體,例如講義裡重疊在一起的機車。為什麼不用 CIoU-NMS?CIoU 的長寬比項需要 ground truth,推論時沒有。
Feature NMS:重疊嚴重、IoU 落在「不確定」區間時,再比較兩個框的特徵向量:特徵很像就是同一個物體,不像就兩個都留。
NMS 的根本問題:它是手工規則,不能端到端訓練,門檻要人調。SEC.04 的 DETR 直接把它拿掉。
每個框都判了「找到/沒找到」之後,要替整個偵測器打總分。兩個問題要分開問。Precision:我說「這裡有東西」的框裡,有幾成是對的?Recall:所有真的物體裡,我抓到幾成?兩個數字由一個信心門檻控制:門檻調高,只交出很有把握的框,precision 高但漏掉很多;門檻調低,什麼都交,recall 高但很多是錯的。把所有門檻都試一遍,畫成一條曲線,曲線下的面積就是 AP。
TP / FP / FN:TP 是框對了(IoU 達到門檻、類別也對)。FP 是框錯了,包含同一個物體的重複框:一個物體只能配一個框,第二個框就算位置完美也算 FP,所以 SEC.02 的 NMS 會直接影響分數。FN 是真實物體沒有任何框配上。偵測裡沒有 TN:「背景沒有被框」的數量是無限多,不算。
講義的迷你例子:100 筆資料,真的正類 20 筆。門檻 0.9 時預測 10 個、9 個對:precision 9/10 = 0.90,recall 9/20 = 0.45。門檻 0.3 時預測 30 個、18 個對:precision 18/30 = 0.60,recall 18/20 = 0.90。提高 recall 往往會掉 precision,反之亦然。
AP:PR 曲線下的面積。常見的算法先做「內插」:每個 recall 位置的 precision,換成它右邊(recall 更高處)最大的 precision,讓曲線變成單調往下的階梯,再算面積。實驗台的勾選框就是這一步。
mAP@[.5:.95]:PASCAL VOC 傳統上報 IoU 0.5 的 mAP(寫成 AP50)。COCO 主要指標是 IoU 從 0.50 到 0.95、每 0.05 一個門檻,10 個門檻各算一次 mAP 再平均,對框的精準度更挑剔。講義引用 YOLOv4 在 COCO 上 43.5% AP(65.7% AP50):同一個模型,門檻不同,數字差了 20 多點。
F1 與 Fβ:precision 和 recall 的調和平均。想要平衡兩者,就在驗證集上掃門檻,選 F1 最大的那個。醫療篩檢、瑕疵檢測寧願多抓(高 recall),自動通知使用者寧願少誤報(高 precision)。在測試集上選門檻會洩漏。
為什麼不用 accuracy:類別極度不平衡時 accuracy 幾乎沒意義;PR 曲線在不平衡時也比 ROC 曲線誠實,因為 ROC 對負類數量不敏感。
偵測的難處是「框的數量每張圖不同」。two-stage 的做法是分兩步:第一步先挑出約兩千個「可能有東西」的候選區域(region proposal),第二步才對每個候選做分類和框的微調(R-CNN 系列)。one-stage 拿掉第一步:把圖切成格子,每一格直接輸出固定數量的框和分數,整張圖只跑一次網路(YOLO、SSD、RetinaNet)。兩者都會吐出重複框,都需要 NMS。DETR 則改了問題本身:直接輸出一組框,訓練時強制一個物體只配一個輸出。
Sliding window:把偵測當分類,拿各種大小的窗口滑過整張圖,每個窗口問 CNN「是狗、是貓、還是背景」。問題是位置和尺度的組合太多,每一個都要跑一次 CNN,算不完。
Region proposals:先用便宜的方法找「看起來像一團東西」的區域。Selective search 先把圖切成很多小區塊,再依顏色、紋理、大小、是否被包住等多種相似度逐層合併(hierarchical grouping),合併過程中每一層的區塊都是候選;在 CPU 上幾秒鐘就能給出約 1000 個候選。講義解釋為什麼要多種策略:兩隻貓要靠顏色分,變色龍要靠紋理分,車輪要靠「被車身包住」才算同一個物體。
Bounding box regression:候選框通常有點歪,用回歸預測一組修正量,把框推到更準的位置。可以用在「修正候選框」,也可以直接拿來做整個偵測(YOLO)。
R-CNN(CVPR 2014):selective search 給約 2000 個候選 → 每個縮放(warp)成 227×227 → 各自送進微調過的 AlexNet 抽特徵 → SVM 分類 + 框回歸。問題:(1)推論慢,一張圖要跑 2000 次 CNN;(2)訓練目標是拼湊的:CNN 用 softmax、SVM 用 hinge loss、框回歸用 least squares,三個分開訓練,CNN 的特徵不會因為 SVM 而更新;(3)訓練要 84 小時、佔大量硬碟。
Fast R-CNN:整張圖只跑一次 CNN,得到 conv5 特徵圖,再把每個候選框投影到特徵圖上,用 RoI pooling 切成固定格數(例如 2×2)各取最大值,變成同樣大小,餵給全連接層同時輸出類別(log loss)和框(smooth L1),一起訓練。RoI pooling 是 SPP(spatial pyramid pooling)只用一層金字塔的特例。剩下的瓶頸:候選框還是由網路外的 selective search 產生,變成最慢的一步。
Faster R-CNN(NIPS 2015):讓 CNN 自己提候選。RPN(region proposal network)在共用的特徵圖上滑一個 3×3 窗口,每個位置放 k = 9 個 anchor(3 種大小 × 3 種長寬比的預設框),對每個 anchor 輸出「是不是物體」2 個分數和 4 個修正量。整個網路同時訓練 4 個 loss:RPN 分類、RPN 框、最後的類別、最後的框(原論文用 4 步交替訓練)。anchor 有不同大小,就同時處理了多尺度。
YOLO v1(CVPR 2016):把偵測當成一個回歸問題。圖縮到 448×448,切成 S×S 格,每格預測 B 個框(各 5 個數:x, y, w, h, confidence)和 C 個條件類別機率,輸出 S×S×(5B + C);PASCAL VOC 的 S = 7、B = 2、C = 20,就是 7×7×30。confidence 的目標值是 Pr(Object) × IoU;推論時類別機率乘上 confidence 得到每個框每一類的分數,再做 score threshold 和 NMS。訓練 loss 是 sum-squared error,但有三個調整:只在格子裡真的有物體時才罰類別;只罰「負責」的那個框(和真實框 IoU 最高的);有物體的座標誤差乘 λcoord = 5,沒物體的 confidence 誤差乘 λnoobj = 0.5,不然大量空格子的梯度會壓過一切;寬高取平方根,讓小框的誤差更有份量。速度 45 fps,精簡版 150 fps。講義引用的錯誤分析:YOLO 把背景誤判成物體的比例 4.75%,Fast R-CNN 是 13.6%(一次看整張圖,有全局資訊);但定位錯誤佔 19.0%,Fast R-CNN 只有 8.6%。
YOLO v2:改預測相對於 anchor 的偏移量,中心點用 sigmoid 限制在本格之內,訓練更穩定,mAP 提升約 5%;格子從 7×7 改成 13×13,每格 5 個 anchor(大小用 k-means 從資料集統計出來),每個 anchor 各自有類別。講義的數字:加 anchor 後 mAP 從 69.5 小降到 69.2,recall 卻從 81% 升到 88%;整體比 v1 進步 15.2%。
YOLO v3:檢測頭分成三個尺度,13×13、26×26、52×52(32、16、8 倍下採樣),每個位置 3 個 anchor × (4 + 1 + 80 類)。下採樣多的感受野大,負責大物體;下採樣少的負責小物體。backbone 換成用 residual 結構(3×3 與 1×1 卷積加 shortcut)疊深的 Darknet-53。
YOLO v4:架構和 v3 相同,各部分換成近年有效的技巧。Mosaic:四張圖隨機縮放、裁切、拼成一張,增加小目標(COCO 裡小目標佔 41.4%,卻只出現在 52.3% 的圖裡),也讓單張 GPU 不需要大 batch。CSP(cross stage partial)backbone CSPDarknet53、DropBlock 正則化、Mish activation、SPP + PAN neck。框 loss 用 CIoU,NMS 用 DIoU-NMS。COCO 43.5% AP、65.7% AP50,Tesla V100 上約 65 FPS。
Class imbalance:講義問「簡單的 one-stage 能不能和 two-stage 一樣準?」RetinaNet(2017)的假設是:輸的原因不是位置或特徵,而是類別不平衡。one-stage 每張圖要評估 104 到 105 個候選(SSD),幾乎都是容易分的背景;每個背景的 loss 很小,但數量太多,總和與梯度被它們主導。two-stage 靠兩道關卡擋掉:proposal 先把候選縮到 1 到 2 千個;分類時再固定前景與背景 1:3 的比例取樣,或做 online hard example mining(OHEM)。
Focal loss:直接依「多容易」把 loss 打折,讓訓練偏向有意義的困難樣本。講義筆記引用的實驗:focal loss 比類別加權、OHEM、OHEM + 1:3 取樣都好,COCO AP 提升約 3 點;實作上把前景機率初始化成 0.01,避免一開始大量背景被判成前景讓 loss 爆掉。
one-stage vs two-stage 總結:two-stage 準、慢、流程複雜、各元件難一起最佳化;one-stage 快、簡單、端到端,早期輸在定位和不平衡,focal loss 與 v2 到 v4 的改進後差距已大幅縮小。兩者都還是 anchor + NMS 的框架。
DETR:把偵測重新定義成集合預測(set prediction)。CNN backbone 抽特徵 → Transformer encoder-decoder → 固定數量的 query 各輸出一個類別(含「沒有物體」)加一個框。訓練時用二分圖匹配(bipartite matching,以 Hungarian 演算法求解)把預測和真實標註一對一配對,再算 loss。好處:不用設計 anchor 規則,也不用 NMS,因為「一個物體只對應一個 query」已經寫進訓練目標。代價:收斂慢、要更多 epoch,初期小物體表現較弱。後續:Deformable DETR 讓每個 query 只看少數取樣點,加快收斂、改善小物體;FCOS 走 anchor-free 的逐像素回歸,用 centerness 分支壓低品質差的框;GLIP、Grounding DINO 用文字描述取代固定類別表(open-vocabulary detection)。講義的結論:架構之間的競爭往往不是誰準確率高,而是誰用更少的人工設計假設達到同樣效果。
這個模組最常被講錯的幾句話。