看完吳恩達老師的 Deeplearning.ai 中目標檢測課程的學習筆記。算法
圖像分類、目標定位以及檢測的區別以下圖所示,前兩個是圖片中只有 1 個對象的狀況,而檢測是圖片有多個對象的狀況。網絡
因此,目標定位其實是在分類的基礎上定位到對象的位置,即找到對象在哪裏而且直到這個對象是屬於哪一類。函數
在圖像分類中,通常定義的標籤 y 的維度和類別是同樣的,即假如是有 3 個類別,那麼標籤 y 的維度也是 3 個,好比令 $y=[c_1, c_2, c_3]$ ,而後輸出的時候就判斷哪一個類別的預測機率大,就將其做爲該對象的預測類別。性能
而在目標定位中,增長了尋找對象的位置的工做,那麼標籤就須要有座標信息,因此這裏假設是 3 個類別,定義其標籤爲:
$$
y = \ \begin{bmatrix}p_c \ b_x \ b_y \ b_h \ b_w \ c_1 \ c_2 \ c_3 \\end{bmatrix}
$$
其中,$p_c$ 表示圖片是否包含有對象,若是對象屬於指定的3 個類別中的一個,那麼$p_c=1$, 不然就是 $p_c=0$,而後接下來的 $b_x, b_y, b_h, b_w$ 表示的就是座標,或者說就是邊界框參數,通常來講就是左上角的座標加上邊界框的寬和高,而後最後 3 個就是表明類別了,有多少個類別,就有多少個參數,其數值表示的預測機率。學習
而後神經網絡的損失函數,通常就是採用平方偏差策略,假設類別 $y$ 和網絡的輸出 $\hat{y}$,那麼損失函數就是這麼計算了,根據上述的標籤訂義,是有 9 維的:
$$
L(\hat{y}, y) = (\hat{y_1}-y_1)2+(\hat{y_2}-y_2)2+\dots +(\hat{y_8}-y_8)^2
$$
固然了,這裏是用平方偏差簡化了,實際應用中,一般作法是對邊界框的座標應用平方差或者相似方法,對 $p_c$ 應用邏輯迴歸函數,或者評分預測偏差,而對類別標籤應用對數損失函數。測試
對於基於滑動窗口的目標檢測算法,首先是建立一個標籤訓練集,也就是將圖片進行剪切成多個圖片樣本,以下圖所示,將左圖進行剪切,獲得中間的 5個樣本,而後按照樣本是否包含汽車,進行標註標籤,而後將這個訓練集輸入 CNN 中,訓練獲得一個模型。優化
當訓練好模型後,就能夠進行測試,測試的例子以下所示,選擇一個特定大小的窗口,而後從圖片左上角開始滑動,每次將窗口內的圖片送入模型中,判斷該圖片內是否有汽車,依次重複操做,直到滑動窗口滑過測試圖片的每一個角落。3d
上述作法就是滑動窗口目標檢測。以某個步幅滑動這些方框窗口遍歷整張圖片,對這些方形區域進行分類,判斷是否包含目標對象。對象
該算法的一個很明顯的缺點,就是計算成本。主要緣由是跟滑動窗口的大小有關係,選擇過小的,那麼就會須要滑動不少次,也就是須要檢測多個小窗口,提升了計算成本;而若是窗口過大,那麼窗口數量會減小,可是會影響模型的性能。blog
上述介紹的實現基於滑動窗口的目標檢測的方法,效率是比較低,這裏會介紹如何經過卷積實現滑動窗口,首先須要將 CNN 的全鏈接層轉換爲卷積層,也就是獲得一個全卷積網絡(FCN),以下圖所示:
這裏的輸入圖片例子是一個 $14\times 14\times 3$ 的圖片,而後通過一個卷積核大小是 $5\times 5$ 的卷積層,輸出是 $14\times 14\times 3$ ,接着是一個 Max pooling 層,參數是 $2\times 2$ ,輸出就是 $5\times 5\times 16$ ,本來是接着兩個 $400\times 400$ 的全鏈接層,如今改成用 $1\times 1\times 400$ 的兩個卷積層。
接着是主要參考論文 OverFeat 來介紹如何經過卷積實現滑動窗口對象檢測算法。
具體實現例子以下所示,第一行表示訓練時候使用 $14\times 14\times 3$的圖片,第二行表示測試時候使用的輸入圖片大小是 $16\times 16\times 3$。而使用這個圖片,在通過卷積層的時候,這裏步幅是 2,因此卷積核是移動了四次,獲得了輸出是 $12\times 12\times 16$,最終的輸出也是 $2\times 2\times 4$。
能夠看到,其實在這 4 次卷積操做中有不少計算是重複的,由於有不少區域都是重疊的,具體四次以下所示,不一樣顏色的框表示四次操做的範圍,左邊第一個圖的紅色,而後移動 2 格,是第二個圖中綠色框的區域,接着是第三張圖裏橙色,也就是左下角,而後第四張圖裏右下角,其實中間區域都是重疊的,也就是四個角落是有所不一樣。
簡單說,經過這個卷積操做,咱們就能夠不用將測試圖片分割成 4 個子圖片,分別輸入網絡中,執行前向操做,進行預測,直接整張圖輸入網絡便可,卷積層就會幫咱們完成這個操做,也就是一次前向操做便可,節省了 4 倍的時間。
不過,這種方法雖然提升了算法的效率,但也有一個缺點,就是邊界框的位置可能不夠準確。
接下來要介紹如何能夠獲得精確的邊界框,這裏介紹的就是著名的 YOLO(You only look once) 算法,目前也是目標檢測裏很經常使用的一種算法,以及有了更多的版本,從最初的 YOLO,到目前的 YOLOv5,持續進行改進和提高。
YOLO 算法的作法以下圖所示,採用一個 $3\times 3$ 的網格,將輸入圖片分紅了 9 個區域,而後檢測每一個區域內是否有目標對象,YOLO 算法會將檢測到的對象,根據其中點位置,將其分配到中點所在的格子裏,因此下圖中編號 4 和 6 包含了汽車,可是編號 5 雖然同時有兩輛車的一部分,但由於中心點不在,因此這個格子輸出的結果是不包含有汽車。
採用這個算法,網絡輸出的結果就是 $3\times 3 \times 8$ , 這裏表示 $3\times 3$ 的網格,每一個網格的結果是一個 8 維的向量,也是以前定義好的,即 $p_c, b_x, b_y, b_w, b_h, c_1, c_2, c_3$ 。
該算法的優勢就是CNN 能夠輸出精確的邊界框,在實踐中能夠採用更多的網格,好比 $19\times 19$,即使圖片中包含多個對象,但若是網格數量越多,每一個格子就越小,一個格子存在多個對象的機率就會很低。
YOLO 算法的另外一個優勢是它採用卷積實現,速度很是快,這也是它很受歡迎的緣由。
交併比(IoU)表示兩個邊界框交集和並集之比。並集就是以下圖中綠色區域部分,即同時包含兩個邊界框的區域;而交集就是兩個邊界框重疊部分,下圖中橙色區域。因此交併比就是橙色區域面積除以綠色區域的面積。
通常來講,IoU 大於等於 0.5,就能夠說檢測正確,結果是能夠接受的,這也是通常的約定。但IoU 越大,邊界框就約精確了。
這也是衡量定位精確到的一種方式,IoU 是衡量了兩個邊界框重疊的相對大小。
目前的檢測算法還會存在一個問題,就是對同一個對象做出屢次的檢測,而非極大值抑制就能夠確保算法只對每一個對象檢測一次。
非極大值抑制算法的執行過程以下圖所示,這裏是採用 $19\times 19$ 的網格,對每一個網格先執行檢測算法,獲得的輸出就是 $19\times 19 \times 8$。固然這裏只是預測是否有汽車,那麼其實能夠暫時不須要分類部分,也就是每一個網格輸出一個 5 維向量,$p_c$ 以及邊界框的四個座標參數。
而後開始實現非極大值抑制算法:
上述說的檢測都是限制於一個格子檢測出一個對象,但若是須要一個格子能夠檢測多個對象,那麼就須要用到 anchor box。
以下圖所示,假設如今輸入圖片是左圖中的例子,在第三行的第二個格子中是恰好同時存在人和汽車,而且中心點都落在這個格子裏,但根據以前的算法,只能檢測到其中一個對象。而要解決這個問題,就須要用到 anchor box 了。
這裏 anchor box 的思路是預先定義兩個不一樣形狀的 anchor box,如上圖的兩個,固然實際狀況裏可能會採用更多的 anchor box,好比 5 個甚至更多。不過這裏只須要兩個便可。
接着就是從新定義標籤,再也不是開始的 8 維向量,而是 $2\times 8$ 的向量,前面 8 個和 anchor box1 相關聯,然後面 8 個和 anchor box2 相關聯。如上圖右側的 $y$ 所示。
在實際例子中,還有一些狀況:
另外,通常怎麼選擇 anchor box 呢?一般是手工指定 anchor box 形狀,選擇 5-10 個不一樣形狀的,儘可能覆蓋多種不一樣的形狀,覆蓋你想要檢測對象的各類形狀。
另外一種作法是在 YOLO 後期論文中介紹的,k-平均算法,用它來選擇一組 anchor box,最具備表明性的一組 anchor box。
目標檢測裏另外一個比較出名的算法,R-CNN,跟 YOLO 相比,是另外一種思路,因此也基於此算法產生了不少檢測算法,好比對其持續改進優化的,Fast-RCNN,Faster-RCNN 等。
R-CNN 算法是嘗試找到一些區域,在這部分區域裏運行 CNN 進行檢測。而選擇這些候選區域的方法是運行圖像分割算法,分割的結果以下圖所示。根據分割算法獲得的結果,在不一樣的區域運行分類器,判斷該區域是否有目標對象,好比圖中標註號碼的幾個區域。
這種作法相比滑動窗口,多是不須要圖片的每一個地方都去檢測一遍,只須要對分割算法獲得的色塊,加上邊界框,而後對邊界框內的區域運行分類器,雖然是工做量會減小一些,但實際上速度仍是很慢,但優勢是精度會很不錯,這個就和 YOLO 算法恰好相反。
由於速度太慢的問題,後續也有不少改進的算法