【YOLO算法】 最耐心細(xì)致的講解
YOLO 是 2016 年提出來的目標(biāo)檢測算法,在當(dāng)時比較優(yōu)秀的目標(biāo)檢測算法有 R-CNN、Fast R-CNN 等等,但 YOLO 算法還是讓人感到很新奇與興奮。
YOLO 是 You only look once 幾個單詞的縮寫,大意是你看一次就可以預(yù)測了,靈感就來自于我們?nèi)祟愖约海驗槿丝匆粡垐D片時,掃一眼就可以得知這張圖片不同類型目標(biāo)的位置。
YOLO 勝在它的簡單與快速。
YOLO 是單個神經(jīng)網(wǎng)絡(luò)進(jìn)行端到端的預(yù)測,沒有多個步驟和過程。
YOLO 的速度非常快,可以達(dá)到實時的 45 fps,簡化版本甚至達(dá)到 155 fps。
YOLO 目標(biāo)預(yù)測如同捕魚
在 YOLO 前,目標(biāo)檢測一般通過算法生成候選區(qū)域,然后在數(shù)量眾多的候選區(qū)域中做目標(biāo)的分類和 bbox 位置的回歸。
更古老的方法是通過滑動窗口的形式去挨個預(yù)測與判別。
但 YOLO 大不相同。

如果把目標(biāo)檢測看做是一個捕魚的過程,其他算法是拿著漁叉一個一個精準(zhǔn)地狙擊,那么 YOLO 就粗獷的多,一個漁網(wǎng)撒撒下去,一網(wǎng)打盡。
YOLO 的預(yù)測是基于整個圖片的,并且它會一次性輸出所有檢測到的目標(biāo)信息,包括類別和位置。
YOLO 的算法思路。
YOLO 的算法思路其實挺簡單的。

縮放輸入的圖片
將圖片送入到卷積神經(jīng)網(wǎng)絡(luò)中進(jìn)行預(yù)測
通過預(yù)測的結(jié)果進(jìn)行置信度的閾值處理,得到最終的結(jié)果。
下面講解算法細(xì)節(jié)。
分割圖片
YOLO 會把輸入圖片分割成 SxS 個網(wǎng)格,如果一個目標(biāo)的中心點落在某個網(wǎng)格當(dāng)中,那么對應(yīng)的那個網(wǎng)格就負(fù)責(zé)預(yù)測這個目標(biāo)的大小和類別。

上面的圖片示例中,狗的中心點落在了藍(lán)色的網(wǎng)格當(dāng)中,所以藍(lán)色的網(wǎng)格就負(fù)責(zé)這個目標(biāo)的信息預(yù)測。
每個網(wǎng)格目標(biāo)的預(yù)測
每個網(wǎng)格都會預(yù)測 B 個 bbox 和 bbox 對應(yīng)的置信值 Confidence,bbox 預(yù)測目標(biāo)的位置,Confidence 用來反映這個網(wǎng)格是否有包含目標(biāo)及 bbox 的準(zhǔn)確性有多高。

但是需要注意的是,如果一個網(wǎng)格它并不包含目標(biāo),那么 P r ( o b j ) Pr(obj)Pr(obj) 就等于 0,反之等于 1,所以,C 等同于預(yù)測出來的 bbox 同 groundtruth 的 IOU。
每一個 bbox 由 5 個預(yù)測量組成:x、y、w、h、confidence。
x,y 是 bbox 中心點相對于對應(yīng)網(wǎng)格的偏移量比例,并且它們的取值是 0 ~ 1 之間,也就是它們有相對于網(wǎng)格的尺寸做歸一化處理。
同樣,w、h 都有經(jīng)過歸一化,因此它們的值都在 0 ~ 1 之間。
w 和 h 是 bbox 相對于整張圖片尺寸的比例。
confidence 剛剛有講過,它代表了預(yù)測出來的 bbox 與 groundtruth 的 bbox 之間的 IOU。
每個網(wǎng)格除了 bbox 外,還會預(yù)測 C 個條件概率

這個條件概率指的是當(dāng)網(wǎng)格中存在目標(biāo)時候,目標(biāo)類別的概率分布。
條件概率針對的是每一個網(wǎng)格,而不是每一個 bbox,因為每個網(wǎng)格會預(yù)測 B 個 bbox。
在測試階段,YOLO 會將條件概率和每個 bbox 的 confidence 相乘。

