如何正確訓練乙個 SVM HOG 行人檢測器

2022-09-20 04:27:10 字數 2352 閱讀 2707

這幾個月一直在忙著做大**,乙個基於 svm 的新的目標檢測演算法。為了做效能對比,我必須訓練乙個經典的 dalal05 提出的行人檢測器,我原以為這個任務很簡單,但是我錯了。

為了訓練出乙個效能達標的行人檢測器,我花了半個月的時間,中間遇到各種 bug 我就不提了,下面只說正確的步驟。(基於 matlab 環境,但是沒有**,請您自己寫~)

訓練檢測器的正例(positive examples)資料庫最好採用「全圖+標註」的形式,不要是那種切出來的行人小,這有助於後續的 bootstrap 操作(當然,在 daimler 這樣的資料庫上似乎無法做到),初始的負例(negative examples)採用一組不包含行人的場景。其實負例的選擇並不重要,因為在 bootstrap 環節,真正影響效能的,靠近分類超平面的資料點會被自動找到。

大多數靠譜的資料庫都有自帶的標註讀取工具庫,或者遵循某種標註格式(例如 pascal),你也可以使用進一步封裝的標註讀取工具,例如 dollar 的 toolbox。

為了計算 hog 特徵,你可以採用 vlfeat 的 hog 計算函式,這個 hog 是我見過的檢測效能最好的之一(比 opencv 的 hog 好很多,效能提高超過 5%)。

訓練必須進行兩輪:初始訓練,以及 bootstrap 訓練。下面的所說的「切圖」操作,就是從某個位置切乙個 128 * 64 的子的意思,當然,你也可以採用其他的切圖尺寸。下面,談乙個很重要的問題,就是標註(ground truth)尺寸的歸一化,以及標註的外邊距(padding)對訓練結果的影響。

由於資料庫中的行人標註,並不是依照某種固定的長寬比,而 dalal 檢測器的輸出是固定長寬比的,所以,在切圖之前,必須將標註框(bounding box)的尺寸調整到統一比例。你也許會試圖不調整標註框,而是按照原始標註框切出,然後再將縮放到 128 * 64,但是這樣是不對的!檢測結果會打折扣。

此外,dalal **裡還指出,如果將行人周圍的一圈背景也包含到訓練子裡,那麼檢測器效果又會提公升幾個百分點,並且**指出上下左右個加 16 畫素的外邊距(padding)效果最好,我做了一下實驗,確實如此。

計算不包含 padding 時的行人長寬比 r,即(128 - 32):(64 - 32)

經過上述步驟,所有標註框的比例都一致了,並且包含了 padding。

2.1 初始訓練

正例直接從訓練集中切出來,負例隨機從場景中切取,假設我需要 9000 個負例,資料集中有 1000 個場景,那麼平均每幅隨機切九個即可。切負例時沒必要考慮尺度,因為初始負例對整體訓練而言沒有顯著影響,所以隨便切即可,任性。

對切出來的資料提取特徵,然後丟到 liblinear 裡訓練乙個 svm,引數:

-b 1 -c 0.01
其中-b 1是為了讓 svm 具有 bias term(就是 wx+b 中的那個 b),-c 0.01是 dalal **裡的 c 引數(你可以試著調一下,不過我試了一下,的確 0.01 最好)。

於是,我們得到了乙個初始的檢測器。svm 的支撐向量個數大概在 1000 ~ 3000 個不等。

2.2 bootstrap 訓練

初始檢測器是乙個非常非常差的檢測器,所以千萬不要試圖一次訓練後就直接拿來用。我們需要新一輪 bootstrap 訓練。

所謂 bootstrap 訓練,就是用初始檢測器在訓練資料集中進行檢測,蒐集所有的誤檢,將它們作為額外的新的負例加入先前的負例集合,然後再次訓練乙個 svm。所謂誤檢,就是乙個與所有標註位置重合都小於 50% 的檢測結果,這個「重合」可以用area(b1 & b2) / area(b1 | b2)來計算,其中 b1 和 b2 都是矩形框,「與」運算子是矩形框的交疊,「或」運算子是兩個矩形框覆蓋的區域相加。

一般來說,初始檢測器在訓練集上能找到大量誤檢,例如,我在 inria 上訓練時就有 2 萬個誤檢,這是正常的(所以你一定要把電腦的虛擬記憶體調大,否則 matlab 會掛),bootstrap 訓練後,得到的新的 svm 的支撐向量個數將達到 6000 個以上,這從乙個側面說明了,該輪訓練找到的負例重新約束了分類超平面的位置。

前面我提到,訓練時需要將標註框擴大,但是,擴大的標註框,將使檢測結果也被擴大,這時,你需要按照與擴大框的步驟相反的方式,將檢測結果框縮小。而且,為了使邊緣的行人不被漏掉,你可以將輸入的四周都加上 padding 後再進行檢測。

按照這種策略訓練出來的檢測器,在 inria 上達到了 precision:50%,recall:71% 的效能,超過了 opencv 自帶的 hog detector(其實沒有可比性,因為我用了更好的 hog 特徵),如果您有更好的方案,請告訴我,謝謝。

如何正確編譯執行乙個包含CocoPods類庫的專案

pod update過幾秒 也許需要十幾秒,取決於你的網路狀況 之後,終端出現 這裡的意思大概是podfile檔案過期,類庫有公升級,但是podfile沒有更改。pod install只會按照podfile的要求來請求類庫,如果類庫版本號有變化,那麼將獲取失敗。但是 pod update會更新所有的...

如何正確獲得ListView的每乙個item高度

最近android中使用listview 需要動態獲取每個item的高度 來計算listview的高度,計算過程中碰到一些問題,特此分享 前提 這個item的根view必須是linearlayout package com.bxg.news.view import android.view.view...

如何正確的更好的停止乙個執行緒?

前面提到過三種停止執行緒的方式,這三種方式不是被廢棄就是可能造成return汙染,最後雖然建議用拋異常法,但拋異常法依靠的是異常處理機制,下面介紹一種更常用的的停止執行緒的方法 通過在實現runnable介面的類裡面 或者是在繼承thread類的類裡面 定義乙個boolean型別的變數 標記 然後對...