ssd源碼解讀(caffe)


ssd是經典的one-stage目標檢測算法,作者是基於caffe來實現的,這需要加入新的層來完成功能,caffe自定義層可以使用pythonc++faster rcnn既使用了c++定義如smoothl1layer,又使用了python定義,如proposaltargetlayerroidatalayer等。而ssd完全使用c++來定義層,包括:

1annotateddatalayer數據讀取層,用於讀取圖像和標簽數據,並且支持數據增強

2permutelayer用於改變blob的讀取順序

3priorboxlayer用於生成defalutbox

4multiboxlosslayer,邊框回歸集成了l2losssmoothl1,於分類集成了softmaxlogistic,並且支持困難樣本挖掘、defaultbox匹配等功能。

name: "mbox_loss"

type: "MultiBoxLoss"

bottom: "mbox_loc"

bottom: "mbox_conf"

bottom: "mbox_priorbox"

bottom: "label"

top: "mbox_loss"

整個網絡比較繁雜,不過相對於fasterrcnn算簡單一些,我們從loss順藤摸瓜,首先查看label的存儲格式,這需要查看annotateddatalayer層是如何對數據進行讀取的,查看網絡定義文件發現數據讀取層的輸入要求是lmdbleveldb格式,那么問題來了,如何將voc格式的數據制作成lmdb呢?原生caffe好像只支持分類的數據制作,github上說通過./data/VOC0712/create_list.sh./data/VOC0712/create_data.sh來制作數據查看create_data.sh文件,里面又調用了$root_dir/scripts/create_annoset.py,繼續查看create_annoset.py 發現最終調用的/build/tools/convert_annoset進而查看tools/convert_annoset.cpp,里面實現了將分散的文件轉換為lmdb格式,但是依然還沒找到哪里解析了voc格式標注的xml文件,convert_annoset.cpp調用了ReadRichImageToAnnotatedDatum函數,終於在utils/io.cpp中找到了讀取xml標注文件的實現。數據層的輸出有datalabeldata的格式是n×3×300×300,label的格式是n*1×nofboxes*8。每個物體包含了8個信息[item_id, group_label, instance_id, xmin, ymin, xmax, ymax, diff]

,含義是batchsize個圖像中的第item_id幅圖像中的第group_label個類別下的第instance_id個目標的坐標為[xmin, ymin, xmax, ymax]

loss層的label輸入格式清楚了,接下來解析mbox_priorbox的格式,mbox_priorbox是由多個priorboxconcat起來的,ssd3006featuremap上生成了priorbox,例如在conv4_3featuremap上的priorbox數量為w×h×numprior,其存儲方式為chw,維度為2×1*(w×h×numprior*4),可以看出是3維的,而不是nchw,這是因為一個batch的圖像大小是相同的,為它們生成的priorbox也是完全相同的,所以不需要batch這個維度,另外注意channel維度是2,是存入了對應位置的方差varirance。多層的priorbox數據concat起來時,axis設為2,也就是在w的維度將bloob接起來形成一個如圖所示長條。

 

接着解析mbox_loc的維度,以大小為38×38conv4_3fmap為例,3*3的卷積在fmap上卷積得到bsize×16×38×38map,注意通道數量是16,38*38的空間位置上,每個空間位置對應16個數,而這16個數就是對4priorbox也就是16個點的回歸,但是麻煩的是priorbox是被拉成了1維向量(不考慮variance的話),暫時不考慮bsize的話,那如何將16×38×38blob拉成與priorbox對應的1維向量呢?直接flatten的話將按照whc從低到高的順序flatten,這是不行的,需要按照cwh的順序flatten才能與priorbox的存儲方式對應得上,於是ssd定義了permutelayerblobnchw順序改為nhwc,然后進行flatten即可。這里需要注意flatten的用法,文件指定從1axis開始flatten,也就是從permute過后hwcflatten1維,整體flatten過后的維度為n×(h*w*c)conv4也就是bsize×23104,四維blob變成了2維,如果對flatten有疑惑可直接查看源碼。各層的二維blob再繼續concat,第1維是bsize,那么肯定在第2維上進行concat,所以mbox_locmbox_conf層拼接的axis都設為1。所以mbox_locblob的維度最終為bsize×27130

mbox_conf層的維度與mbox_loc層維度的推算類似,3*3的卷積在fmap上卷積得到bsize×84×38×38map,其中84=4×21,4是每個位置4個不同的priorbox21代表了卷積網絡預測出該priorbox屬於21類的概率。后續計算方式參考mbox_loc即可

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM