【目標檢測】2萬字詳解 RCNN系列 YOLO系列 YOLOv3程式碼實現全流程詳解 pytorch
目標檢測概述
之前的MTCNN實現了單類多目標的高效檢測,而現實中更普遍的任務是多類多目標檢測。
目標檢測可劃分為3個發展階段:
- 傳統的目標檢測
區域選擇:滑動視窗
特徵提取:Harr、SIFT、HOG等特徵提取演算法
分類器:如常用的SVM模型
基於滑動視窗的區域選擇策略沒有針對性,時間複雜度高,視窗冗餘;
手工設計特徵費時費力,且對於多樣性的變化沒有很好的魯棒性。 - 基於Region Proposal的深度學習目標檢測演算法
使用 region proposal+CNN 代替傳統目標檢測使用的 滑動視窗+手工設計特徵
region proposal利用影像中的紋理、邊緣、顏色等資訊預先找出圖中目標可能出現的位置,獲取的候選視窗要比滑動視窗的質量更高, 可以在選取較少視窗(幾千個甚至幾百個)的情況下保持較高的召回率。以RCNN系列為代表。 - 基於迴歸方法的端到端的深度學習目標檢測演算法
端到端(End-to-End)的目標檢測方法,不需要將檢測過程分為兩步(two-stage), 用region proposal來選擇區域,而是把目標檢測問題,當作迴歸問題,一步(one-stage)直接完成分類和定位。
以YOLO系列為代表,一張圖只需看一次,這也是YOLO(You Only Look Once)名字的由來。
RCNN系列
R-CNN
流程:
- 輸入影像,使用選擇性搜尋演算法(selective search)評估相鄰影像之間的相似度,把相似度高的進行合併,對合並後的區塊打分,選出2000個左右的region proposal(建議框),並把所有 region proposal 裁剪/縮放成固定大小。
- 將歸一化後的region proposal 輸入CNN網路,提取特徵。
- 對於提取到的CNN特徵,用SVM分類來做識別,用線性迴歸來微調邊框位置與大小,其中每個類別單獨訓練一個邊框迴歸(bounding-box regression)器。
不足:
- 2000個左右的候選框都需要進行卷積操作,計算量依然很大,其中有不少是重複計算。
- 訓練分為多個階段,步驟繁瑣:region proposal、CNN特徵提取、SVM分類、邊框迴歸。
- 訓練耗時,佔用磁碟空間大:卷積出來的特徵資料還需要單獨儲存。
Fast R-CNN
流程:
- 利用selective search 演算法在影像中從上到下提取2000個左右的Region Proposal。
- 將整張圖片輸入CNN,進行特徵提取。
- 把建議框對映到CNN的最後一層卷積feature map上。
- 通過RoI pooling層(類似SPP精簡版)使每個建議視窗生成固定尺寸的feature map。
- 使用Multi-task Loss(多工損失函式)對Softmax Loss(分類概率) 和Smooth L1 Loss(邊框迴歸)聯合訓練。
SPP-net
R-CNN 之所以要將建議框crop / warp成固定尺寸,是因為網路最後是全連線層。 空間金字塔池化層(Spatial Pyramid Pooling,SPP)使用多尺度池化,然後將結果拼接。可以在不限制輸入大小的情況下,固定輸出尺寸,有效避免了R-CNN演算法對影像區域剪裁、縮放操作導致的影像物體剪裁不全以及形狀扭曲等問題。
輸入圖片的某個位置的特徵反映在特徵圖上也是在相同位置。基於這一事實,對某個RoI區域的特徵提取只需要在特徵圖上的相應位置提取即可。SPP-net 最重要的改進在於,對原圖只做一次特徵提取,而不是對所有region proposal都做卷積,解決了重複特徵提取的問題,極大地提高了檢測速度。
Faster R-CNN
流程:
- 將整張圖片輸入CNN,進行特徵提取。
- RPN層,用於生成候選框,並利用softmax判斷候選框是前景還是背景,從中選取前景候選框(因為物體一般在前景中),並利用bounding box regression調整候選框的位置,從而得到特徵子圖(proposals)。
- RoI pooling層 生成固定尺寸的feature map
- 通過全連線層判斷proposal的類別,同時再次對bounding box進行regression從而得到精確位置。
selective search 演算法是非常耗時的,Faster R-CNN最大的貢獻就是RPN(Region Proposal Networks)網路,創造性地採用卷積網路自行產生建議框,並且和目標檢測網路共享卷積網路,使得建議框數目從原有的約2000個減少為300個,且建議框的質量也有本質的提高.。
RPN具體步驟:
- 生成錨框 anchors
經過RPN層的3x3卷積後每個feature map上的一個點,生成9個anchor(3種尺寸×3種比例)。anchor分為前景和背景兩類(先不管物體類別,只用區分它是前景還是背景即可)。anchor有[x,y,w,h]四個座標偏移量,x,y表示中心點座標,w和h表示寬度和高度。 - 判斷選區是前景還是背景
輸出分為兩部分,一部分在1x1卷積後,reshape成一維向量,經過softmax來判斷anchors是前景還是背景,由於感興趣的物體位於前景中,大量背景anchors將被捨棄。 - 確定建議框位置
另一部分經1x1卷積後用來確定建議框的位置,也就是迴歸anchors的 [x,y,w,h] 座標值。 - 輸出特徵子圖 proposal
對anchors做非極大值抑制(NMS)等篩選處理,至此得到最終的proposals,即物體的粗糙定位。 - RoI pooling層 生成固定尺寸的feature map。
- 通過全連線層和softmax得到分類概率,並對建議框做最後迴歸調整。
Faster R-CNN用resNet101模型作為卷積層,在voc2012資料集上可以達到83.8%的準確率,超過YOLO SSD和YOLOv2。 其最大的問題是速度偏慢,每秒只能處理5幀,達不到實時性要求。
YOLO系列
YOLOv1
針對於two-stage目標檢測演算法普遍存在的運算速度慢的缺點,YOLO創造性的提出了one-stage端到端演算法,將目標檢測重新定義為單個迴歸問題,也就是將物體分類和物體定位在一個步驟中完成,直接在輸出層迴歸bounding box的位置座標和所屬類別概率。通過這種方式,YOLO可實現45幀每秒的檢測速度,完全能滿足實時性要求。
YOLO的使用流程非常簡潔:
- resize圖片大小至448×448
- 傳入單個卷積網路
- 根據模型置信度做非極大值抑制
實現原理:
將輸入影像劃分成
S
∗
S
S * S
S∗S個網格,如果一個物體的中心點落入一個grid cell(單元格)內,那麼這個grid cell就負責檢測這個物體。每一個grid cell預測
B
B
B個bounding boxes,以及這些bounding boxes的分數。這個分數反映了模型預測這個grid cell是否含有物體,以及是這個物體的可能性是多少。
定義 c o n f i d e n c e = P r ( O b j e c t ) ∗ I O U p r e d t r u t h confidence=Pr(Object)*IOU^{truth}_{pred} confidence=Pr(Object)∗IOUpredtruth ,如果這個 cell 中不存在物體,則得分為0 ;否則的話,分數為 predicted box(預測框)與ground truth(真實框)之間的 IoU(交併比)。
每個 bounding box 由五個預測值組成:x,y,w,h,confidence。座標(x,y)代表了 bounding box 的中心點相對於 grid cell 邊界的值,(w,h) 則是 bounding box 的寬和高相對於整幅影像的值,confidence 就是 IoU 值。
在測試階段,把每個柵格的條件類別概率乘上每個 bounding box 的 confidence,這樣既包含了 bounding box 包含物體的類別資訊,也包含了預測框和真實框的符合程度。
圖片劃分為
S
×
S
S×S
S×S個grid , 每個grid cell預測
B
B
B個bounding boxes,類別數為
C
C
C。預測值是一個
S
×
S
×
(
B
∗
5
+
C
)
S×S×(B*5+C)
S×S×(B∗5+C)的張量。在論文中,使用 PASCAL VOC 資料集,
S
=
7
,
B
=
2
,
C
=
20
S=7,B=2,C=20
S=7,B=2,C=20, 最終預測值為
7
×
7
×
30
7×7×30
7×7×30的張量。
網路模型
YOLO檢測網路結構借鑑了GoogLeNet ,用1x1+3x3卷積層簡單代替 inception 模組,包括24個卷積層和2個全連線層。
特點:
- 使用 224 ∗ 224 224*224 224∗224的影像預訓練分類樣本,再改為 448 ∗ 448 448*448 448∗448訓練檢測樣本。
- 啟用函式由ReLU改為PReLU。
- 輸出層為全連線層,因此在檢測時要求輸入影像尺寸和訓練影像相同。
損失函式
- 第1行:bounding box 中心點座標 ( x , y ) (x, y) (x,y)損失
- 第2行:bounding box 寬高
(
w
,
h
)
(w, h)
(w,h)損失
相同值的寬高誤差對不同大小的目標影響是不一樣的,比如同樣是寬度相差2個畫素,對小目標的預測影響很大,對大目標則無足輕重,因此加根號的目的是拉開這種差距,使得同樣的誤差對大目標的損失更小,對小目標的損失更大。 - 第3、4行:bounding box 的置信度損失
分為包含物體和不包含物體兩部分,包含物體的置信度只在每個grid cell的兩個bounding boxes中選擇IoU大的計算,因此每個grid cell只能預測一個物體,這是YOLOv1的一個缺陷。 - 第5行:分類損失
只有在grid cell包含物體的時候才計算。
YOLO最大的特點就是速度快,處理速度達到45fps,fast版本(網路較小)甚至可以達到155fps。
不足之處有以下幾點:
- 一張圖片最多隻能檢測 7 ∗ 7 = 49 7*7=49 7∗7=49個物體。
- 每個grid cell只有兩個bounding boxes,只對應一個類別,容易漏檢,相比較Faster R-CNN雖然降低了背景誤檢率,但召回率低。
- 對小目標和聚集目標效果差。
SSD
SSD(Single Shot MultiBox Detector)針對YOLOv1對寬高不常見物體和小目標物體偵測效果差的缺陷做了改進。
SSD去掉了網路最後的全連線層,其認為目標檢測中的物體,只與周圍資訊相關,它的感受野是區域性的,故沒必要也不應該做全連線。
SSD最大的特點是:多尺度檢測。對多個卷積層,提取不同大小感受野的feature map,在這些多尺度的feature map上,進行目標位置和類別的訓練和預測。顯然,越淺層的feature map感受野越小,越利於檢測小物體。
和Faster R-CNN相似,SSD也提出了anchor(錨框)的概念。feature map 的每個點對應為原圖的一個區域的中心點,以這個點為中心,構造出6個寬高比例不同,大小不同的anchor, 每個anchor對應4個位置引數
(
x
,
y
,
w
,
h
)
(x,y,w,h)
(x,y,w,h)和21個類別概率(VOC訓練集20個類別,加上anchor是否為背景,共21類)。
通過多尺度多 anchor 的方法,SSD顯著提升了YOLOv1的檢測精度。
YOLOv2 / YOLO9000
YOLOv1與Fast R-CNN的誤差比較分析表明,YOLOv1 產生了大量的定位錯誤。此外,與生成候選區域方法相比,YOLOv1召回率相對較低。 因此,YOLOv2主要關注改善召回率和定位,同時保持分類準確性。
YOLOv1到YOLOv2的進化之路中嘗試了各項改進,我們看一下最重要的幾點:
批標準化(batch normalization)
批標準化可以顯著改善收斂性,避免過擬合,而且不再需要dropout和其他形式的正則化。
全卷積網路
和SSD一樣,YOLOv2移除了全連線層,另外消除一個池化層,使網路卷積層的輸出具有更高的解析度,將網路輸入影像解析度由448×448改為416X416,這樣做是為了讓特徵圖尺寸為奇數,只有一箇中心點。目標,尤其是大的目標,往往佔據影像的中心,所以最好在正中心擁有單獨一個位置來預測這些目標,而不是在中心附近的四個位置。如此,通過32倍的下采樣,416X416的影像最終得到13×13的特徵圖。
使用錨框anchor
引入anchor後,我們將類別預測與座標迴歸分開處理,單獨預測每個anchor的類及其目標。對比YOLOv1,現在每個grid cell可以預測多個類別的物體,一個anchor可以預測一個物體。YOLOv1僅為每個圖片預測98個框,使用anchor後,模型預測的框數超過一千個,雖然精度會小幅下降,但召回率顯著提升。
聚類獲得anchor尺寸
anchor的尺寸是手工挑選的,雖然網路可以通過學習適當地調整方框,但是如果從一開始就為網路選擇更好的prior(先驗),就可以讓網路更容易學習。
YOLOv2不手工選擇先驗,而是對訓練集的邊框使用k-means聚類演算法,自動找到良好的prior。如果在演算法中使用歐氏距離進行聚類,大框比小框的誤差會更大,我們重視的是同一類框的IoU值,因此定義距離為:
用不同的k值執行k-means,並繪製樣本框和聚類中心的平均IoU。權衡模型複雜度和召回率,選擇
k
=
5
k = 5
k=5。聚類的中心與手工選取的anchor顯著不同,它有更少的短寬框,更多的長窄框。5個聚類anchor的效能類似於9個手工選取anchor。
位置預測
按照Faster RCNN的anchor方法,在訓練的早期階段,預測bounding box的中心點沒有約束,可能出現在任何位置,位置預測容易不穩定,因此YOLOv2調整了預測公式。
b
x
,
b
y
,
b
w
,
b
h
b_x,b_y,b_w,b_h
bx,by,bw,bh為bounding box的中心點和寬高;
σ
\sigma
σ為sigmoid函式;
c
x
,
c
y
c_x,c_y
cx,cy為grid cell大小歸一化後,當前grid cell相對影像左上角的座標;
p
w
,
p
h
p_w,p_h
pw,ph為anchor的寬高;
t
x
,
t
y
,
t
w
,
t
h
,
t
o
t_x,t_y,t_w,t_h,t_o
tx,ty,tw,th,to是要學習的引數,分別用於預測bounding box的中心點、寬高、置信度。
通過sigmoid函式,
t
x
,
t
y
t_x,t_y
tx,ty被約束在
(
0
,
1
)
(0,1)
(0,1),即當前grid cell內。如此引數更容易學習,網路更穩定。
相較YOLOv1計算loss時使用 w , h \sqrt w,\sqrt h w,h來平衡大小框的損失,YOLOv2選擇用自然對數函式 ln \ln ln壓縮寬高,對照兩個函式影像, ln \ln ln函式的值域在 ( − ∞ , + ∞ ) (-\infty,+\infty) (−∞,+∞),更符合網路輸出。
網路模型
為了進一步提升速度,YOLOv2提出了Darknet-19模型,包含19個卷積層和5個最大池化層,最後使用全域性平均池化來進行預測。
識別更多類別
YOLOv2聯合訓練ImageNet資料集和COCO資料集,其中混合了分類和檢測兩種資料,當學習分類樣本時,只計算分類損失,學習檢測樣本時,才同時計算位置損失。這是一種開創性的訓練方法,擴充了網路檢測能力,使其學會檢測一些沒有檢測樣本的物件。由此,訓練出了可以識別9000個類的YOLO9000。
YOLOv3
雖然YOLO之父Joseph Redmon在YOLOv3論文引言中說,他之前一年啥也沒幹,主要刷Twitter… 但絲毫不影響YOLOv3成為當時目標檢測演算法的集大成者。
使用sigmoid分類器
作者發現Softmax對於提升網路效能沒什麼作用,YOLOv3選擇使用單獨的Logistic分類器,在訓練中用binary cross-entropy loss(二元交叉熵損失)來預測類別。
因為Softmax總和為1的排他性,強加了一個假設:每個框有且只有一個類別。對於有巢狀關係標籤的複雜資料集(如“人”和“女人”),這種假設是不妥的,相比之下,多標籤的分類方法能更好地模擬資料。
跨尺度預測
為了更好地檢測小目標,YOLOv2曾使用passthrough層來獲得細粒度特徵(感受野更小), 而YOLOv3選擇在3個不同尺度進行預測,網路分別為每種尺寸各預測了3個邊界框,對於COCO資料集,每種尺寸最終得到的張量為
N
×
N
×
[
3
×
(
4
+
1
+
80
)
]
N ×N ×[3 \times (4+ 1+ 80)]
N×N×[3×(4+1+80)]:4個邊框偏移量、1個目標置信度、80個類別。
從淺層網路提取特徵圖,上取樣之後,在element-wise(畫素級別)將高低兩種解析度的特徵圖拼接到一起,由此得到早期特徵對映中的細粒度特徵,並獲得更豐富的語義資訊。
YOLOv3依然使用K-Means聚類方法來得到anchor的尺寸,在COCO資料集上選擇了9個聚類和3個尺寸。特徵圖下采樣次數越少,尺寸越大,感受野越小,用來檢測越小的物體。
新的網路
YOLOv3提出新的網路模型:Darknet-53。在Darknet-19基礎上借鑑了residual(殘差)網路,新增了shortcut connection(捷徑連線),共有53個卷積層。這個新網路在效能上遠超Darknet-19 ,但是在效率上同樣優於ResNet-101和ResNet-152。
YOLOv3 程式碼實現流程詳解
anchor
在進入實現流程之前,不得不先開啟一個番外篇。你說不就anchor嘛,看好多遍早明白了。不!你沒有!!好叭對不起,是我沒有……讓我們不厭其煩(手動微笑)地再來擼一擼:
bounding box?anchor box??
這兩個概念在一些不嚴謹的說法裡容易混淆。Bounding box是完整的邊框資訊,包括中心座標、寬高、置信度以及類別;而anchor box是一個物體形狀的先驗,只包含寬高。
搞個anchor出來有啥用??
按照吳恩達的課程,anchor是為了在一個grid cell中預測多個物體。
我的腦回路
:為啥YOLOv1選擇一個類別對應兩組座標?一個類別對應一組座標,再來一個類別對應一組座標,不就能預測兩個物體了嘛?
:哦……這樣的兩組預測好像沒法對應物體。做標籤的時候可以指定哪組標籤表示哪個物體,可是預測的時候網路只會輸出最有可能的兩組值,這兩組值基本上只會是預測同一個物體的相似值,起不到預測多個物體的效果。
:emmm 我想起來了,好像在做單類單目標檢測的時候遇到過類似的問題,如果單純地將一幅圖片上的目標改成兩個,標註兩個目標進行訓練,預測的時候兩個框只會出現在同一個目標上,置信度較低的目標是框不到的。
so,anchor的意義就是告訴這兩組預測,你倆分別負責找什麼形狀的物體。比如1號bounding box找高瘦的目標,2號bounding box找矮胖的目標。在訓練的時候用anchor和ground truth的IoU作為置信度來篩選正負樣本,將物體交給大小形狀相近的anchor所對應的那組值來學習,這樣在預測時,兩個bounding box就有了傾向,不會只框到同一個物體。
那麼,anchor的尺寸怎麼給呢?這是一種先驗,表示我們一開始就告訴模型物體更有可能是哪些大小形狀的。這個尺寸如果給的不好,不同的物體就沒法區分,自然會影響訓練效果。比如,我給了高瘦和矮胖兩個尺寸較小的anchor,而實際物體的ground truth都是接近正方形的或者尺寸很大的,這就不好辦了,它和兩個anchor的IoU都不大,可能被判作負樣本不參與訓練,即使勉強作為正樣本,網路根據IoU學習到的置信度也是不高的,在預測的時候效果也不會好。我們主觀估計的anchor尺寸並不準確,因此才需要K-means聚類演算法。
anchor思想在程式碼中的實現並不複雜,但我一直沒有徹底理解,也沒找到解釋很清晰的文章。那不管了,暫時按我說的為主!有不服的……請快來教教我!
好了,番外篇完結,進入正題~
網路
YOLOv3網路模型的主幹部分是Darknet-53,輸入影像經過Darknet-53得到52×52、26×26、13×13三種尺寸的特徵圖,網路具體引數如下:
通過route(特徵在通道維度拼接)操作,融合了不同層次的特徵,從而提高預測精度。以26×26的特徵圖為例,concatenate(拼接)操作融合了淺層網路的512維特徵(偏區域性)和由上取樣得到的256維特徵(偏全域性),為了預測小物體,顯然以區域性特徵為主。52×52的特徵圖同理。
網路輸出為:
其中
3
3
3表示每個尺寸的特徵圖預測3個anchor,
5
5
5表示4個座標偏移量+置信度,C為類別數。
以COCO資料集80分類為例,網路輸出如下:
標籤
生成的訓練標籤應該和網路輸出相對應,分別有13×13、26×26、52×52三組。
思路是這樣的:首先生成
(
13
,
13
,
3
,
5
+
C
)
,
(
26
,
26
,
3
,
5
+
C
)
,
(
52
,
52
,
3
,
5
+
C
)
(13,13,3,5+C),(26,26,3,5+C),(52,52,3,5+C)
(13,13,3,5+C),(26,26,3,5+C),(52,52,3,5+C)三個零矩陣,其中
3
3
3表示每種尺寸特徵圖的每個grid cell有3個anchor,
5
+
C
5+C
5+C的含義同上。然後在有物體的grid cell計算3個anchor與對應ground truth的IoU和座標偏移量,填入矩陣。沒有物體的grid cell只需要訓練置信度,預設為0即可。
b
x
,
b
y
,
b
w
,
b
h
b_x,b_y,b_w,b_h
bx,by,bw,bh為bounding box的中心點和寬高;
σ
\sigma
σ為sigmoid函式;
c
x
,
c
y
c_x,c_y
cx,cy為grid cell大小歸一化後,當前grid cell相對影像左上角的座標;
p
w
,
p
h
p_w,p_h
pw,ph為anchor的寬高;
t
x
,
t
y
,
t
w
,
t
h
,
t
o
t_x,t_y,t_w,t_h,t_o
tx,ty,tw,th,to是要學習的引數,分別用於預測bounding box的中心點、寬高、置信度。
為了避免混淆,沿用上圖預測時的引數名稱進行說明。設每張樣本圖片有n個物體,每個物體對應標籤 ( c l s , x , y , w , h ) (cls,x,y,w,h) (cls,x,y,w,h),分別表示類別、中心點座標、寬高。
grid cell在歸一化之前,代表原圖的尺寸就是該特徵圖在網路中下采樣的倍數,如13×13的特徵圖, 每個grid cell代表的尺寸自然是 416 ÷ 13 = 32 {416}\div{13}=32 416÷13=32,這也是網路中5次下采樣的倍數總和 32 = 2 5 32=2^5 32=25。
我們先要找到有物體的grid cell的座標
c
x
,
c
y
c_x,c_y
cx,cy,這裡有個取巧的做法:將物體中心點座標
(
x
,
y
)
(x,y)
(x,y)除以每個grid cell代表的尺寸,相當於給grid cell做歸一化,如此可以同時得到物體所在grid cell的座標
c
x
,
c
y
c_x,c_y
cx,cy和中心點偏移量
t
x
,
t
y
t_x,t_y
tx,ty。
舉個例子:13×13的特徵圖,一個grid cell尺寸為32,現有一物體中心點座標
(
x
,
y
)
=
(
88
,
60
)
(x,y)=(88,60)
(x,y)=(88,60),除以32後等於
(
2.75
,
1.875
)
(2.75,1.875)
(2.75,1.875),不難發現,其中整數部分
(
2
,
1
)
(2,1)
(2,1)正是物體所在grid cell的座標
c
x
,
c
y
c_x,c_y
cx,cy,小數部分
(
0.75
,
0.875
)
(0.75,0.875)
(0.75,0.875)正是物體對所在grid cell左上角點的偏移量
t
x
,
t
y
t_x,t_y
tx,ty。
寬高偏移量 t w , t h = l o g e w p w , l o g e h p h \displaystyle t_w,t_h=log_e \frac w{p_w},log_e \frac h{p_h} tw,th=logepww,logephh,置信度 t o t_o to只需計算物體的真實框ground truth與3個anchor的IoU即可。最後,在建立的零矩陣中,對應座標 c x , c y c_x,c_y cx,cy處,填入三個anchor對應的 5 + C 5+C 5+C個值,類別 C C C經過one-hot編碼,因此需要 C C C個數表示。
至此,標籤處理完成。你可能注意到,標籤shape和網路輸出還是不一樣,在計算loss和預測時,通過矩陣變換就能解決,具體在損失設計中說明。
這裡我在一開始有個疑惑:在做訓練label時, t w , t h t_w,t_h tw,th是用真實框ground truth寬高比上anchor寬高,再取log得到,因此在預測時符合上述公式,可是 t x , t y t_x,t_y tx,ty並未做任何處理,為什麼在預測時可以直接加上sigmoid函式?
我的理解是: t x , t y t_x,t_y tx,ty的label是在 ( 0 , 1 ) (0,1) (0,1)內,可是網路學習到的值沒有任何約束,很可能超出這個範圍,顯然超出當前grid cell的預測是不合理的。sigmoid函式是增函式,在壓縮的同時,不會改變值的大小關係,也就是說網路梯度更新的方向是對的,只是對值的要求變低了。比如我們希望 σ ( t x ) \sigma(t_x) σ(tx)值在 ( 0.5 , 0.6 ) (0.5,0.6) (0.5,0.6),根據sigmoid反函式算得,網路學習到的 t x t_x tx滿足 ( 0 , 0.4 ) (0,0.4) (0,0.4)範圍內即可,降低了學習難度。置信度 t o t_o to也是同理。
另外還有一個小點:
如果物體和anchor形狀不太匹配,置信度值會比較低,訓練和預測的效果不太好,有些GitHub上的程式碼選擇直接將IoU最大的anchor置信度直接給1。
損失
根據置信度標籤篩選正負樣本,按照論文,選擇置信度最高的anchor負責該物體,忽略不是最高但高於閾值(論文中給0.5)的anchor,小於閾值的anchor作為負樣本。正樣本損失包含置信度、座標、分類損失3部分,負樣本置信度標籤為0,只有置信度損失。
在具體實現中,因為雖然YOLO使用了anchor,但相較MTCNN多個偏移框迴歸一個預測框,YOLO的召回率還是較低的,因此在篩選樣本時有些GitHub上的程式碼選擇儘可能保留anchor,將大於設定閾值的數個anchor都作為正樣本參與訓練。這樣在預測時可以增加預測數,提高召回率。這些GitHub程式碼的改動實現效果還可以,可能有什麼負面影響我尚不清楚。
相對於anchor的總數,其中需要負責物體預測的正樣本往往是遠不足一半,正負樣本損失求和時前面可以加上係數以均衡樣本:
l
o
s
s
=
α
l
o
s
s
p
o
s
i
t
i
v
e
+
β
l
o
s
s
n
e
g
a
t
i
v
e
loss=\alpha loss_{positive} + \beta loss_{negative}
loss=αlosspositive+βlossnegative。最後將3種特徵圖的損失求和得到總損失。
損失函式如下:
- 置信度損失:二元交叉熵損失(BCE)
- 座標損失:均方差損失(MSE)
- 分類損失:交叉熵損失(標籤無巢狀)或二元交叉熵損失(標籤有巢狀)
三種損失其實都可以簡單地用均方差損失函式,YOLOv2就是這麼幹的,但是對分類損失,使用交叉熵更合理,而且在求導時不會有MSE的梯度彌散問題。
別忘了在計算前,要將網路輸出的3組值通過換軸和reshape變成和標籤一致:
(
(
3
×
(
5
+
C
)
)
,
f
e
a
t
u
r
e
,
f
e
a
t
u
r
e
)
((3×(5+C)),feature,feature)
((3×(5+C)),feature,feature)
−
>
(
f
e
a
t
u
r
e
,
f
e
a
t
u
r
e
,
(
3
×
(
5
+
C
)
)
)
->(feature,feature,(3×(5+C)))
−>(feature,feature,(3×(5+C)))
−
>
(
f
e
a
t
u
r
e
,
f
e
a
t
u
r
e
,
3
,
5
+
C
)
->(feature,feature,3,5+C)
−>(feature,feature,3,5+C)
我一開始覺得,網路輸出的值本身是沒有任何含義的,只要和標籤對應上就行,所以輸出可以直接reshape,沒必要加一步換軸操作。後來經過思考和實驗發現不是這樣,2個feature維度是通過下采樣得到的特徵尺寸,不能被reshape破壞,否則下采樣和特徵融合就沒意義了。
預測
流程:
- 將網路輸出reshape。
- 置信度經sigmoid函式後,根據給定閾值篩選,大於閾值的作為預測目標留下。
- 根據公式反算bounding box的座標值。
- 預測出的同一種類別的邊框進行NMS(非極大值抑制)。
- 在原圖上畫出邊框,輸出預測類別。
座標反算:
mask = torch.sigmoid(output[..., 0]) > thresh
idxs = mask.nonzero()
vecs = output[mask]
根據置信度篩選得到滿足條件的特徵圖座標idxs和對應向量vecs。
設共檢測到n的物體。
idxs的shape為
(
n
,
4
)
(n,4)
(n,4),4個值為
(
N
,
H
,
W
,
3
)
(N,H,W,3)
(N,H,W,3),分別表示第幾張圖片、物體中心點所在grid cell座標
c
y
,
c
x
c_y,c_x
cy,cx(注意變換)、第幾個anchor。
vecs的shape為
(
n
,
5
+
C
)
(n,5+C)
(n,5+C),
5
+
C
5+C
5+C含義同上。
b
x
,
b
y
,
b
w
,
b
h
b_x,b_y,b_w,b_h
bx,by,bw,bh為bounding box的中心點和寬高;
σ
\sigma
σ為sigmoid函式;
c
x
,
c
y
c_x,c_y
cx,cy為當前grid cell在特徵圖中的座標;
p
w
,
p
h
p_w,p_h
pw,ph為anchor的寬高;
t
x
,
t
y
,
t
w
,
t
h
t_x,t_y,t_w,t_h
tx,ty,tw,th為vecs中的第2到第5個值。
接下來找到每個物體對應的anchor尺寸,按照公式反算即可,沒有太難的地方。
閒言
YOLOv4、v5嘛,其中技巧太多,我現在理解還不透徹,就不獻醜,之後有機會再補上。
YOLOv3作者在論文最後探討了一下YOLO的意義,許多人選擇忽視甚至翻譯都跳過了。私以為作者的表達極客且活潑,我向來不覺得程式和文學或藝術是矛盾的。人需要理性的技術,也需要敏感的心。作者對YOLO侵犯隱私和傷害生命的用途表達了抗議和愧疚,直至在YOLOv4誕生前夕選擇退出CV界。
雙刃恆存,不予置評。
技術不會停止,關於技術的思考也不會。
文章難免有錯漏之處,敬請指正。
相關文章
- 【百度飛漿】YOLO系列目標檢測演算法詳解YOLO演算法
- 目標檢測之YOLO系列YOLO
- 二階段目標檢測網路-Faster RCNN 詳解ASTCNN
- 二階段目標檢測網路-Mask RCNN 詳解CNN
- 二階段目標檢測網路-Cascade RCNN 詳解CNN
- 【目標檢測從放棄到入門】SSD / RCNN / YOLO通俗講解CNNYOLO
- pytorch實現yolov3(5) 實現端到端的目標檢測PyTorchYOLO
- YOLO目標檢測從V1到V3結構詳解YOLO
- 目標檢測入門系列手冊二:RCNN訓練教程CNN
- 從零開始PyTorch專案:YOLO v3目標檢測實現PyTorchYOLO
- 深度學習目標檢測(object detection)系列(六)YOLO2深度學習ObjectYOLO
- 目標檢測入門系列手冊五:YOLO訓練教程YOLO
- 深度學習與CV教程(13) | 目標檢測 (SSD,YOLO系列)深度學習YOLO
- 一階段目標檢測網路-RetinaNet 詳解NaN
- 二階段目標檢測網路-FPN 詳解
- 使用 YOLO 進行實時目標檢測YOLO
- 實時通訊系列目錄篇之SignalR詳解SignalR
- 基於YOLOv5的目標檢測系統詳解(附MATLAB GUI版程式碼)YOLOMatlabGUI
- CSS流程分步程式碼詳解CSS
- 【小白學PyTorch】13 EfficientNet詳解及PyTorch實現PyTorch
- 【小白學PyTorch】12 SENet詳解及PyTorch實現PyTorchSENet
- 目標檢測網路之 YOLOv3YOLO
- 【JS系列】物件詳解JS物件
- grpc系列- protobuf詳解RPC
- 這才是目標檢測YOLOv3的真實面目YOLO
- Mysql系列第十四講 檢視詳解MySql
- 【pytest系列】- fixture測試夾具詳解
- Spring框架系列(7) - Spring IOC實現原理詳解之IOC初始化流程Spring框架
- Mysql系列第十八講 遊標詳解MySql
- 【SpringBoot系列】SpringBoot註解詳解Spring Boot
- 詳解JSON和JSONP劫持檢測程式碼以及解決方法JSON
- Spring原始碼系列(補充):詳解ApplicationContextSpring原始碼APPContext
- webpack loader配置全流程詳解Web
- 保姆教程系列:Git 實用命令詳解Git
- netty系列之:channelHandlerContext詳解NettyContext
- netty系列之:channelPipeline詳解Netty
- 深入解析xLSTM:LSTM架構的演進及PyTorch程式碼實現詳解架構PyTorch
- YOLO演算法(三)—— Yolov3 & Yolo系列網路優缺點YOLO演算法