這樣的結(jié)果是針對每一個 bbox 而言的目標(biāo)類別概率分布的置信值,這個置信值同時表達(dá)了 2 樣?xùn)|西,一個是目標(biāo)是某個類別的概率,一個是預(yù)測的 bbox 離真實的 bbox 有多遠(yuǎn)。

YOLO 把輸入圖片劃分成 SxS 個網(wǎng)格,每個網(wǎng)格都會預(yù)測 B 個 bbox 和 C 個目標(biāo)類別的條件概率,并且每一個 bbox 包含 x、y、w、h、confidence 5 個參數(shù)。
所以,YOLO 最終的預(yù)測結(jié)果可以整合成一個尺寸為 SS(5*B+C) 的 tensor。
B、S、C 這幾個值都由網(wǎng)絡(luò)結(jié)構(gòu)的設(shè)計者決定,YOLO v1 在 PASCAL VOC 數(shù)據(jù)集上評估時,S = 7,B = 2。
因為這個數(shù)據(jù)集有 20 個種類,所以 C = 20,套用前面的公式,最終預(yù)測時 Tensor 的尺寸為 7730。
YOLO 的網(wǎng)絡(luò)結(jié)構(gòu)設(shè)計
YOLO 是基于 CNN 的,論文作者說他受 GooLeNet 結(jié)構(gòu)的啟發(fā),然后構(gòu)建了一個新的網(wǎng)絡(luò)結(jié)構(gòu)。
YOLO 用 1x1 的卷積核代替了 GooLeNet 的 Inception 模塊來做降維度。
YOLO 有 24 個卷積層,然后后面跟著 2 個全連接層。
下面是它的網(wǎng)絡(luò)結(jié)構(gòu)。

大家看到,YOLO 最終的預(yù)測輸出就是一個 7x7x30 的 tensor。

