**
前些日子因工程需求,需要將yolov3從基於darknet轉化為基於caffe框架,過程中踩了一些坑,特在此記錄一下。
想要轉化為caffe框架,就要先了解yolov3的網路結構,如下圖。
如果有執行過darknet應該會很熟悉,這是darknet執行成功後列印log資訊,這裡面包含了yolo網路結構的一些資訊。yolov3與v2相比,網路結構中加入了殘差(shortcut層),並且引入了上取樣(upsample層),並為了將取樣後的特徵圖進行融合引入了拼接(route層),最後融合的特徵圖以三個不同的大小13*13*75,26*26*75,52*52*75輸入給yolo層最後得到目標的位置及分類資訊,加上卷積層convolution,這些便是yolov3的網路基本構造。因此只要我們如果在caffe中找到對應的層按照相應的進行構造就能夠使用caffe實現yolov3了。
卷積層不說,yolov3中的shortcut層可以用eltwise替代,route層可以用concat替代,而upsample層和yolo層則需要自己實現,並新增到caffe中即可。upsample層主要完成了上取樣的工作,這裡不細說。本文主要講一下yolo層如何實現,上圖中的yolo detection即為yolo層的所在位置,接收三種不同大小的特徵圖,並完成對特徵圖的解析,得到物體的位置和類別資訊。所以其實yolo層主要起到了解析特徵並輸出檢測結果的作用,這一過程我們完全可以在外部實現而無需加入到網路結構當中,也就是說我們無需將實現的yolo層加入到caffe當中去。
通過上圖(我自己花的靈魂解析圖,凑活看吧),可以解釋yolo層如何得到檢測目標的位置和分類。yolo層的input是乙個13*13*n的特徵圖,其中13*13如果有看過yolov1的**作者有給出過解釋,其實就是影象被分成了13*13個grid cell,而每個grid中是乙個長度為n的張量,其中的資料是這樣分布的,前4個位置分別為x,y,w,h,用於計算目標框的位置;第5個位置為置信度值pr(object)*iou,表明了該位置的目標框包含目標的置信度;第5個位置往後則為該box包含物體類別的條件概率pr(class|object),從class1~class n,n為你所需檢測類別數。這樣(x,y,w,h)+ pr(object)*iou + n*pr(class|object)構成了box1的所有資訊,而乙個grid cell中含有3個這樣的boxes,這就是輸入到yolo層的特徵圖的直觀解釋。在yolo層進行檢測的時候,首先判定每個box的包含物體的置信度值即p的值是否大於設定閾值thresh,如果大於該閾值則認為這個box中含有物體,讀取位置資訊(x,y,w,h)與對應的anchor box的資訊計算得到物體框的實際位置。之後針對於每個含有物體的box,根據其類別概率判定其類別所屬,再對同一類別的目標框進行非極大值抑制nms,即得到最終結果。
以上即為yolo層所實現的檢測過程簡要介紹,具體的過程如何計算還需要看官們仔細看一下**和**,當然此過程不包括訓練的前向和反向過程,僅包含推理。因此我們轉換到caffe框架下的yolov3也僅能實現推理過程,具體的訓練還需要通過darknet來完成。
下面這部分將著重講一下如何實現從darknet向yolov3的轉換,首先這一過程要感謝chenyingpeng提供的**,部落格在這裡。
1.加入upsample層並編譯caffe
upsample層的**在這裡,密碼bwrd。
其中的upsample_layer.hpp放入include/caffe/layers下面;upsample_layer.cpp與upsample_layer.cu放在src/caffe/layers下面。
修改相應的caffe.proto檔案,src/caffe/proto/caffe.proto中的layerparameter的最後一行加入加入:
message layerparameter
注意149為新層的id號,該id號請根據個人的caffe.proto檔案指定即可。
然後再caffe.proto中新增upsample層的引數:
message upsampleparameter
緊接著重新編譯caffe,這樣就完成了在caffe中新增upsample層。更多資訊請參考caffe中新增新層教程。
上面說過轉換到caffe後只包含推理過程,因此我們需要將訓練好的模型(.cfg)和權重檔案(.weights)轉換到對應caffe下的.proto和.caffemodel,**可以借鑑github上的模型轉換工具。注意該工具需要pytorch支援請自行安裝。且該工具應用於yolov2,因為我們在caffe中加入了相應的upsample層並且yolov3和v2的網路結構有變化,因此需要替換相應的darknet2caffe.py,**在這裡,密碼:i6y2。
至此我們的準備工作就結束了,這樣通過caffe我們就能得到相應的blobs,這些blobs裡包含的資訊和darknet輸入給yolo層的資訊是一樣的。我們只需要通過yolo layer將blobs的資訊進行解析就能夠得到目標的位置和類別資訊。因為私人原因,這部分**不能開放,但是可以參考chenyingpeng的**,在這裡。經測試是同樣可用的,只需要注意因為我們的yolo layer的檢測過程是在caffe外部實現的,因此yolo layer層的相應資訊作者以硬編碼的形式加入到**中,使用的時候需要根據個人yolo layer的引數進行修改(比如我測試的時候yolo_layer.cpp中的函式get_detections中的類別數目沒有修改就發生了難以言表的結果...)。
yolov3從darknet轉caffe的整個過程就結束了,其中關於yolov3的原理並沒有詳細解釋特別多,本文主要著重於和轉到caffe框架相關的內容,具體yolov3的原理性文章推薦大家看這篇,裡面關於yolov1~v3講解的很詳細(來自一群還在上大一的學生的**解讀,不禁讓人感嘆長江後浪推前浪,前浪我已gg)。關於yolov3的訓練**,推薦大家去看darknet的原始碼,尤其是關於yolo layer的**,裡面有許多作者文章裡沒有講清楚的內容,感興趣的可以仔細鑽研一下。
本人才疏學淺,本文僅是最近工程實踐中的一點成果,如有錯誤還望指正。
基於caffe框架復現yolov3目標檢測
新增過程 把upsample layer.hpp 放在include caffe layers下面 把upsample layer.cpp與upsample layer.cu放在src caffe layers下面 然後重新編譯 編譯成功之後就可以載入yolov3.prototxt與yolov3.c...
yolo v3模型測試及測試結果轉化
訓練完成生成模型後,進行模型測試。對測試集資料進行檢測,得到檢測結果 像製作訓練集時生產2019 train.txt 檔案內容為包含所有訓練的路徑和檔名 一樣,製作2019 test.txt檔案 檔案內容為包含所有測試的路徑和檔名 採用以下程式來生成測試集的 test.txt 檔案,其中包含每個測試...
將yolov3的標籤轉化為yolov5格式的標籤
一般yolov3的資料集標籤格式為xml,其中bbox為xyxy格式 如圖 每行乙個obj,第乙個欄位是name,後面4個字段是normalized xywh格式的bbox。如下圖 為了能用yolov3的資料訓練yolov5,所以需要乙個轉格式的 將xml格式的標籤轉換為txt格式,並且將bbox的...