目標檢測:Mobilenet-SSD實現步驟
寫的比較好,我就儲存一下:http://blog.csdn.net/Jesse_Mx/article/details/78680055
mobilenet 也算是提出有一段時間了,網上也不乏各種實現版本,其中,谷歌已經開源了Tensorflow的全部程式碼,無奈自己幾乎不熟悉Tensorflow,還是比較鍾愛Caffe平臺,因而一直在關心這方面。
單純的Mobilenet分類不是關注重點,如何將其應用到目標檢測網路才是關鍵,目前基本看好的思路就是Mobilenet+SSD,github上已經有至少如下專案涉及到這方面:
接下來的時間,我將會盡可能進行進行分析驗證,目的是尋找並試驗出好的解決方案,並且期待能成功訓練其他資料集。。
Mobilenet的速度是很快的,如果配上Depthwise layer,在TitanX應該能達到150fps,如果能將檢測精度提升到70%以上,將會是一個很好的檢測網路。
實現方案一
幾個月前接觸到了這個project,當時chuanqi大神在Caffe平臺上初步實現了Mobilenet-SSD,本人自然是很驚喜的,接下來就時不時和大神一起探討,在其指導下,我在VOC資料集也能訓練出大約72%的精度。現在這個專案趨於穩定,根據github上的描述,最終精度是72.7%,也很不錯了。下面簡單記錄一下執行和訓練方法。
模型分析
通過分析Mobilenet的模型結構和MobileNet-SSD的模型結構, 可以看出,conv13是骨幹網路的最後一層,作者仿照VGG-SSD的結構,在Mobilenet的conv13後面添加了8個卷積層,然後總共抽取6層用作檢測,貌似沒有使用解析度為38*38的層,可能是位置太靠前了吧。
模型執行
這個專案既然叫MobileNet-SSD,那首先要求能正常執行基礎版本的SSD,這方面的部落格教程這是不少,本人也有幾篇博文涉及,可以參考。
克隆專案:
$ git clone https://github.com/chuanqi305/MobileNet-SSD.git
然後可以在自己的目錄(我是用的是/home目錄)下得到MobileNet-SSD資料夾,其中重要檔案簡介如下:
- template 存放4個網路定義的公用模板,可以由gen.py指令碼修改並生成
- MobileNetSSD_deploy.prototxt 執行網路定義檔案
- solver_train.prototxt 網路訓練超引數定義檔案
- solver_test.prototxt 網路測試超引數定義檔案
- train.sh 網路訓練指令碼
- test.sh 網路測試指令碼
- gen_model.sh 生成自定義網路指令碼(呼叫template資料夾內容)
- gen.py 生成公用模板指令碼(暫不用)
- demo.py 實際檢測指令碼(圖片存於images資料夾)
- merge_bn.py 合併bn層指令碼,用於生成最終的caffemodel
接下來下載已經訓練好的caffemodel放入專案資料夾:Google Drive | 百度雲
最後開啟demo.py指令碼,根據個人情況修改以下路徑:
caffe_root = '/home/yaochuanqi/ssd/caffe/'
net_file= 'MobileNetSSD_deploy.prototxt'
caffe_model='MobileNetSSD_deploy.caffemodel'
test_dir = "images"
然後執行demo.py指令碼,就能看到檢測結果了,效果尚可,隨便貼兩張圖:
模型訓練
我們也可以用自己的資料集來訓練這個MobileNet-SSD模型,訓練步驟簡要記錄如下:
1.建立資料集軟連線
我們需要提前建立好適用於SSD訓練的資料集(VOC格式),比如博主所用的是KITTI資料集,製作方法可在往期博文中找到,最終需要生成訓練驗證集和測試集的lmdb檔案,然後建立軟連線,類似於一個快捷方式,可以簡化命令和節省空間。
$ cd ~/MobileNet-SSD
$ ln ‐s /home/its/data/KITTIdevkit/KITTI/lmdb/KITTI_trainval_lmdb trainval_lmdb
$ ln ‐s /home/its/data/KITTIdevkit/KITTI/lmdb/KITTI_test_lmdb test_lmdb
執行完命令,就能在專案資料夾下看到trainval_lmdb和test_lmdb軟連線。
2.建立labelmap.prototxt檔案
該檔案用於定義訓練樣本的類別,置於專案資料夾下,其內容如下:
item {
name: "none_of_the_above"
label: 0
display_name: "background"
}
item {
name: "Car"
label: 1
display_name: "Car"
}
item {
name: "Pedestrian"
label: 2
display_name: "Pedestrian"
}
item {
name: "Cyclist"
label: 3
display_name: "Cyclist"
}
3.執行gen_model.sh指令碼
由於VOC資料集是21類(加上背景),而這裡只有4類,因此,我們需要重新生成訓練、測試和執行網路檔案,這裡就要用到gen_model.sh指令碼,它會呼叫template資料夾中的模板,按照我們指定的引數,生成所需的文。這個指令碼的用法如下:
usage: ./gen_model.sh CLASSNUM
for voc the classnum is 21
只有一個類別數量的引數,因此我們執行命令如下:
./gen_model.sh 4
執行之後,得到examples資料夾,裡面的3個prototxt就是從模板生成的正式網路定義,根據作者設定,其中的deploy檔案是已經合併過bn層的,需要後面配套使用。
4.修改訓練和測試超引數
根據實際情況,修改solver_train.prototxt和solver_test.prototxt。
其中test_iter=測試集圖片數量/batchsize;初始學習率不宜太高,否則基礎權重破壞比較嚴重;優化演算法是RMSProp,可能對收斂有好處,不要改成SGD,也是為了保護權重。
5.下載預訓練模型
下載地址:Google Drive | 百度雲,放在專案資料夾下,這裡的預訓練模型是作者從Tensorflow那邊轉化過來的,然後經過了VOC資料集的初步除錯。
6.開始訓練
修改並執行train.sh指令碼,中途可以不斷調節引數。訓練結束後,執行test.sh指令碼,測試網路的精度值。
7.合併bn層
為了提高模型執行速度,作者在這裡將bn層合併到了卷積層中,相當於bn的計算時間就被節省了,對檢測速度可能有小幅度的幫助,開啟merge_bn.py檔案,然後注意修改其中的檔案路徑:
caffe_root = '/home/yaochuanqi/ssd/caffe/'
train_proto = 'MobileNetSSD_train.prototxt'
train_model = 'MobileNetSSD_train.caffemodel' # should be your snapshot caffemodel, e.g. mobilnetnet_iter_72000.caffemodel
deploy_proto = 'MobileNetSSD_deploy.prototxt'
save_model = 'MobileNetSSD_deploy.caffemodel'
然後執行該指令碼,就可以得到最終的檢測模型,那這個模型由於合併了bn層,引數格式已經變化,就不能再用於訓練了。如果想繼續訓練,應該用合併前的。對於得到的最終模型,可用demo.py指令碼檢視實際檢測效果,也可以部署在其他地方。
存在的問題
本人使用擴充的KITTI資料集訓練Mobilenet-SSD,折騰了一週,精度才只有52%左右,而且訓練速度比VGG的慢一些。我感覺不應該這麼低,至少也應該有65%吧,暫時沒有找到問題的根源在哪裡,如果有同學也拿這個訓練且效果很好,請告知,不勝感激!
更新:考慮到Mobilenet特徵提取能力有限,最近試驗將解析度提升至416*416(速度降低很少),然後使用僅含4類目標(通過指令碼提取)的COCO預訓練模型,初始學習率為0.001,根據損失值和精度調整後續學習率,迭代50000次後,目前精度提升到62.8%。
Mobilenet使用Depthwise Layer
理論上Mobilenet的執行速度應該是VGGNet的數倍,但實際執行下來並非如此,前一章中,即使是合併bn層後的MobileNet-SSD也只比VGG-SSD快那麼一點點,主要的原因是Caffe中暫時沒有實現depthwise convolution,目前都是用的group。這裡group相當於一個for迴圈,需要依次計算,如果能使用深度卷積,那就可以一次性計算完,節省不少時間。
經過大量實驗,終於找到能讓mobilenet加速的方法,專案地址:DepthwiseConvolution, 十分感謝該專案作者。
用上了depthwise convolution layer,對於mobilenet的提速十分明顯,可以說是立竿見影。下面簡單介紹使用方法.
新增新的深度卷積層
首先克隆專案:
$ git clone https://github.com/yonghenglh6/DepthwiseConvolution.git
注意到專案中的caffe資料夾,將其中的depthwise_conv_layer.hpp,depthwise_conv_layer.cpp和depthwise_conv_layer.cu這三個檔案放到SSD(即caffe)的相應位置中,這裡的操作是從基礎卷積類中派生了深度卷積這個類,此處並不需要對caffe.proto檔案進行修改。稍後,需要重新編譯Caffe,這樣才能識別新增的depthwise convolution layer。
修改deploy檔案
接下來我們需要修改MobileNetSSD_deploy.prototxt,將其中所有名為convXX/dw(XX代指數字)的type從”Convolution”替換成”DepthwiseConvolution”,總共需要替換13處,從conv1/dw到conv13/dw,然後把“engine: CAFFE”都註釋掉,這個新的網路檔案可以另存為MobileNetSSD_deploy_depth.prototxt。在執行網路的時候,caffemodel模型不用動,只需要指定新的prototxt檔案和含有depthwise convolution layer的Caffe即可。
效果驗證
為了驗證效果,我們使用demo.py指令碼來測試網路的平均執行時間,執行模式設定為gpu,在demo.py檔案中新增和time相關的程式碼:
import time
def detect(imgfile):
#
#
net.blobs['data'].data[...] = img
start=time.time() # time begin
out = net.forward()
use_time=time.time()-start # proc time
print("time="+str(use_time)+"s")
#
#
膝上型電腦顯示卡是GTX 850m,對於預設的7張檢測圖片,VGG-SSD,Mobilenet-SSD(group)和Mobilenet-SSD(depth)的平均檢測時間為:
Model | Inference time |
---|---|
VGG-SSD | 107ms |
MobileNet-SSD(group) | 62ms |
MobileNet-SSD(depth) | 17ms |
如果我們使用Caffe自帶的time工具,結果也是差不多的:
$ cd ~/caffe
$ ./build/tools/caffe time -gpu 0 -model examples/mobilenet/XXXX.prototxt
I1219 20:09:24.062338 10324 caffe.cpp:412] Average Forward pass: 109.97 ms. # VGG-SSD
I1219 20:09:47.771399 10343 caffe.cpp:412] Average Forward pass: 57.4238 ms. # Mobilenet-SSD(group)
I1219 20:10:25.145504 10385 caffe.cpp:412] Average Forward pass: 16.39 ms. # Mobilenet-SSD(depth)
可以看到,depthwise convolution layer是有效的,執行時間快了五六倍之多。然後,博主在Jetson TX1上也如法炮製,得到的檢測時間如下:
I1219 22:08:15.236963 2210 caffe.cpp:412] Average Forward pass: 57.3939 ms.
意味著TX1上Mobilenet-SSD能達到17幀左右,這離真正的real-time又近了一步