這張圖片也可以大致示意最終預(yù)測的 tensor 的結(jié)構(gòu)。
YOLO 的訓(xùn)練過程
YOLO 在 ImageNet 上用前 20 個卷積層和 1 個全連接層做通用的類別識別訓(xùn)練,并達(dá)到比較高的準(zhǔn)確率。
之后,YOLO 作者在預(yù)訓(xùn)練好的結(jié)構(gòu)上添加了 4 個卷積層和 1 個全連接層做目標(biāo)識別訓(xùn)練。
因為想提高目標(biāo)識別的整體表現(xiàn),所以 YOLO 在 ImageNet 預(yù)訓(xùn)練時,輸入圖片尺寸是 224x224,但在 PASCAL VOC 上做目標(biāo)識別的專項訓(xùn)練時,輸入圖片尺寸變成了 448x448
除了最后一層采用線性激活函數(shù)外,其他層都采用 leaky Relu。
YOLO 的 Loss 設(shè)定
我們都知道,采用合適的 loss 對于訓(xùn)練一個神經(jīng)網(wǎng)絡(luò)而言非常重要。
而我認(rèn)為,只有理解了 YOLO 的 loss 設(shè)計原則,才算真正理解了 YOLO 算法的核心.
我們知道,一般 Loss 值越低,代表網(wǎng)絡(luò)準(zhǔn)確度越高,訓(xùn)練的越有效,所以訓(xùn)練時基本上是以減弱 loss 值為目標(biāo)的。
YOLO 作者在訓(xùn)練時,用 sum-squared error (誤差的平方的和)來作為 loss 進(jìn)行優(yōu)化。
采用 sum-squared error 是因為它容易進(jìn)行優(yōu)化,但是它也有不好的地方,那就是對于提高 mAP 的表現(xiàn)有些吃力。
sum-squared error 會讓 Loss 函數(shù)對于位置預(yù)測、類別預(yù)測的誤差權(quán)重一樣。
實際情況是,YOLO 在每一張圖片上會預(yù)測 772=98 個 bbox,但只有很少的 bbox 才包含目標(biāo),哪些不包含目標(biāo)的 bbox 它們的 confidence 會在訓(xùn)練過程中很快變成 0,所以哪些包含了目標(biāo)的網(wǎng)格它們預(yù)測的 bbox 的梯度會更加急劇變化,這樣而言,整個預(yù)測系統(tǒng)處于不平衡也不穩(wěn)定的狀態(tài),最終可能出現(xiàn) loss 無法收斂。
為了,糾正和改善情況,YOLO 的作者調(diào)整了 bbox 的坐標(biāo)誤差和 沒有包含目標(biāo)時 confidence 的誤差權(quán)重,也可以看做是添加了不同的懲罰系數(shù),分別是 5 和 0.5。
為什么這樣做呢?
可以這樣理解,整個 YOLO 系統(tǒng)其實最有效的地方就是那些包含了目標(biāo)中心點的網(wǎng)格它們所預(yù)測的 2 個 bbox,所以它們這 2 個 bbox 的位置信息就至關(guān)重要,所以它們的坐標(biāo)就不允許它們變化劇烈,所以就需要添加一個系數(shù)放大它們的誤差,進(jìn)而達(dá)到懲罰的目的。
而沒有包含目標(biāo)的網(wǎng)格,雖然它們也會預(yù)測 bbox,也會有 confidence 的預(yù)測,但基本等同于無效,所以可以看做它們對于整體的 Loss 而言,沒有那么重要,因此要減弱它們對于 Loss 的影響,以防止它去干擾正常的包含了目標(biāo)的那些 bbox 的 confidence 表現(xiàn),畢竟它無關(guān)緊要。
說到這里,我有思考一個問題:
如果要減弱沒有 object 時的 confidence 對 loss 整體的影響,為什么不做到極致?讓懲罰系數(shù)由 0.5 變成 0 不更好嗎?
我沒有標(biāo)準(zhǔn)答案,但我的理解是那樣會讓 YOLO 這個系統(tǒng)失衡,喪失了預(yù)測背景的能力,所以也失去了某種綜合的能力。
sum-squared error 還有一個問題,那就是它會讓大的 bbox 和小的 bbox 位置誤差敏感度一樣。
比如預(yù)測一個小的 bbox,groundtruth 的 width 是 4,它預(yù)測是 3,那么它的誤差是 1.
再預(yù)測一個大的 bbox,groundtruth 的 width 是 100,預(yù)測值是 99,那么誤差也是 1.
但大家很容易發(fā)現(xiàn),進(jìn)行小尺寸的 bbox 預(yù)測時,誤差更敏感,所以 sum-sqaured error 手段需要改良。
YOLO 采用的是用預(yù)測值和 groundtruth 各自的平方根做誤差,然后再 sum-sqaured error。
還是用剛才的例子,小的 bbox width prediction = 3,groundtruth = 4,誤差為 0.067。
大的 bbox width prediction = 99,groundtruth = 100,誤差為 0.0025。
所以,完美的解決了這個問題。
最終的 Loss 變成了一個復(fù)合的 Loss,公式如下:

需要注意的是,YOLO 每個網(wǎng)格預(yù)測兩個 bbox,最終只有 1 個 bbox 來負(fù)責(zé)代表相應(yīng)的目標(biāo)的 bbox 位置,它們通過 Confidence 比較,也就是 IOU 比較,勝出的是分?jǐn)?shù)更高的那個,進(jìn)行 loss 計算時,也是這個 bbox 才能參與。
其它具體的訓(xùn)練策略如下:
第一個 epoch,學(xué)習(xí)率從 0.001 緩慢變成 0.01.
接下來的 75 個 epoch ,學(xué)習(xí)率固定為 0.01
之后又用 0.001 訓(xùn)練 30 個 epoch
最后用 0.0001 訓(xùn)練 40 個 epoch
為了避免過擬合,YOLO 訓(xùn)練時有采用 dropout 和數(shù)據(jù)增強手段。
總結(jié)
YOLO v1 也有和當(dāng)年其它杰出的目標(biāo)檢測系統(tǒng)做對比,但在今天來看,這個并不十分重要,重要的是我們需要理解 YOLO 快的原因。
YOLO 就是一個撒漁網(wǎng)的捕魚過程,一次性搞定所有的目標(biāo)定位。
YOLO 快的原因在于比較粗的粒度將輸入圖片劃分網(wǎng)格,然后做預(yù)測。
YOLO 的算法精髓都體現(xiàn)在它的 Loss 設(shè)計上及作者如何針對問題改進(jìn) Loss,這種思考問題的方式才是最值得我們學(xué)習(xí)的。