監控在安保和巡查中發揮著重要作用,但也是一項非常乏味的任務,深度學習的出現在一定程度上將人類從這一任務中解放出來。本文介紹瞭如何使用基於深度學習的目標檢測去搭建一個簡單但有效的監控系統,還比較了使用 GPU 多處理進行推斷的不同目標檢測模型在行人檢測方面的效能。
監控是安保和巡查一個不可或缺的組成部分。在大多數情況下,這項工作需要長時間去查詢一些你不期望發生的事。我們做的這件事很重要,但也是一項非常乏味的任務。
如果有什麼東西可以代替我們做「觀察和等待」的工作,生活不就簡單多了嗎?嗯,你很幸運。憑藉過去幾年的技術進步,我們可以編寫一些指令碼來自動執行上述任務—而且也很容易實現。但在我們深入探討之前,讓我們自問:機器的表現和人類一樣好嗎?
任何熟悉深度學習的人都知道影像分類器的準確率已經超出了人類水平。
傳統計算機視覺(CV)和深度學習相比於人類,在 ImageNet 資料集上隨時間變化的錯誤率。(圖源:https://www.dsiac.org/resources/journals/dsiac/winter-2017-volume-4-number-1/real-time-situ-intelligent-video-analytics)
與人類相比,機器可以以相同(或更好)的標準保持對物體的監控。因此使用技術去進行監控要高效得多。
監控是一項重複且乏味的任務,可能會導致人類表現的下降。但使用技術進行監控,我們就可以在出現問題時專注於採取行動。
為了去調查一大片區域,你會需要大量人力。而固定攝像機的視野範圍是有限的。透過使用移動監控機器人(比如微型無人機)可以減輕這些問題。
此外,同樣的技術還有除了安保以外的各種應用,比如嬰兒監視器或自動化產品交付。
好極了!但是我們如何實現自動化呢?
在設計複雜的理論之前,讓我們考慮一下監控的正常運作方式。如果看一段影片時發現了異常,我們就會採取行動。所以從本質上說,我們的技術應該細讀影片的每一幀,希望可以發現一些異常的東西。這個過程是不是很耳熟?
正如你可能已經猜到的那樣,這就是使用帶有定位的目標檢測的本質。它和分類略有不同,就是我們需要知道目標的確切位置。此外,我們可能在單張影像中有多個目標。
為了找到目標的確切位置,我們的演算法應該檢查影像的每一部分以找到一個類的存在。這比聽起來更難。但自 2014 年以來,深度學習領域不斷更新的研究已經引入了可以實時檢測目標的複雜神經網路。
看,僅在 2 年時間內,效能就增加了那麼多!
有幾種在內部使用不同方法的深度學習架構來實現相同的任務。最流行的變種是 Faster RCNN、YOLO 和 SSD 網路。
速度和準確率的權衡。更高的 mAP 和 更少的 GPU 執行時間是最優的。
每個模型都依賴於一個基礎分類器,該分類器對最終的準確率和模型大小有很大影響。此外,目標檢測器的選擇會極大影響計算複雜度和最終準確率。
選擇目標檢測演算法的過程通常是速度、準確率和模型大小之間的權衡。
在本博文中,我們將學習如何使用目標檢測搭建一個簡單但有效的監控系統。讓我們先討論一下由於監控任務的性質而受限制的約束。
深度學習在監控領域的限制因素
我們經常想持續關注一大片區域的情況。在實現自動化監控前,我們需要考慮一些因素。
1. 影片輸入
一般來說,為了監控一大片區域,我們需要多個攝像機。此外,這些攝像機需要在某個地方儲存資料;要麼在本地,要麼在某個遠端儲存。
典型的監控攝像機。(圖片來自 Unsplash 的 Scott Webb)
較高質量的影片將比較低質量的影片佔用更多的記憶體。此外,RGB 輸入流比 BW 輸入流大 3 倍。由於我們只能儲存有限數量的輸入流,因此通常會降低質量以最大化儲存。
因此,可擴充套件的監控系統應該能夠解析低質量的影像。因此,我們的深度學習演算法也必須在低質量的影像上進行訓練。
2. 處理能力
現在已經解決了輸入約束,我們可以去回答一個更大的問題。我們在哪裡處理從攝像機中獲得的資料?有兩種方法可以做到這一點。
在中央伺服器上處理:
來自攝像機的影片流在遠端伺服器或叢集上逐幀處理。這個方法非常穩健,同時讓我們得以利用高準確率的複雜模型的優勢。顯而易見的問題是延遲;所以你需要一個快速的網路連線來解決延遲。此外,如果你沒有使用商用 API,那麼伺服器設定和維護的成本會很高。
記憶體消耗與 GPU 推斷時間(毫秒)。大多數高效能模型都會消耗大量記憶體。(圖源:https://arxiv.org/pdf/1611.10012.pdf)
邊緣處理
透過連線小型微控制器,我們可以在攝像機上進行實時推斷。這就沒有傳輸延遲,同時相比之前的方法,可以更快地報告異常。此外,對於移動機器人來說,這是一個很好的補充,因此它們不需要再受到可用的 WiFi / Bluetooth 範圍的限制。(比如微型無人機。)
不同目標檢測器的 FPS 效能。(圖源:https://medium.com/@jonathan_hui/object-detection-speed-and-accuracy-comparison-faster-r-cnn-r-fcn-ssd-and-yolo-5425656ae359)
缺點是,微控制器沒有 GPU 那麼強大,因此你可能被迫使用較低準確率的模型。使用板載的 GPU 可以避免這個問題,但代價高昂。一個有趣的解決方案是使用像 TensorRT 這樣的軟體,此類軟體可以最佳化程式的推理過程。
訓練監控系統
在本節中,我們將使用目標檢測來檢測一下如何識別行人。我們將使用 TensorFlow 目標檢測 API 來構建我們的模組。我們會簡要探討如何設定 API,並訓練其完成監控任務。詳細解釋見另一篇博文(https://medium.freecodecamp.org/how-to-play-quidditch-using-the-tensorflow-object-detection-api-b0742b99065d)。
整個過程可以被歸納為 3 個階段:
1. 資料準備
2. 訓練模型
3. 推斷
涉及訓練目標檢測模型的工作流程。
如果你想看到那些能激勵你進行更多嘗試的結果,請向下滾動到第 3 階段!
階段 1:資料準備
步驟 1:獲取資料集
過去拍攝的監控錄影可能是你可以獲得的最準確的資料集。但是,大部分情況下,通常很難獲得這樣的監控錄影。在這種情況下,我們可以訓練自己的目標檢測器,以便從正常影像中識別我們的目標。
從我們的資料集中提取帶註釋的影像。
如前所述,攝像機中的影像質量可能較低。因此你必須訓練你的模型適應這樣的工作條件。一種巧妙的方法是使用資料擴充,在此有詳細解釋(https://medium.com/nanonets/how-to-use-deep-learning-when-you-have-limited-data-part-2-data-augmentation-c26971dc8ced)。本質上說,我們必須新增一些噪音來降低資料集中圖片的質量。我們還可以嘗試模糊和侵蝕效果。
為了目標檢測任務,我們將使用 TownCentre 資料集。我們將使用影片的前 3600 幀進行訓練和驗證,剩下的 900 幀用來測試。你可以使用我 github repo 中的指令碼來提取資料集。GitHub repo:https://github.com/thatbrguy/Pedestrian-Detector。
步驟 2:註釋資料集
你可以使用像 LabelImg 這樣的工具來進行註釋。這是一項乏味的任務,但同樣重要。註釋儲存為 XML 檔案。
幸運的是,TownCentre 資料集的所有者提供了 csv 格式的註釋。我寫了一個快速指令碼去將註釋轉化為需要的 XML 格式,同樣可以在上述 github repo 中找到。
步驟 3:克隆儲存庫
克隆儲存庫(https://github.com/thatbrguy/Pedestrian-Detector)。執行以下命令去安裝需求包,編譯一些 Protobuf 庫並設定路徑變數。
pip install -r requirements.txt
sudo apt-get install protobuf-compiler
protoc object_detection/protos/*.proto --python_out=.
export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim
步驟 4:準備支援的輸入
我們需要給我們的目標分配一個 ID。我們在名為 label_map.pbtxt 的檔案中定義 ID,如下所示:
item {
id: 1
name: ‘target’
}
接著,你必須建立一個包含 XML 和圖片檔名的文字檔案。例如,如果你的資料集中有影像 img1.jpg、img2.jpg 以及 img1.xml、img2.xml,你的 trainval.txt 應如下所示:
img1
img2
將你的資料集分成兩個資料夾,即 images 和 annotations。將 label_map.pbtxt 和 trainval.txt 放到 annotations 資料夾中。在 annotations 資料夾中建立一個名為 xmls 的資料夾,並將所有 XML 檔案放入其中。你的目錄層次結構應如下所示:
-base_directory
|-images
|-annotations
||-xmls
||-label_map.pbtxt
||-trainval.txt
步驟 5:建立 TF Records
API 接受 TFRecords 檔案格式的輸入。使用我的 repo 中提供的 create_tf_records.py 檔案去將你的資料集轉換為 TFRecords。你應該在你的基本目錄執行以下命令:
python create_tf_record.py \
--data_dir=`pwd` \
--output_dir=`pwd`
在程式執行完後,你會發現兩個檔案:train.record 和 val.record。
階段 2:訓練模型
步驟 1:模型選擇
如前所述,這是速度和準確率之間的權衡。同時,從頭開始建立並訓練一個目標檢測器是十分耗時的。因此,TensorFlow 目標檢測 API 提供了一堆預訓練模型,你可以在你的任務中對它們進行微調。這個過程被稱為遷移學習,可以大幅加快你的訓練過程。
一堆在 MS COCO 資料集上的預訓練模型
下載其中一個模型,並將內容解壓到你的基礎目錄下。你將得到模型的 checkpoint、一個凍結推理圖 和一個 pipeline.config 檔案。
步驟 2:定義訓練任務
你必須在 pipeline.config 檔案中定義「訓練任務」。將檔案放在基礎目錄下。真正重要的是檔案的最後幾行—你只需要將突出高亮的值分別設定為自己的檔案位置。
gradient_clipping_by_norm: 10.0
fine_tune_checkpoint: "model.ckpt"
from_detection_checkpoint: true
num_steps: 200000
}
train_input_reader {
label_map_path: "annotations/label_map.pbtxt"
tf_record_input_reader {
input_path: "train.record"
}
}
eval_config {
num_examples: 8000
max_evals: 10
use_moving_averages: false
}
eval_input_reader {
label_map_path: "annotations/label_map.pbtxt"
shuffle: false
num_epochs: 1
num_readers: 1
tf_record_input_reader {
input_path: "val.record"
}
}
步驟 3:開始訓練
執行以下命令以開始訓練。建議使用 GPU 足夠大的機器(假設你安裝了 TensorFlow 的 GPU 版本)以加速訓練過程。
python object_detection/train.py \
--logtostderr \
--pipeline_config_path=pipeline.config \
--train_dir=train
階段 3:推斷
步驟 1:匯出訓練模型
在使用模型之前,你需要將訓練好的 checkpoint 檔案匯出到一個凍結的推理圖中。其實做比說起來容易——只需執行以下程式碼(用 checkpoint 數字替換「xxxxx」):
python object_detection/export_inference_graph.py \
--input_type=image_tensor \
--pipeline_config_path=pipeline.config \
--trained_checkpoint_prefix=train/model.ckpt-xxxxx \
--output_directory=output
你將得到一個名為 frozen_inference_graph.pb 的檔案,以及一堆 checkpoint 檔案。
步驟 2:在影片流上使用它
我們需要從影片源中提取單幀。可以透過使用 OpenCV 的 VideoCapture 方法完成,如下所示:
cap = cv2.VideoCapture()
flag = True
while(flag):
flag, frame = cap.read()
## -- Object Detection Code --
階段 1 中使用的資料提取程式碼會自動建立一個包含測試集影像的資料夾「test_images」。我們可以透過執行以下命令在測試集上執行我們的模型:
python object_detection/inference.py \
--input_dir={PATH} \
--output_dir={PATH} \
--label_map={PATH} \
--frozen_graph={PATH} \
--num_output_classes=1 \
--n_jobs=1 \
--delay=0
實驗
如前所述,在選擇目標檢測模型時,是在速度和準確度之間進行權衡。我進行了一些實驗,測量了使用三種不同模型檢測到的人的 FPS 和計數準確率。此外,實驗是在不同的資源約束(GPU 並行約束)上執行的。這些實驗的結果可以在選擇目標檢測模型時,為你提供一些有價值的見解。
設定
我們的實驗選擇了以下模型。這些可在 TensorFlow 目標檢測 API 的 Model Zoo 中找到。
帶有 ResNet 50 的 Faster RCNN
帶有 MobileNet v1 的 SSD
帶有 InceptionNet v2 的 SSD
所有模型都在 Google Colab 上訓練 10 k 步(或直到它們的損失不再下降)。推理使用了 AWS p2.8xlarge 例項。透過比較模型檢測到的人數和真實結果來測量計數準確率。在以下約束條件下測試推理速度的每秒幀數(FPS):
1 塊 GPU
2 塊並行 GPU
4 塊並行 GPU
8 塊並行 GPU
結果
下圖是在我們的測試集上使用 FasterRCNN 生成的輸出的部分結果。更多結果將在下文的影片中呈現。
訓練時間
下圖展示了訓練每個模型 10 k 步(以小時為單位)所需的時間。這不包括超引數搜尋所需的時間。
當你的應用程式與用於遷移學習的預訓練模型大相徑庭時,你可能需要大幅調整超引數。但是,當你的應用程式與之類似時,你不需要進行大量搜尋。儘管如此,你可能仍需要嘗試不同的訓練引數,例如學習率和最佳化器的選擇。
速度(每秒幀數)
這是我們實驗中最有趣的部分。如前所述,我們測量了三種模型在五種不同資源約束下的 FPS 效能。結果如下所示:
當我們使用單塊 GPU 時,SSD 的速度極快,能輕鬆超越 Faster RCNN 的速度。但是,當我們增加(並行)GPU 的數量時,Faster RCNN 會迅速趕上 SSD 的速度。毋庸置疑,在一個低 GPU 環境下,採用帶有 MobileNet 的 SSD 比使用帶有 InceptionNet 的 SSD 要快得多。
上圖中的一個顯著特徵是,當我們為帶有 MobileNet 的 SSD 增加 GPU 數量時,FPS 略有下降。這個明顯的悖論實際上有一個簡單的解釋。事實證明,我們處理影像的設定比影像讀取函式提供的速度快!
影片處理系統的速度不能快於影像輸入系統的速度。
為了證明我的假設,我先啟動影像讀取函式。下圖顯示了新增延遲時帶有 MobileNet 的 SSD 的 FPS 提升情況。早期圖表中,FPS 的輕微下降是由於多塊 GPU 請求輸入所涉及的開銷。
毋庸置疑,我們發現如果引入延遲,FPS 會急劇增加。最重要的是,我們需要一個最佳化的影像傳輸管道,以防止速度瓶頸的出現。但想將其應用在監控上還有一個瓶頸。監控攝像機的 FPS 設定了我們系統 FPS 的上限。
計算準確率
我們將計數準確率定義為我們的目標檢測系統正確識別的人的百分比。我覺得該定義用在監控方面更合適。以下是我們每個模型的表現:
毋庸置疑,Faster RCNN 是最準確的模型。同樣令人驚訝的是,MobileNet 的效能優於 InceptionNet。
速度與準確率之間的權衡在實驗中顯而易見。但是,如果有足夠的資源,我們就可以以良好的 FPS 率使用高精度的模型。我們發現,使用 ResNet-50 的 Faster RCNN 準確率最高,並且當並行部署在 4+ 塊 GPU 上時,具有非常高的 FPS 率。
這有一大堆步驟!
這裡的步驟非常多。此外,為此模型設定一個實時工作的雲例項將是繁重且昂貴的。
一個更好的解決方案是使用已部署在伺服器上的 API 服務,這樣你就只需考慮產品的開發了。這就是 Nanonets 的用武之地。他們將 API 部署在帶有 GPU 的高質量硬體上,這樣你就可以在沒有任何麻煩的情況下獲得意想不到的效能!
我將現有的 XML 註釋轉換為 JSON 格式並將其提供給 Nanonets API。事實上,如果你不想手動註釋資料集,可以請求它們為你新增註釋。以下是 Nanonets 負責繁重的工作時的簡化工作流程。
使用 Nanonets 簡化工作流程
早些時候,我曾提到像微型無人機這樣的移動監控裝置如何大大提高效率。我們可以使用類似 Raspberry Pi 的微控制器輕鬆地建造這樣的無人機,同時我們可以使用 API 呼叫來執行推斷。
開始使用 Nanonets API 進行目標檢測是非常簡單的,但若想要一篇講解清楚的指南,你可以檢視這篇博文(https://medium.com/nanonets/how-to-easily-detect-objects-with-deep-learning-on-raspberrypi-225f29635c74)。
使用 Nanonets 的結果
Nanonets 花了大約 2 個小時才完成訓練。這包括超引數搜尋所需的時間。就所費的訓練時間而言,Nanonets 是當仁不讓的贏家。Nanonets 在計數準確率方面也擊敗了 FasterRCNN。
FasterRCNN Count Accuracy = 88.77%
Nanonets Count Accuracy = 89.66%
以下是在我們的測試資料集上,所有 4 個模型的效能。很明顯,兩種 SSD 模型都有點不穩定並且準確率較低。此外,儘管 FasterRCNN 和 Nanonets 具有相當的精度,但後者具有更穩定的邊界框。
自動化監控可靠嗎?
深度學習是一種令人驚歎的工具,可以輕鬆提供典型的結果。但是,我們能在多大程度上信任我們的監控系統並放任其自動執行?在一些情況下,自動化是令人懷疑的。
更新:鑑於 GDPR 和下述原因,我們有必要思考監控自動化的合法性和道德問題。此博文僅用於教育目的,文中使用了一個公開的資料集。你有責任確保你的自動化系統符合你所在地區的法律。
1. 不太可靠的結論
我們不知道深度學習演算法如何得出結論。即使資料輸入過程無可挑剔,也可能存在大量的虛假資料。例如,英國警察使用的 AI 鑑黃過濾器不斷將沙丘影像誤判為裸體影像而將其刪除。有引導的反向傳播等技術可以在一定程度上解釋決策,但我們還有很長的路要走。
2. 對抗性攻擊
深度學習系統非常脆弱。對抗性攻擊類似於影像分類器的光學錯覺。但可怕的是,一個計算出的不明顯的擾動會迫使深度學習模型進行錯誤分類。依據相同的原理,研究人員能夠透過使用「對抗眼鏡」(adversarial glasses)來避免基於深度學習的監控系統出現錯誤。
3. 假正類
另一個問題是,如果出現假正類,我們該怎麼做。問題的嚴重程度取決於應用程式本身。例如,邊境巡邏系統的假正類可能比花園監控系統更重要。應該有一些人為干預以避免意外。
4. 相似的面孔
可悲的是,你的外觀並不像你的指紋那麼獨一無二。兩個人(或更多人)看起來非常相似是可能的。同卵雙胞胎是最好的例子之一。據報導,蘋果的 Face ID 無法區分兩個無親屬關係的中國員工。這會使監控和識別人變得更難。
5. 資料集缺乏多樣性
你提供多好的資料,深度學習演算法就有多好。最受歡迎的人臉資料集只有白人樣本。對於孩子來說,人類存在各種膚色似乎是顯而易見的,但深度學習演算法卻有點傻。谷歌就曾因為將一個黑人錯誤地歸類為大猩猩而陷入麻煩。
原文連結:https://medium.com/nanonets/how-to-automate-surveillance-easily-with-deep-learning-4eb4fa0cd68d