YOLOv4詳細(xì)分析 | 細(xì)數(shù)當(dāng)前最佳檢測(cè)框架小細(xì)節(jié)(1)
前段時(shí)間,突然發(fā)布的YOLOv4成了計(jì)算機(jī)視覺(jué)領(lǐng)域一大熱點(diǎn)新聞。這個(gè)目標(biāo)檢測(cè)任務(wù)的SOTA模型究竟有何創(chuàng)新?這篇解讀文章為你一一拆解。
目標(biāo)檢測(cè)在近幾年開(kāi)始發(fā)展成熟,但即便如此,競(jìng)爭(zhēng)依舊激烈。如下所示,YOLOv4 宣稱(chēng)已經(jīng)實(shí)現(xiàn)了當(dāng)前最前沿技術(shù)的準(zhǔn)確度,同時(shí)還能維持較高的處理幀率。使用 Tesla V100 GPU,在 MS COCO 數(shù)據(jù)集上以接近 65 FPS 的推理速度,YOLOv4 實(shí)現(xiàn)了 43.5% AP (65.7% AP??)的準(zhǔn)確度。但對(duì)于目標(biāo)檢測(cè)而言,高準(zhǔn)確度早已不是唯一的目標(biāo)。我們還希望邊緣設(shè)備也能流暢地運(yùn)行這些模型。因此,如何使用低成本硬件實(shí)時(shí)地處理輸入視頻也成為了一個(gè)重要的研究方向。
YOLOv4 的開(kāi)發(fā)歷程很有意思,其中評(píng)估、修改和整合了很多有趣的新技術(shù)。而且其也優(yōu)化了計(jì)算效率,使檢測(cè)器在單個(gè) GPU 上也能很好地完成訓(xùn)練。
Bag of freebies (BoF) 與 Bag of specials (BoS)
為了提升準(zhǔn)確度,可以針對(duì)訓(xùn)練過(guò)程進(jìn)行一些優(yōu)化,比如數(shù)據(jù)增強(qiáng)、類(lèi)別不平衡、成本函數(shù)、軟標(biāo)注…… 這些改進(jìn)不會(huì)影響推理速度,可被稱(chēng)為「Bag of freebies」。另外還有一些改進(jìn)可稱(chēng)為「bag of specials」,僅需在推理時(shí)間方面做少許犧牲,就能獲得優(yōu)良的性能回報(bào)。這類(lèi)改進(jìn)包括增大感受野、使用注意力機(jī)制、集成跳過(guò)連接(skip-connection)或 FPN 等特性、使用非極大值抑制等后處理方法。本文將探討特征提取器和頸部的設(shè)計(jì)方式以及那些好用的 BoF 和 BoS 改進(jìn)策略。
骨干網(wǎng)絡(luò)
密集模塊與 DenseNet
為了提升準(zhǔn)確度,我們可通過(guò)提高網(wǎng)絡(luò)深度來(lái)擴(kuò)展感受野和增大模型復(fù)雜度。同時(shí),為了降低訓(xùn)練難度,還可應(yīng)用跳過(guò)連接。我們還可以進(jìn)一步延伸這一概念,即使用高度互連的層。
密集模塊(Dense Block)包含多個(gè)卷積層,其中每一層 H_i 都由批歸一化、ReLU 與之后的卷積構(gòu)成。H_i 的輸入不僅包含前一層的輸出,還包含之前所有層的輸出以及原始輸入,即 x_?, x_?, …, x_{i-1}。下圖中每個(gè) H_i 都輸出 4 個(gè)特征圖。因此,在每一層,特征圖的數(shù)量都增加 4 倍——增長(zhǎng)率。
然后,通過(guò)組合多個(gè)密集模塊與其間的過(guò)渡層(由卷積和池化構(gòu)成),可以構(gòu)建出 DenseNet。
下面給出了這種架構(gòu)設(shè)計(jì)的詳情。
交叉階段部分連接(CSP)
CSPNet 將密集模塊的輸入特征圖分為了兩部分。第一部分 x_?’ 會(huì)繞過(guò)密集模塊,成為下個(gè)過(guò)渡層的輸入的一部分。第二部分 x_?’’ 則會(huì)通過(guò)密集模塊,如下圖所示。
這種新設(shè)計(jì)通過(guò)將輸入分為兩部分而降低了計(jì)算復(fù)雜度——此時(shí)僅有一部分輸入會(huì)經(jīng)過(guò)密集模塊。
CSPDarknet53
YOLOv4 使用了上面的 CSP 與下面的 Darknet-53 作為特征提取的骨干。
相比于基于 ResNet 的設(shè)計(jì),CSPDarknet53 模型的目標(biāo)檢測(cè)準(zhǔn)確度更高,不過(guò) ResNet 的分類(lèi)性能更好一些。但是,借助后文將討論的 Mish 和其它技術(shù),CSPDarknet53 的分類(lèi)準(zhǔn)確度可以得到提升。因此,YOLOv4 最終選擇了 CSPDarknet53。
頸部(Neck)
目標(biāo)檢測(cè)器由用于特征提取的骨干部分(backbone)和用于目標(biāo)檢測(cè)的頭部(head,下圖最右邊的模塊)構(gòu)成。而為了檢測(cè)不同大小的目標(biāo),需要使用一種分層結(jié)構(gòu),使得頭部可探測(cè)不同空間分辨率的特征圖。
為了讓輸入頭部的信息更豐富,在輸入頭部前,會(huì)將來(lái)自自底向上和自上而下的數(shù)據(jù)流按逐元素的方式相加或相連。因此,頭部的輸入將包含來(lái)自自底向上數(shù)據(jù)流的豐富空間信息以及來(lái)自自上而下數(shù)據(jù)流的豐富語(yǔ)義信息。該系統(tǒng)的這一部分稱(chēng)為頸部(neck)。下面更詳細(xì)地談?wù)勥@一設(shè)計(jì)。
特征金字塔網(wǎng)絡(luò)(FPN)
YOLOv3 采用了與 FPN 類(lèi)似的方法來(lái)實(shí)現(xiàn)不同大小層次的目標(biāo)檢測(cè)預(yù)測(cè)。
在針對(duì)特定尺寸大小進(jìn)行預(yù)測(cè)時(shí),F(xiàn)PN 會(huì)對(duì)自上而下的數(shù)據(jù)流進(jìn)行上采樣(2 倍),并將其與自底向上的相鄰層相加(見(jiàn)下圖)。得到的結(jié)果會(huì)被傳遞給一個(gè) 3×3 的卷積核,以減少上采樣偽影以及為頭部創(chuàng)建下圖中的特征圖 P4。
SPP(空間金字塔池化層)
SPP 應(yīng)用了略有不同的策略來(lái)檢測(cè)不同尺寸大小的目標(biāo),即使用一個(gè)空間金字塔池化層替代了最后的池化層(在最后的卷積層之后)。其特征圖在空間上分成了 m×m 個(gè) bin,其中 m 可以分別為 1、2、4 等值。然后針對(duì)每個(gè)通道,為每個(gè) bin 應(yīng)用一次最大池化。這會(huì)形成一個(gè)長(zhǎng)度固定的表征,然后可以使用 FC 層對(duì)該表征進(jìn)行進(jìn)一步的分析。
許多基于 CNN 的模型都包含 FC 層,因此只能接受指定尺寸的輸入圖像。相對(duì)而言,SPP 可使用不同大小的圖像。然而,也還存在不包含 FC 層的技術(shù),比如全卷積網(wǎng)絡(luò)(FCN);這些技術(shù)可以接受不同尺寸的圖像。對(duì)于空間信息非常重要的圖像分割等任務(wù)而言,這類(lèi)設(shè)計(jì)尤為重要。因此,對(duì)于 YOLO,并不必需將 2D 特征圖轉(zhuǎn)化為固定大小的 1D 向量。
使用 SPP 的 YOLO
YOLO 中使用的 SPP 經(jīng)過(guò)修改,以保留輸出的空間尺寸大小。而且還在大小為 1×1、5×5、9×9、13×13 等的滑動(dòng)核(sliding kernel)應(yīng)用了最大池化。空間尺寸大小得以保留。然后將來(lái)自不同核大小的特征圖連接起來(lái)作為輸出。
下圖展示了 SPP 是如何整合進(jìn) YOLO 的。
路徑聚合網(wǎng)絡(luò)(PAN)
早期的深度學(xué)習(xí)的模型設(shè)計(jì)相對(duì)簡(jiǎn)單。每一層的輸入都來(lái)自其上一層。更前面的層會(huì)提取局部的紋理和圖案信息,并構(gòu)建出后續(xù)層所需的語(yǔ)義信息。但是,隨著網(wǎng)絡(luò)向右側(cè)推進(jìn),微調(diào)優(yōu)化預(yù)測(cè)結(jié)果時(shí)所需的局部信息可能會(huì)丟失。
在后來(lái)的深度學(xué)習(xí)開(kāi)發(fā)中,層之間的互連方式變得更加復(fù)雜。DenseNet 在這方面達(dá)到了極致。其中每一層都連接了其前面的所有層。
在 FPN 中,來(lái)自自底向上和自上而下數(shù)據(jù)流的鄰近層的信息會(huì)結(jié)合到一起。
層之間信息的流動(dòng)方式變成了模型設(shè)計(jì)中需要考慮的又一關(guān)鍵事項(xiàng)。
下圖是用于目標(biāo)檢測(cè)的路徑聚合網(wǎng)絡(luò)(PAN)。其中,自底向上的路徑得到增強(qiáng),使得低層信息更容易傳播到頂部。在 FPN 中,局部空間信息會(huì)向上傳播,如紅色箭頭所示。盡管圖中可能沒(méi)有展示清楚,但這條紅色路徑穿過(guò)了大約 100 多層。PAN 引入了一個(gè)捷徑路徑(綠色路徑),其僅需 10 層左右就能抵達(dá)頂部的 N? 層。這個(gè)短回路概念使得頂層也能獲取到細(xì)粒度的局部信息。
順帶一提,頸部設(shè)計(jì)可以進(jìn)行如下的可視化:
但是,YOLOv4 并沒(méi)有將鄰近層加到一起,而是將特征圖連接到一起。
在 FPN 中,不同尺寸大小的目標(biāo)是分開(kāi)獨(dú)立檢測(cè)的。這可能會(huì)導(dǎo)致出現(xiàn)重復(fù)的預(yù)測(cè)結(jié)果,而且無(wú)法利用來(lái)自其它特征圖的信息。PAN 最早使用了逐元素最大運(yùn)算將這些信息融合到一起(這里不再詳述相關(guān)細(xì)節(jié))。
空間注意力模塊(SAM)
注意力已經(jīng)在深度學(xué)習(xí)設(shè)計(jì)中得到了廣泛的應(yīng)用。SAM 會(huì)為輸入特征圖分別應(yīng)用最大池化和平均池化,從而得到兩個(gè)特征圖集合。其結(jié)果會(huì)被送入一個(gè)卷積層,之后再由一個(gè) sigmoid 函數(shù)創(chuàng)建出空間注意力。
這個(gè)空間注意力掩碼再被應(yīng)用于輸入特征,從而輸出經(jīng)過(guò)優(yōu)化的特征圖。
YOLOv4 使用了一種修改版的 SAM,其中沒(méi)有使用最大池化和平均池化。
YOLOv4 使用修改版的 SPP、PAN 和 SAM 逐步實(shí)現(xiàn) / 替換了 FPN 概念。
用于骨干部分的 Bag of freebies (BoF)
用于 YOLOv4 骨干部分的 BoF 特征包括:
· CutMix 和 Mosaic 數(shù)據(jù)增強(qiáng)
· DropBlock 正則化
· 類(lèi)別標(biāo)簽平滑化
CutMix 數(shù)據(jù)增強(qiáng)
Cutout 數(shù)據(jù)增強(qiáng)會(huì)移除圖像的部分區(qū)域(見(jiàn)下圖)。這會(huì)迫使模型在執(zhí)行分類(lèi)時(shí)不過(guò)于相信特定的特征。但是,如果圖像的某部分充滿(mǎn)了無(wú)用信息,則這種操作就浪費(fèi)了。CutMix 的做法則不同,其是將圖像的一部分剪切下來(lái)再粘貼到另一張圖像上。其基本真值標(biāo)簽會(huì)根據(jù)補(bǔ)丁的面積比例進(jìn)行調(diào)整,比如狗的部分占 0.6,貓的部分占 0.4。
從概念上講,CutMix 在目標(biāo)的可能組成成分方面有更寬廣的視角。裁減掉的部分會(huì)迫使模型學(xué)習(xí)使用不同的特征組合進(jìn)行分類(lèi)。這可避免信心過(guò)高。因?yàn)槭怯昧硪粡垐D像替代該區(qū)域,所以圖像中的信息量和訓(xùn)練效率都不會(huì)受到顯著的影響。
Mosaic 數(shù)據(jù)增強(qiáng)
Mosaic 這種數(shù)據(jù)增強(qiáng)方法是將 4 張訓(xùn)練圖像組合成一張來(lái)進(jìn)行訓(xùn)練(而非 CutMix 中的 2 張)。這讓模型在非慣例的環(huán)境中能更好地執(zhí)行目標(biāo)檢測(cè)。此外,由于每個(gè) mini-batch 都包含圖像的較多變體(4×),因此在估計(jì)均值和方差時(shí),對(duì)較大 mini-batch 的需求會(huì)降低。
DropBlock 正則化
在全連接層中,我們可通過(guò)丟棄一些連接來(lái)迫使模型學(xué)習(xí)不同的特征,而不是過(guò)于依賴(lài)少量特征。但是,這可能不適用于卷積層。相鄰的位置可能高度相關(guān)。所以即使丟棄一些像素(如中部的圖所示),仍然可以檢測(cè)出空間信息。DropBlock 正則化基于類(lèi)似的概念,但適用于卷積層。
不過(guò) DropBlock 丟棄的不是各個(gè)像素,而是大小為 block_size × block_size 的一個(gè)像素塊。
類(lèi)別標(biāo)簽平滑化
每當(dāng)你覺(jué)得自己完全正確時(shí),你可能只是想錯(cuò)了。如果一個(gè)預(yù)測(cè)結(jié)果的置信度為 100%,可能只是說(shuō)明模型記憶了這個(gè)數(shù)據(jù),而非學(xué)習(xí)了什么東西。標(biāo)簽平滑化將預(yù)測(cè)結(jié)果的目標(biāo)上界調(diào)整至了一個(gè)更低的值,比如 0.9。然后在計(jì)算損失時(shí),模型會(huì)以這個(gè)值為目標(biāo),而不是 1.0。這一方法可緩解過(guò)擬合問(wèn)題。
p = tf.placeholder(tf.float32, shape=[None, 10])
# Use 0.9 instead of 1.0.
feed_dict = {
p: [[0, 0, 0, 0.9, 0, 0, 0, 0, 0, 0]] # Image with label "3"
}
# logits_real_image is the logits calculated by
# the discriminator for real images.
d_real_loss = tf.nn.sigmoid_cross_entropy_with_logits(
labels=p, logits=logits_real_image)
*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。