增加檢測類別?這是一份目標檢測的一般指南
目標檢測技術作為計算機視覺的重要方向,被廣泛應用於自動駕駛汽車、智能攝像頭、人臉識別及大量有價值的應用上。這些系統除了可以對圖像中的每個目標進行識別、分類以外,它們還可以通過在該目標周圍繪製適當大小的邊界框來對其進行定位。本文作者從圖像識別與目標檢測的區別開始,進一步簡單介紹了目標檢測的基本模塊與實現方法。本文是目標檢測的一般指南,它並沒有詳細介紹主流的目標檢測演算法,這些演算法讀者可參考從 RCNN 到 SSD,這應該是最全的一份目標檢測演算法盤點。
本文受 PyImageSearch 的讀者 Ezekiel 的啟發,他上個星期在郵件中諮詢道:
Adrian 你好,
我仔細地瀏覽了您之前關於深度學習目標檢測 的文章及其跟進的實時深度學習目標檢測 。感謝你做的這一切,我在自己的樣例項目中使用了你的源代碼,但是我有兩個問題:
1. 我該如何過濾/忽略那些我不感興趣的類?
2. 我如何才能向自己的目標檢測器中增加新類別?有這個可能嗎?
如果你能就這兩個問題寫一篇文章,我將不勝感激。
Ezekiel 並不是受此問題困擾的唯一讀者。事實上,如果你仔細瀏覽了我最近關於深度目標檢測兩篇文章的評論,你會發現最常見的問題可以被表述為:
我該如何修改你的源代碼來包含我自己的類別?
由於這是一個如此常見的問題,並且是關於神經網路/深度學習目標檢測器實際工作的一個誤解,所以我決定在今天的博客中重溫深度學習目標檢測的話題。
具體地,你將在這篇文章中學到以下內容:
圖像分類和目標檢測的區別
深度學習目標檢測器的組成:包含不同目標檢測架構的區別和基本模型之間的區別
如何使用預訓練模型進行深度學習目標檢測
如何從一個深度學習模型中過濾或者忽略一些預測類別
向深度神經網路增加類別或從中刪除類別時常見的誤區和誤解
為了更多地了解深度學習目標檢測,並解釋清楚我們對基於深度學習的目標檢測的一些誤區和誤解,請繼續閱讀本文。
想要查看本文相關的源碼?請查看原文的下載鏈接(https://www.pyimagesearch.com/2018/05/14/a-gentle-guide-to-deep-learning-object-detection/#):
深度學習目標檢測的一般指南
今天的博客是對基於深度學習的目標檢測的簡單介紹。我儘可能對深度學習目標檢測器的組成做一個概述,包括使用預訓練的目標檢測器執行任務的源代碼。
你可以使用這份指南來幫助學習深度學習目標檢測,但是也要意識到,目標檢測是高度細節化的工作,我不可能在一篇文章中包含關於深度學習目標檢測的所有細節。
這篇文章將從討論圖像分類和目標檢測之間的本質區別開始,其中包括判斷一個圖像分類網路是否可以用於目標檢測,以及在什麼情況下可以這樣使用等話題。
當我們理解了什麼是目標檢測時,隨後會概述一個深度學習目標檢測器的核心模塊。它一般包括目標檢測架構和基本模型,不熟悉目標檢測的讀者可能會誤解這兩個部分。
在這裡,我們將使用 OpenCV 來實現實時深度學習目標檢測。我也會展示如何在不修改網路架構或者重新訓練的情況下忽略或者過濾一些不感興趣的目標類別。最後,我們通過討論如何從深度學習目標檢測器中增加或者刪除類別來總結本文。
圖像分類和目標檢測的區別
圖 1: 圖像分類(左)和目標檢測(右)的區別是比較直觀和簡單的。在圖像分類中,整幅圖像被分類為單一的標籤。而在目標檢測中,我們的神經網路還要找出圖像中目標的位置(有可能是多個)。
在進行標準的圖像分類時,我們將一張給定的圖像輸入到神經網路,然後得到一個最可能的標籤,而且也許會同時得到相關的概率。
這個類別標籤用來表徵整個圖像的內容,或者至少是圖像最主要的可見內容。例如,上面的圖 1 中,給定輸入圖像(左),我們的 CNN 給它的標籤是「比格犬」。所以我們可以認為圖像分類具有以下特點:
一張圖像輸入
一個類別標籤輸出
無論是通過深度學習還是其他計算機視覺技術的目標檢測,都是基於圖像分類構建的,只不過需要精確定位每個對象在圖像中出現的位置。在進行目標檢測的時候,給定一張輸入圖像,我們期望得到:
一個邊界框列表,或者一幅圖像中每個對象的(x,y)坐標
與每個邊界框關聯的類別標籤
與每個邊界框和類別標籤關聯的概率或者置信度得分
圖 1(右)展示了一個深度學習目標檢測的例子。請注意,人物和狗都被用邊界框找出了位置,同時類標籤也被預測到了。
所以,目標檢測允許我們:
向網路輸入一張圖像
得到多個邊界框以及類別標籤
深度學習圖像分類可以被用於目標檢測嗎?
圖 2:非端到端深度學習的目標檢測器使用一個滑動窗口(左)+圖像金字塔(右)相結合的方法來分類。
所以現在你理解了圖像分類和目標檢測的根本區別:
在進行圖像分類時,我們輸入一張圖像,得到一個輸出類別
然而在進行目標檢測時,我們輸入一張圖像,得到多個邊界框以及類別標籤的輸出
這自然引發這麼一個問題:
我們可以拿一個已訓練的分類網路,將其用於目標檢測嗎?
這個答案有些棘手,因為這在技術上是可以的,但是理由並不太明顯。解決方案涉及:
1. 應用基於計算機視覺的標準目標檢測方法(非深度學習方法),例如滑動窗口和圖像金字塔等方法通常被用在 HOG+基於線性 SVM 的目標檢測器。
2. 採用預訓練的網路,並將其作為深度學習目標檢測架構的基本網路(例如 Faster R-CNN, SSD, YOLO)。
方法 #1: 傳統的目標檢測技術路線
第一個方法不是純端到端的深度學習目標檢測器。相反,我們使用:
1. 固定尺寸的滑動窗口,它從左到右,自上而下滑動,來定位不同位置的對象。
2. 圖像金字塔,用來檢測不同尺度的對象
3. 一個預訓練(分類)的 CNN 來分類
在滑動窗和對應圖像金字塔每一次停留的時候,我們會提取 ROI(感興趣區域),將其輸入到 CNN 中,得到對 RIO 的分類。
如果標籤 L 的分類概率比某個閾值 T 高,我們就將這個 ROI 的邊界框標記為該標籤(L)。對滑動窗和圖像金字塔的每次停留都重複這個過程,我們就得到了目標檢測器的輸出。最終,我們對邊界框應用非極大值抑制(NMS),得到最終輸出的檢測結果:
圖 3:應用 NMS 會抑制重疊的和置信度不高的邊界框。這個方法在一些特定的用例中是有效的,但是它通常比較慢和繁瑣,也容易出錯。
然而,這個方法也是值得學習的,因為它可以將任意圖像分類網路轉換為一個目標檢測器,而不需要顯式地訓練一個端到端的深度學習目標檢測器。這個方法可以節省大量的時間和精力,且效率的高低具體取決於你的用例。
方法 #2:目標檢測架構的基本網路
第二個深度學習目標檢測的方法允許我們將一個預訓練的分類網路作為深度學習目標檢測架構(例如 Faster R-CNN、SSD 或者 YOLO)的基本網路。
這個方法的好處是:你可以創建一個基於深度學習的複雜端到端目標檢測器。
而其不足之處是:它需要一些關於深度學習目標檢測器如何工作的知識,我們將在後面的部分中討論這個問題。
深度學習目標檢測器的模塊
圖 4: VGG16 基本網路是 SSD 深度學習目標檢測框架的一個特徵抽取模塊。
深度學習目標檢測器有很多模塊,子模塊以及更小的子模塊,但是我們今天要重點關注的是深度學習入門讀者所困惑的兩個:
1. 目標檢測框架(不包括 Faster R-CNN, SSD, YOLO)
2. 適合目標檢測框架的基本網路
你可能已經比較熟悉基本網路(只是你之前並沒聽到它被稱作基本網路而已)。基本網路就是你常用的分類 CNN 架構,包括:
VGGNet
ResNet
MobileNet
DenseNet
通常這些網路在大數據集上進行預訓練來進行分類,例如 ImageNet,它們可以學習到很多具有鑒別能力的濾波器。
目標檢測框架由很多組成部分和子模塊構成。例如,Faster R-CNN 框架包括:
候選區域網路(RPN)
一組錨點
ROI 池化模塊
最終基於區域的卷積神經網路
在使用 SSD(單步檢測器,single shot detectors)時,具有以下的組成部分:
多框(MultiBox)
先驗(Priors)
固定先驗(Fixed priors)
請記住,基本網路只是整個深度學習目標檢測框架的眾多組件之一,上文圖 4 描述了 SSD 框架內部的 VGG-16 網路。通常,我們需要在基本網路上進行「網路手術」。這種修改:
讓它變成全卷積的形式,並接受任意輸入維度。
剪除了基本網路中更深層的卷積和池化層,將它們以一系列新層(SSD)、新模塊(Faster R-CNN),或者這兩者的一些組合代替。
這裡的「網路手術」是一種口語化的說法,它的意思是移除基本網路中的一些原始卷積層,將它們用新層替代。網路手術也是講究策略的,我們移除一些不需要的部分,然後用一組新的部分來替代它們。
然後,當我們開始訓練我們的框架進行目標檢測時,(1)新層、模塊和(2)基本網路的權重都被修改了。
再強調一次,綜述關於不同深度學習目標檢測框架是如何工作的(包括基本網路所起的作用)並不屬於本文的探討範圍。
如果你對深度學習目標檢測的完整綜述(包括理論和實現)感興趣,請參考機器之心曾經發過的文章:從 RCNN 到 SSD,這應該是最全的一份目標檢測演算法盤點 。
我是如何計算一個深度學習目標檢測器的準確度的?
在評價目標檢測器的性能時我們使用了一個叫做均值平均精度(mAP)的指標,它是以我們數據集中所有類別的交並比(IoU)為基礎的。
交並比(IoU)
圖 5: 在這個交並比的可視化例子中,標註邊界框(綠色)可以與預測的邊界框(紅色)進行對比。IoU 與 mAP 一起被用來評價一個深度學習目標檢測器的精度。計算 IoU 的簡單方程如圖 5(右)所示。
你通常會發現 IoU 和 mAP 被用於評價 HOG+線性 SVM 檢測器、Haar cascades 以及基於深度學習的方法的性能;但是請記住,實際用於生成預測邊界框的演算法並不是那麼重要。
任何一個以預測邊界框作(以及可選擇的標籤)為輸出的演算法都可以用 IoU 來評價。更一般的地,為了使用 IoU 來評價任意一個目標檢測器,我們需要:
1. 真實的邊界框(也就是測試集中表明我們的目標在圖像的哪個位置的人工標籤)
2. 模型預測到的邊界框
3. 如果你想一起計算召回率和精度,那麼還需要真實類別標籤和預測類別標籤
在圖 5(左)中,我展示了真實邊界框(綠色)與預測邊界框(紅色)相比的可視化例子。IoU 的計算可以用圖 5 右邊的方程表示。
仔細檢查這個方程你會發現,IoU 就是一個比值。在分子項中,我們計算了真實邊界框和預測邊界框重疊的區域。分母是一個並集,或者更簡單地說,是由預測邊界框和真實邊界框所包括的區域。兩者相除就得到了最終弄的得分:交並比。
平均精度均值(MAP)
圖 6:為了計算目標檢測器的 mAP@0.5,我們執行了以下計算。對於所有被標記為「正檢測」(positive detection)、具備至少 0.5 的交並比(IoU)的對象,我們對所有 N 個類別計算 IoU (>0.5) 均值,然後對 N 個均值再求平均。這個指標就是 mAP@0.5。
為了在我們的數據集中評估目標檢測器,我們需要同時基於以下兩者的 IoU 來計算 mAP:
1. 基於每個類別(也就是說每個類別的平均 IoU);
2. 數據集中所有類別(也就是說所有類別平均 IoU 的均值,所以這個術語就是平均精度均值)。
為了計算每個類別的平均精度,我們在所有的數據點上計算某個類別的 IoU。一旦我們計算出了一個類別在每個數據點的 IoU,我們對它們求一次平均(第一次平均)。
為了計算 mAP,我們對所有的 N 個類別計算平均 IoU,然後對這 N 個平均值取平均值(均值的平均)。
通常我們使用 mAP@0.5,表示測試集中要被標記為「正檢測」的目標必須具備的條件,真值不小於 0.5 的 IoU(並可以被正確地標記)。這裡的 0.5 是可以調整的,但是在所有的目標檢測數據集和挑戰中,0.5 是一個相對標準的數值。
再次強調,這只是一個關於目標檢測評價指標的快速指南,所以我將整個過程簡化了一些。
使用 OpenCV 進行基於深度學習的目標檢測
我們已經在本文以及之前的博客中討論了深度學習和目標檢測。出於完整性考慮,我們將在本文中概述實際的代碼。
我們的例子包含以 MobileNet 作為基礎模型的單次檢測器(SSD)。該模型由 GitHub 用戶 chuanqi305(https://github.com/chuanqi305/MobileNet-SSD)在 COCO 數據集上訓練得到。更多細節請瀏覽我之前的文章(https://www.pyimagesearch.com/2017/09/11/object-detection-with-deep-learning-and-opencv/),這篇文章介紹了該模型以及相關的背景信息。
讓我們回到 Ezekiel 在本文開始提出的第一個問題上。
1. 我該如何過濾/忽略那些我不感興趣的類?
我會在下面的示例代碼中回答這個問題,但是首先你需要準備一下系統:
你需要在 Python 虛擬環境中安裝版本不低於 3.3 的 OpenCV(如果你在使用 python 虛擬環境的話)。OpenCV 3.3+ 包含運行以下代碼所需的 DNN 模塊。確保使用鏈接中的 OpenCV 安裝教程之一(https://www.pyimagesearch.com/opencv-tutorials-resources-guides/),要額外注意你下載和安裝的 OpenCV 版本。
你還應該安裝我的 imutils 包(https://github.com/jrosebr1/imutils)。為了在 Python 虛擬環境中安裝/更新 imutils,簡單地使用以下命令即可: pip install --upgrade imutils。
系統準備好之後,創建一個新文件,命名為 filter_object_detection.py。下面讓我們開始:
在第 2 到 8 行中,我們導入了所需的包和模塊,尤其是 imultils 和 OpenCV。我們會使用我的 VideoStream 類處理從攝像頭獲取的幀。
我們已經具備了所需的工具,接著我們來解析命令行參數:
我們的腳本在運行時需要兩個命令行參數:
--prototxt : The path to the Caffe prototxt file which defines the model definition.
--model : Our CNN model weights file path.
--prototxt:Caffe prototxt 文件的路徑,它定義了模型的定義。
--model:CNN 模型權重的文件路徑。
你還可以有選擇性地指定--confidence,這是過濾弱檢測的閾值。
我們的模型可以預測 21 個對象類別:
CLASSES 列表包含該網路訓練時的所有類別標籤(也就是 COCO 中的標籤)。
對 CLASSES 列表的一個常見誤解是你可以:
1. 向列表增加一個新的類別標籤;
2. 或者從列表移除一個類別標籤。
……以及以為網路可以自動「了解」你想要完成的任務。
不是這樣的。
你不能簡單地修改文本標籤列表,讓網路自動修改自己,在非訓練所用數據上學習、增加或者移除模式。這並不是神經網路的運行方式。
也就是說,有一個快速的技巧,你可以使用它來過濾或者忽略你不感興趣的預測。
解決方案就是:
1. 定義一個 IGNORE 標籤集合(即網路是在這個類別標籤列表上進行訓練的,但你現在想忽略這些標籤)。
2. 對一個輸入圖像/視頻幀進行預測。
3. 忽略類別標籤存在於 IGNORE 集合中的所有預測結果。
在 Python 中實現時,IGNORE 集合是這樣的:
這裡我們忽略所有具有類別標籤「person」的預測對象(用於過濾的 if 語句會在後續內容中介紹)。
你可以很容易地增加額外的元素(CLASS 列表中的類別標籤)來忽略該集合。
接下來,我們將生成隨機的類別/框顏色,載入模型,然後啟動視頻流:
第 27 行中名為 COLORS 的隨機數組為 21 個類別中的每一個隨機生成顏色。這些顏色會在後邊用於顯示。
第 31 行中使用 cv2.dnn.readNetFromCaffe 函數載入我們的 Caffe 模型,我們所需的兩個命令行參數作為參數被傳遞。
然後我們將 VideoStream 對象實例化為 vs,並開始 fps 計數(36-38 行)。2 秒鐘的 sleep 讓我們的攝像頭有足夠的預熱時間。
現在我們已經準備好在來自攝像頭的視頻幀中進行循環,並將它們發送到我們的 CNN 目標檢測器中:
在第 44 行,我們抓取 1 幀,然後重新調整它的大小並保留用於顯示的長寬比(第 45 行)。
我們從中提取高度和寬度,稍後會用到(第 48 行)。
第 48 行和 49 行從這一幀中生成 blob。要了解更多 blob,以及如何使用 cv2.dnn.blobFromImage 函數構建 blob,請在以前的博文中查看所有細節(https://www.pyimagesearch.com/2017/11/06/deep-learning-opencvs-blobfromimage-works/)。
下一步,我們將 blob 發送到神經網路中來檢測目標(54-55 行)。
循環檢測:
從第 58 行開始檢測循環。
對於每一次檢測,我們都提取 confidence(#61 行),然後將它與置信度閾值進行比較(#65 行)。當 confidence 超過最小值(默認的 0.5 可以通過命令行參數進行修改),我們可以認為這次檢測是一次積極有效的檢測,可以繼續進行處理。
首先,我們從 detections 中提取類別標籤索引(#68)。
然後,回到 Ezekiel 的第一個問題,我們可以忽略 INGNORE 集合中的類別(#72—73)。如果這個類別是要被忽略的,我們只需返回到頂部的檢測循環(不會顯示這個類別的標籤或邊界框)。這符合我們的「quick hack」解決方案。
否則,我們檢測到的目標就在白名單中,我們需要在該幀中顯示對應的類別標籤和矩形框:
在這段代碼中,我們提取出了邊界框的坐標(#77-78),然後畫出這幀的標籤和矩形框(#81-87)。
每個類別的標籤和矩形框都是同樣的顏色,也就是說,同一類別的對象都會具有相同的顏色(即視頻中所有的「boats」都具有相同顏色的標籤和邊界框)。
最後,仍然在這個 while 循環中,我們將結果顯示在屏幕上:
我們顯示出這一幀,並且捕捉按鍵(#90-91)。
如果 q 鍵被按下,則我們通過跳出循環來結束程序(#94-95)。
否則,我們會繼續更新 fps 計數(#98),並且繼續抓取並分析視頻幀。
在後面幾行中,當循環中斷後,我們會顯示時間+fps(幀每秒)指標然後清空。
運行你的深度學習目標檢測器
為了運行今天的腳本,你需要滾動到下面的「下載」部分來抓取文件。
當你提取到文件之後,打開一個終端,切換到已下載代碼+模型的路徑。並在這裡執行以下命令:
圖 6: 使用同一個模型的實時深度學習目標檢測演示,在右邊的視頻中我在程序中忽略了某些目標類別。
在上邊的動圖中,你在左邊可以看到「person」類別被檢測到了。這是由於 IGNORE 是空的。在右邊的動圖中,你可以看到我沒有被檢測到,這是由於我把「person」增加到了 IGNORE 集合了。
儘管我們的深度學習目標檢測器仍然從技術上檢測到了「person」類別,但是我們的後期處理代碼將它過濾出來了。
也許你在運行這個深度學習目標檢測器的時候會遇到錯誤?
排除故障的第一步是檢查你是否連接了攝像頭。如果這個是正常的,也許你會在你的終端中看到以下錯誤信息:
如果你看到這個信息,那說明你沒有向程序傳遞「命令行參數」。如果他們不熟悉 Python、argparse 以及命令行參數的話(https://www.pyimagesearch.com/2018/03/12/python-argparse-command-line-arguments/)。
這是 PyImageSearch 讀者最常遇見的問題。查看一下這個鏈接,看看你是否存在這個問題。帶有注釋的完整視頻在這裡:https://youtu.be/5cwFBUQb6_w
如何向深度學習目標檢測器添加或者刪除類別?
圖7:深度學習目標檢測的微調過程和遷移學習。
正如我在這份指南中前期所提到的,你不能在 CLASS 列表中簡單地增加或者刪除類別,基礎的網路並沒有改變。
你所能做的,最好就是修改一個能夠列出所有類別標籤的文本文件。
此外,如果你想顯式地在神經網路中增加或者刪除類別,你需要做的工作有:
1. 從零開始訓練
2. 進行微調
從零開始訓練通常會比較耗時間,是一個代價昂貴的操作,所以我們儘可能避免,但是在一些情況下是無法避免的。另一個選擇就是進行微調。微調是一種遷移學習的形式,它是這樣的過程:
1. 刪除負責分類/打標籤的全連接層
2. 並用全新的、隨機初始化的全連接層替代
我們也可以選擇性地修改網路中的其它層(包括在訓練過程中凍結一些層的權重,以及解凍它們)。
準確來說,如何訓練你自己的定製的深度學習目標檢測器(包括微調和從零開始訓練)是比較高級的話題,並不屬於本文的討論範圍,但是閱讀下面的部分可以有助於你開始這項工作。
我可以在哪裡學到更多關於深度學習目標檢測的內容?
圖 8: 汽車前後視角的實時深度學習目標檢測
正如我們在這篇博文中討論過的,目標檢測並不是像圖像分類一樣簡單,其細節和複雜度超出了本文的範圍(我已經啰嗦了好多遍了)。
本教程肯定不是我在深度學習目標檢測方方面的最後一篇文章(毫無疑問,我會在未來寫更多關於深度學習目標檢測的文章),但是如果你對學習以下內容感興趣:
1. 為目標檢測準備你的數據集。
2. 在你的數據集上精調並訓練你自己的定製化目標檢測器,包括 Faster R-CNN 和 SSD。
3. 了解我的最好的實踐做法、技術和過程,並使用它們來訓練自己的深度學習目標檢測器。
... 然後,你可能會想看一下我的新書(https://www.pyimagesearch.com/deep-learning-computer-vision-python-book/)。在《Deep Learning for Computer Vision with Python》一書中,我會一步一步地指導你構建自己的深度學習目標檢測器。
總結
這篇博客簡單介紹了深度學習目標檢測所涉及的一些難點。我們以概述圖像分類和目標檢測之間的本質區別作為開始,包括如何將一個圖像分類的神經網路用於目標檢測。
然後我們概述了深度學習目標檢測器的核心組成:
1. 檢測框架
2. 基本模型
基本模型通常是一個預訓練的(分類)網路,為了學習到一系列具有辨識能力的濾波器,一般是在大型圖像數據集(例如 ImageNet)上進行訓練的。
我們也可以從零開始訓練基本網路,但是,對於目標檢測器而言,為了達到較合理的準確率。這通常需要更長的訓練時間。
在絕大多數情況下,你應該以一個預訓練的基本模型作為開始,而不是嘗試著從零開始訓練。
當我們對深度學習目標檢測器有了充分的理解之後,我們就可以在 OpenCV 中實現能夠實時運行的目標檢測器。
我還概述了如何過濾或者忽略那些不感興趣的類別標籤。
最後,我們了解到:實際地向深度學習目標檢測器增加一個類別標籤,或者從深度學習目標檢測器中刪除一個類別標籤並不是像從硬編碼的標籤列表張增加或者刪除標籤一樣簡單。
神經網路本身並不在乎你是否修改了類別標籤,相反,你需要:
1. 通過刪除全連接目標預測層並進行調整來修改網路結構
2. 或者從零開始訓練目標檢測網路框架
對於更多的深度學習目標檢測項目,你需要從一個基於目標檢測任務(例如 COCO)的預訓練深度學習目標檢測器開始。然後基於預訓練模型進行微調,以得到你自己的檢測器。
訓練一個端到端的定製深度學習目標檢測器並不屬於本文的範疇,所以,如果你對探索如何訓練自己的目標檢測器感興趣,請參考我的書籍《deep learning for computer vision with python》。
在這本書中,我描述了一些深度學習目標檢測的例子,包括為以下任務訓練你自己的深度學習目標檢測器:
1. 檢測交通標誌,例如 Stop 標誌,人行橫道標誌等等。
2. 汽車的前後視角
※剛剛,Uber發生全球首例自動駕駛致死事件
※阿里巴巴「鹿班」演算法技術負責人星瞳:用可控視覺生成引擎完成智能設計
TAG:機器之心 |