第二十七節,IOU和非極大值抑制
你如何判斷對象檢測算法運作良好呢?在這一節中,你將了解到並交比函數,可以用來評價對象檢測算法。
一 並交比(Intersection over union )
在對象檢測任務中,你希望能夠同時定位對象,所以如果實際邊界框是這樣的,你的算法給出這個紫色的邊界框,那麽這個結果是好還是壞?所以交並比(loU)函數做的是計算兩個邊界框交集和並集之比。兩個邊界框的並集是這個區域,就是屬於包含兩個邊界框區域(綠色陰影表示區域),而交集就是這個比較小的區域(橙色陰影表示區域),那麽交並比就是交集的大小,這個橙色陰影面積,然後除以綠色陰影的並集面積。
一般約定,在計算機檢測任務中,如果IoU≥0.5,就說檢測正確,如果預測器和實際邊界框完美重疊, loU 就是 1,因為交集就等於並集。但一般來說只要loU≥ 0.5,那麽結果是可以接受的,看起來還可以。一般約定,0.5 是閾值,用來判斷預測的邊界框是否正確。一般是這麽約定,但如果你希望更嚴格一點,你可以將 loU 定得更高,比如說大於 0.6 或者更大的數字,但 loU 越高,邊界框越精確。
所以這是衡量定位精確度的一種方式,你只需要統計算法正確檢測和定位對象的次數,你就可以用這樣的定義判斷對象定位是否準確。再次, 0.5 是人為約定,沒有特別深的理論依據,如果你想更嚴格一點,可以把閾值定為 0.6。 有時我看到更嚴格的標準,比如 0.6 甚至 0.7,但很少見到有人將閾值降到 0.5 以下。
人們定義 loU 這個概念是為了評價你的對象定位算法是否精準,但更一般地說, loU 衡量了兩個邊界框重疊地相對大小。如果你有兩個邊界框,你可以計算交集,計算並集,然後求兩個數值的比值,所以這也可以判斷兩個邊界框是否相似,我們將在後面再次用到這個函數,當我們討論非最大值抑制時再次用到。
二 非極大值抑制
到目前為止你們學到的對象檢測中的一個問題是,你的算法可能對同一個對象做出多次檢測,所以算法不是對某個對象檢測出一次,而是檢測出多次。非極大值抑制這個方法可以確保你的算法對每個對象只檢測一次,我們講一個例子。
假設你需要在這張圖片裏檢測行人和汽車,你可能會在上面放個 19×19 網格,理論上這輛車只有一個中點,所以它應該只被分配到一個格子裏,左邊的車子也只有一個中點,所以理論上應該只有一個格子做出有車的預測。
實踐中當你運行對象分類和定位算法時,對於每個格子都運行一次,所以這個格子(編號 1)可能會認為這輛車中點應該在格子內部,這幾個格子(編號 2、 3)也會這麽認為。對於左邊的車子也一樣,所以不僅僅是這個格子,如果這是你們以前見過的圖像,不僅這個格(編號 4)子會認為它裏面有車,也許這個格子(編號 5)和這個格子(編號 6)也會,也許其他格子也會這麽認為,覺得它們格子內有車。
我們分步介紹一下非極大抑制是怎麽起效的,因為你要在 361 個格子上都運行一次圖像檢測和定位算法,那麽可能很多格子都會舉手說我的,我這個格子裏有車的概率很高,而不是 361 個格子中僅有兩個格子會報告它們檢測出一個對象。所以當你運行算法的時候,最後可能會對同一個對象做出多次檢測,所以非極大值抑制做的就是清理這些檢測結果。這樣一輛車只檢測一次,而不是每輛車都觸發多次檢測。
所以具體上,這個算法做的是,首先看看每次報告每個檢測結果相關的概率pc,實際上是pc乘以c1、 c2或c3。現在我們就說,這個pc檢測概率,首先看概率最大的那個,這個例子(右邊車輛)中是 0.9,然後就說這是最可靠的檢測,所以我們就用高亮標記,就說我這裏找到了一輛車。這麽做之後,非極大值抑制就會逐一審視剩下的矩形,所有和這個最大的邊框有很高交並比,高度重疊的其他邊界框,那麽這些輸出就會被抑制。所以這兩個矩形pc分別是 0.6 和 0.7,這兩個矩形和淡藍色矩形重疊程度很高,所以會被抑制,變暗,表示它們被抑制了。
接下來,逐一審視剩下的矩形,找出概率最高, pc最高的一個,在這種情況下是 0.8,我們就認為這裏檢測出一輛車(左邊車輛),然後非極大值抑制算法就會去掉其他 loU 值很高的矩形。所以現在每個矩形都會被高亮顯示或者變暗,如果你直接拋棄變暗的矩形,那就剩下高亮顯示的那些,這就是最後得到的兩個預測結果。
所以這就是非極大值抑制,非最大值意味著你只輸出概率最大的分類結果,但抑制很接近,但不是最大的其他預測結果,所以這方法叫做非極大值抑制。
我們來看看算法的細節,首先這個 19×19 網格上執行一下算法,你會得到 19×19×8 的輸出尺寸。不過對於這個例子來說,我們簡化一下,就說你只做汽車檢測,我們就去掉c1、 c2或c3,然後假設這條線對於 19×19 的每一個輸出,對於 361 個格子的每個輸出,你會得到這樣的輸出預測,就是格子中有對象的概率(pc),然後是邊界框參數(bx、 by、 b?和bw)。如果你只檢測一種對象,那麽就沒有c1、 c2或c3這些預測分量。
現在要實現非極大值抑制,你可以做的第一件事是,我們就將所有的預測值,所有的邊界框pc小於或等於某個閾值, 比如≤0.6 的邊界框去掉。
我們就這樣說,除非算法認為這裏存在對象的概率至少有 0.6,否則就拋棄,所以這就拋棄了所有概率比較低的輸出邊界框。所以思路是對於這 361 個位置,你輸出一個邊界框,還有那個最好邊界框所對應的概率,所以我們只是拋棄所有低概率的邊界框。
接下來剩下的邊界框,沒有拋棄沒有處理過的,你就一直選擇概率pc最高的邊界框,然後把它輸出成預測結果,這個過程就是上面所說的,取一個邊界框,讓它高亮顯示,這樣你就可以確定輸出做出有一輛車的預測。
接下來去掉所有剩下的邊界框,任何沒有達到輸出標準的邊界框,之前沒有拋棄的邊界框,把這些和輸出邊界框有高重疊面積和上一步輸出邊界框有很高交並比的邊界框全部拋棄。所以 while 循環的第二步是之前所說的變暗的那些邊界框,和高亮標記的邊界重疊面積很高的那些邊界框拋棄掉。在還有剩下邊界框的時候,一直這麽做,把沒處理的都處理完,直到每個邊界框都判斷過了.
上面只介紹了算法檢測單個對象的情況,如果你嘗試同時檢測三個對象,比如說行人、汽車、摩托,那麽輸出向量就會有三個額外的分量。事實證明,正確的做法是獨立進行三次非極大值抑制,對每個輸出類別都做一次。
這就是非極大值抑制,如果你能實現我們說過的對象檢測算法,你其實可以得到相當不錯的結果。 但結束我們對 YOLO 算法的介紹之前,最後我還有一個細節想給大家分享,可以進一步改善算法效果,就是 anchor box 的思路。
三 Anchor Boxes
到目前為止,對象檢測中存在的一個問題是每個格子只能檢測出一個對象,如果你想讓一個格子檢測出多個對象,你可以這麽做,就是使用 anchor box 這個概念,我們從一個例子開始講吧。
假設你有這樣一張圖片,對於這個例子,我們繼續使用 3×3 網格,註意行人的中點和汽車的中點幾乎在同一個地方,兩者都落入到同一個格子中。所以對於那個格子,如果y輸出這個向量:
你可以檢測這三個類別,行人、汽車和摩托車,它將無法輸出檢測結果,所以我必須從兩個檢測結果中選一個。
而 anchor box 的思路是,這樣子,預先定義兩個不同形狀的 anchor box,或者 anchorbox 形狀,你要做的是把預測結果和這兩個 anchor box 關聯起來。一般來說,你可能會用更多的 anchor box,可能要 5 個甚至更多,但在這裏,我們就用兩個 anchor box,這樣介紹起來簡單一些。
你要做的是定義類別標簽 , 用的向量不再是上面這個:
而是重復兩次:
前面的pc,bx,by,bh,bw,c1,c2,c3(綠色方框標記的參數)是和 anchor box 1 關聯的 8 個參數,後面的 8 個參數(橙色方框標記的元素)是和 anchor box 2 相關聯。因為行人的形狀更類似於anchor box 1 的形狀,而不是 anchor box 2 的形狀,所以你可以用這 8 個數值(前 8 個參數),這麽編碼pc=1,是的,代表有個行人,用bx,by,bh,bw來編碼包住行人的邊界框,然後用c1,c2,c3(c1=1,c2=0,c3=0)來說明這個對象是個行人。
然後是車子,因為車子的邊界框比起 anchor box 1 更像 anchor box 2 的形狀,你就可以這麽編碼,這裏第二個對象是汽車,然後有這樣的邊界框等等,這裏所有參數都和檢測汽車相關(pc=1,bx,by,bh,bw,c1=0,c2=1,c3=0)。
總結一下, 用 anchor box 之前,你做的是這個,對於訓練集圖像中的每個對象,都根據那個對象中點位置分配到對應的格子中,所以輸出y就是 3×3×8,因為是 3×3 網格,對於每個網格位置,我們有輸出向量,包含pc,然後邊界框參數bx,by,bh,bw,然後c1,c2,c3。
現在用到 anchor box 這個概念,是這麽做的。現在每個對象都和之前一樣分配到同一個格子中,分配到對象中點所在的格子中,以及分配到和對象形狀交並比最高的 anchor box 中。所以這裏有兩個 anchor box,你就取這個對象,如果你的對象形狀是這樣的(編號 1,紅色框),你就看看這兩個 anchor box, anchor box 1 形狀是這樣(編號 2,紫色框), anchorbox 2 形狀是這樣(編號 3,紫色框),然後你觀察哪一個 anchor box 和實際邊界框(編號1,紅色框)的交並比更高,不管選的是哪一個,這個對象不只分配到一個格子,而是分配到一對,即(grid cell, anchor box)對,這就是對象在目標標簽中的編碼方式。所以現在輸出 y就是 3×3×16,或者你也可以看成是3×3×2×8,因為現在這裏有 2 個 anchor box,而 y是 8 維的。 y維度是 8,因為我們有 3 個對象類別,如果你有更多對象,那麽y的維度會更高。
所以我們來看一個具體的例子,對於這個格子(編號 2),我們定義一下y=
所以行人更類似於 anchor box 1 的形狀,所以對於行人來說,我們將她分配到向量的上半部分。是的,這裏存在一個對象,即pc = 1,有一個邊界框包住行人,如果行人是類別 1,那麽 c1 = 1, c2 =0, c3 = 0(編號 1 所示的橙色參數)。車子的形狀更像 anchor box 2,所以這個向量剩下的部分是 pc = 1,然後和車相關的邊界框,然後 c1 = 0, c2 =1, c3 = 0(編號 1 所示的綠色參數)。所以這就是對應中下格子的標簽 y,這個箭頭指向的格子(編號 2 所示)。
現在其中一個格子有車,沒有行人,如果它裏面只有一輛車,那麽假設車子的邊界框形狀是這樣,更像 anchor box 2,如果這裏只有一輛車,行人走開了,那麽 anchor box 2 分量還是一樣的,要記住這是向量對應 anchor box 2 的分量和 anchor box 1 對應的向量分量,你要填的就是,裏面沒有任何對象,所以 pc = 0, 然後剩下的就是 don’t care-s(即? )(編號 3所示)。
現在還有一些額外的細節,如果你有兩個 anchor box,但在同一個格子中有三個對象,這種情況算法處理不好,你希望這種情況不會發生,但如果真的發生了,這個算法並沒有很好的處理辦法,對於這種情況,我們就引入一些打破僵局的默認手段。還有這種情況,兩個對象都分配到一個格子中,而且它們的 anchor box 形狀也一樣,這是算法處理不好的另一種情況,你需要引入一些打破僵局的默認手段,專門處理這種情況,希望你的數據集裏不會出現這種情況,其實出現的情況不多,所以對性能的影響應該不會很大。
這就是 anchor box 的概念,我們建立 anchor box 這個概念,是為了處理兩個對象出現在同一個格子的情況,實踐中這種情況很少發生,特別是如果你用的是 19×19 網格而不是3×3 的網格,兩個對象中點處於 361 個格子中同一個格子的概率很低,確實會出現,但出現頻率不高。也許設立 anchor box 的好處在於 anchor box 能讓你的學習算法能夠更有征對性,特別是如果你的數據集有一些很高很瘦的對象,比如說行人,還有像汽車這樣很寬的對象,這樣你的算法就能更有針對性的處理,這樣有一些輸出單元可以針對檢測很寬很胖的對象,比如說車子,然後輸出一些單元,可以針對檢測很高很瘦的對象,比如說行人。
最後,你應該怎麽選擇 anchor box 呢?人們一般手工指定 anchor box 形狀,你可以選擇 5 到 10 個 anchor box 形狀,覆蓋到多種不同的形狀,可以涵蓋你想要檢測的對象的各種形狀。還有一個更高級的版本,我就簡單說一句,你們如果接觸過一些機器學習,可能知道後期 YOLO 論文中有更好的做法,就是所謂的 k-平均算法,可以將兩類對象形狀聚類,如果我們用它來選擇一組 anchor box,選擇最具有代表性的一組 anchor box,可以代表你試圖檢測的十幾個對象類別,但這其實是自動選擇 anchor box 的高級方法。如果你就人工選擇一些形狀,合理的考慮到所有對象的形狀,你預計會檢測的很高很瘦或者很寬很胖的對象,這應該也不難做。
第二十七節,IOU和非極大值抑制