YOLO v1,YOLO v2,YOLO9000演算法總結與原始碼解析
1.YOLO v1簡介
YOLO出自2016 CVPR 《You Only Look Once:Unified, Real-Time Object Detection》。YOLO將目標區域定位於目標類別預測整合於單個神經網路模型中,實現了在準確率較高的情況下快速目標檢測與識別,YOLO達到了45幀每秒,Fast YOLO達到了155幀每秒,適用於實時的目標檢測。
YOLO利用單個卷積神經網路,將目標檢測問題轉換為直接從影象中提取bounding boxes和類別概率的迴歸問題。整個檢測過程分為3個階段:
(1)將影象縮放到448*448
(2)通過神經網格進行檢測和分類
(3)NMS抑制,輸出最終結果
具體地,YOLO首先將影象分為S*S的格子(grid cell)。如果一個目標的中心落入格子,則該格子就負責檢測該目標(如下圖)。每個格子(grid cell)預測B個邊界盒(bounding box)和C類判別屬性(最終輸出S*S*(B*5+C)維向量)。每一個邊界盒包含5個值:x,y,w,h(分別為邊界盒中心點橫、縱座標,寬,高)和邊界盒包含目標的置信值confidence。置信值為格子包含目標的概率與IOU的乘積。每個格子預測包含某一類目標的條件概率值。每個bounding box通過對應格子的類別概率和box置信度相乘得到該類別的置信分數。這個分數衡量了該類別出現在box中的概率以及該box與目標的吻合程度。
在VOC上訓練中,S=7,B=2,C=20,最終輸出7*7*(2*5+20)維度的資訊。
YOLO v1缺陷:
1.YOLO對相互靠的很近的物體(挨在一起且中點都落在同一個格子上的情況),還有很小的群體 檢測效果不好,這是因為一個網格中只預測了兩個框,並且只屬於一類。
2.測試影象中,當同一類物體出現的不常見的長寬比和其他情況時泛化能力偏弱。
3.由於損失函式的問題,定位誤差是影響檢測效果的主要原因,尤其是大小
物體的處理上,還有待加強。
2.YOLO v2簡介
YOLO相對於目前最好的目標檢測系統存在的問題是精確度不夠。相對於Fast R-CNN,YOLO在目標定位方面錯誤率較高。YOLO v2是YOLO的升級版,作者採用了一系列的方法優化了YOLO的模型結構,產生了YOLO v2,在快速檢測的同時準確率達到了state of the art,並且增強了定位精確度。
2.1為了達到更精確(Better)的目的,YOLO v2主要做了如下改進:
1 Batch normalization
神經網路學習過程本質就是為了學習資料分佈,一旦訓練資料與測試資料的
分佈不同,那麼網路的泛化能力也大大降低;另外一方面,一旦每批訓練資料的分佈各不相同(batch 梯度下降),那麼網路就要在每次迭代都去學習適應不同的分佈,這樣將會大大降低網路的訓練速度。
解決辦法之一是對資料做一個歸一化預處理。YOLOv2網路通過在每一個
卷積層後新增batch normalization,極大的改善了收斂速度同時減少了對其它regularization方法的依賴(捨棄了dropout優化後依然沒有過擬合),使得mAP獲得了2%的提升。
2 High Resolution Classifier
YOLOv2首先修改預訓練分類網路的解析度為448*448,在ImageNet資料
集上訓練10輪(10 epochs)。這個過程讓網路有足夠的時間調整filter去適應高解析度的輸入。然後fine tune為檢測網路,mAP獲得了4%的提升。
3 Convolutional With Anchor Boxes
YOLO(v1)使用全連線層資料進行bounding box預測(將全連線層轉換為S*S*(B*5+20)維的特徵),這會丟失較多的空間資訊,導致定位不準。
YOLOv2借鑑了Faster R-CNN中的anchor思想: 簡單理解為卷積特徵圖上進行滑窗取樣,每個中心預測9種不同大小和比例的建議框。由於都是卷積不需要reshape,很好的保留了空間資訊,最終特徵圖的每個特徵點和原圖的每個cell一一對應。而且用預測相對偏移(offset)取代直接預測座標簡化了問題,方便網路學習。總的來說就是移除全連線層(以獲得更多空間資訊)使用 anchor boxes去預測 bounding boxes。並且,YOLOv2將預測類別的機制從空間位置(cell)中解耦,由anchor box同時預測類別和座標(YOLO是由每個cell來負責預測類別,每個cell對應的2個bounding負責預測座標)。
4 Dimension Clusters(維度聚類)
在使用anchor時,Faster-RCNN中anchor boxes的個數和寬高維度往往是手動精選的先驗框(hand-picked priors),如果能夠一開始就選擇了更好的、更有代表性的先驗boxes維度,那麼網路就應該更容易學到準確的預測位置。YOLOv2中利用K-means聚類方法,通過對資料集中的ground truth box做聚類,找到ground truth box的統計規律。以聚類個數k為anchor boxes個數,以k個聚類中心box的寬高維度為anchor box的維度。
5 Direct location prediction
使用anchor boxes的另一個問題是模型不穩定,尤其是在早期迭代的時候。大部分的不穩定現象出現在預測box的(x,y)座標時。YOLOv2中預測相對於grid cell的座標位置,同時把ground truth限制在0到1之間,解決了模型隨機初始化之後將需要很長一段時間才能穩定預測敏感的物體偏移的問題。
使用Dimension Clusters和Direct location prediction這兩項anchor boxes改進方法,mAP獲得了5%的提升。
6 Fine-Grained Features(細粒度特徵)
YOLOv2使用了一種不同的方法,簡單新增一個 passthrough layer,把淺層特徵圖(解析度為26*26)連線到深層特徵圖。
passthroughlaye把高低解析度的特徵圖做連結,疊加相鄰特徵到不同通道(而非空間位置),類似於Resnet中的identity mappings。這個方法把26*26*512的特徵圖疊加成13*13*2048的特徵圖,與原生的深層特徵圖相連線。
YOLOv2的檢測器使用的就是經過擴充套件後的的特徵圖,它可以使用細粒度特徵,使得模型的效能獲得了1%的提升。
7 Multi-ScaleTraining
原始YOLO網路使用固定的448*448的圖片作為輸入,加入anchor boxes後輸入變成416*416,由於網路只用到了卷積層和池化層,就可以進行動態調整(檢測任意大小圖片)。為了讓YOLOv2對不同尺寸圖片的具有魯棒性,在訓練的時候也考慮了這一點。
不同於固定網路輸入圖片尺寸的方法,每經過10批訓練(10 batches)就會隨機選擇新的圖片尺寸。網路使用的降取樣引數為32,於是使用32的倍數{320,352,…,608},最小的尺寸為320*320,最大的尺寸為608*608。 調整網路到相應維度然後繼續進行訓練。
這種機制使得網路可以更好地預測不同尺寸的圖片,同一個網路可以進行不同解析度的檢測任務,在小尺寸圖片上YOLOv2執行更快,在速度和精度上達到了平衡。
在低解析度圖片檢測中,YOLOv2是檢測速度快(計算消耗低),精度較高的檢測器。輸入為228*228的時候,幀率達到90FPS,mAP幾乎和Faster R-CNN的水準相同。使得其更加適用於低效能GPU、高幀率視訊和多路視訊
場景。
在高解析度圖片檢測中,YOLOv2達到了先進水平(state-of-the-art)。
2.2為了達到更快速(Faster)的目的,YOLO v2主要做了如下改進:
1. Darknet-19
為了精度與速度並重,YOLOv2使用了一個新的分類網路作為特徵提取部分,參考了前人的工作經驗。類似於VGG,網路使用了較多的3*3卷積核,在每一次池化操作後把通道數翻倍。借鑑了network in network的思想,網路使用了全域性平均池化(global average pooling)做預測,把1*1的卷積核置於3*3的卷積核之間,用來壓縮特徵。使用batch normalization穩定模型訓練,加速收斂,正則化模型。最終得出的基礎模型就是Darknet-19,包含19個卷積層、5個最大值池化層(max pooling layers )。
2. Training for classifier
作者使用Darknet-19在標準1000類的ImageNet上訓練了160次,用隨機
梯度下降法,starting learning rate 為0.1,polynomial rate decay 為4,weight decay為0.0005 ,momentum 為0.9。訓練的時候仍然使用了很多常見的資料擴充方法(data augmentation),包括random crops, rotations, and hue, saturation, and exposure shifts。(引數都是基於作者的darknet框架)初始的224*224訓練後把解析度上調到了448*448,使用同樣的引數又訓練了10次,學習率調整到了10的-3次方。高解析度下訓練的分類網路top-1準確率76.5%,top-5準確率93.3%。
3. Training for detection
為了把分類網路改成檢測網路,去掉原網路最後一個卷積層,增加了三個 3 *3 (1024 filters)的卷積層,並且在每一個卷積層後面跟一個1*1的卷積層,輸出維度是檢測所需數量。
對於VOC資料集,預測5種boxes,每個box包含5個座標值和20個類別,所以總共是5*(5+20)= 125個輸出維度。
也添加了passthrough layer,從最後3*3*512的卷積層連到倒數第二層,使模型有了細粒度特徵。
學習策略是:先以10的-3次方的初始學習率訓練了160次,在第60次和
第90次的時候學習率減為原來的十分之一。weight decay為0.0005,momentum為0.9,以及類似於Faster-RCNN和SSD的資料擴充(data augmentation)策略:random crops, color shifting, etc。使用相同的策略在 COCO 和VOC上訓練。
3.YOLO9000簡介
YOLO9000是在YOLOv2的基礎上得到的,相比於YOLO v2,YOLO9000
具有更強大(Stronger)的檢測功能,可以檢測出更多的類別。作者提出了一種在分類資料集和檢測資料集上聯合訓練的機制。使用檢測資料集的圖片去學習檢測相關的資訊,例如bounding box 座標預測,是否包含物體以及屬於各個物體的概率。使用僅有類別標籤的分類資料集圖片去擴充套件可以檢測的種類。
訓練過程中把監測資料和分類資料混合在一起。當網路遇到一張屬於檢測資料集的圖片就基於YOLOv2的全部損失函式(包含分類部分和檢測部分)做反向傳播。當網路遇到一張屬於分類資料集的圖片就僅基於分類部分的損失函式做反向傳播。 作者最後採用一種不要求互不包含的多標籤模型(multi-label model)來整合資料集。這種方法忽略了資料集的結構(例如 COCO資料集的所有類別之間是互不包含的)。
1. Hierarchical classification(層次式分類)
WordNet是一個有向圖結構(而非樹結構),因為語言是複雜的(例如“dog”既是“canine”又是“domestic animal”),為了簡化問題,作者從ImageNet的概念中構建了一個層次樹結構(hierarchical tree)來代替圖結構方案。最終結果是一顆 WordTree (視覺名片語成的層次結構模型)
2.Dataset combination with WordTree
使用WordTree把多個數據集整合在一起。
3.joint classification and detection(聯合訓練分類和檢測)
使用WordTree整合了資料集之後就可以在資料集(分類-檢測資料)上訓練聯合模型。我們想要訓練一個檢測類別很大的檢測器所以使用COCO檢測資料集和全部ImageNet的前9000類創造一個聯合資料集。為了評估我們使用的方法,也從ImageNet detection challenge 中向整合資料集新增一些還沒有存在於整合資料集的類別。相應的WordTree有9418個類別。由於ImageNet是一個非常大的資料集,所以通過oversampling COCO資料集來保持平衡,使ImageNet:COCO = 4:1。
使用上面的資料集訓練YOLO9000。採用基本YOLOv2的結構,anchor box數量由5調整為3用以限制輸出大小。
當網路遇到一張檢測圖片就正常反向傳播。其中對於分類損失只在當前及其路徑以上對應的節點類別上進行反向傳播。當網路遇到一張分類圖片僅反向傳播分類損失。在該類別對應的所有bounding box中找到一個置信度最高的(作為預測座標),同樣只反向傳播該類及其路徑以上對應節點的類別損失。反向傳播objectness損失基於如下假設:預測box與ground truth box的重疊度至少0.31IOU。
採用這種聯合訓練,YOLO9000從COCO檢測資料集中學習如何在圖片中尋找物體,從ImageNet資料集中學習更廣泛的物體分類。
作者在ImageNet detection task上評估YOLO9000。ImageNet detection task和COCO有44個物體類別是相同的。這意味著YOLO9000只從大多數測試資料集中看到過分類資料而非檢測資料。最終整體精度為19.7mAP,在從未見過的156個物體檢測資料類別上精度為16.0mAP。這個結果高於DPM,但是YOLO9000是在不同資料集上進行半監督訓練。而且YOLO9000可以同時實時檢測9000多種其它物體類別。
作者也分析了YOLO9000在ImageNet上的效能,發現可以學習新的動物表現很好,但是學習衣服和裝置這類物體則不行。因為從COCO資料集上動物類別那裡學習到的物體預測泛化性很好。但是COCO資料集並沒有任何衣服類別的標籤資料(只有”人”類別),所以YOLO9000很難對“太陽鏡”,“游泳褲”這些類別建模。
4.YOLO原始碼解析
4.1 train 解析
從main()方法(darknet.c中)開始,首先讀取引數;
第一個引數是yolo,故跳轉到run_yolo函式(yolo.c中);
第二個引數是train,所以跳轉到了train_yolo函式(yolo.c中)。
第三個引數是cfg/yolo.train.cfg, 網路架構檔案
第四個引數是預訓練權重引數weightfile,預訓練引數檔案
4.1.1相關函式解析
網路引數解析函式:parse_network_cfg
1.首先建立一個list,取名sections,記錄一共有多少個section(一個section儲存了CNN一層所需引數);
2.然後建立一個node,該node的void型別的指標指向一個新建立的section;該section的char型別指標指向.cfg檔案中的某一(line),然後將該section的list指標指向一個新建立的node,該node的void指標指向一個kvp結構體,kvp結構體中的key就是.cfg檔案中的關鍵字(如:batch,subdivisions等),val就是對應的值;如此迴圈就形成了上述的引數網路圖。
注:用矩形表示list,橢圓表示section,圓形表示node,六邊形表示kvp,為了表達方便,我就把section和kvp放到了node裡面
載入權重函式:load_weights(&net,weightfile)
1.呼叫load_weights_upto(net, filename, net->n)函式;
2.分別載入每一層的權重;
網路訓練函式:train_network(network net, data d)
1.載入訓練資料至網路中
2.呼叫train_network_datum(net, x, y)訓練網路
3.呼叫forward_network(net, state); backward_network(net, state);
4.計算損失
4.2 test 解析
從main()方法(darknet.c中)開始,首先讀取引數;
第一個引數是yolo,故跳轉到run_yolo函式(yolo.c中);
第二個引數是test,所以跳轉到了test_yolo函式(yolo.c中)。
第三個引數是cfg/yolo.cfg
第四個引數是預訓練權重引數weightfile
第五個引數是filename,為待測試的圖片檔案
4.3 YOLO 程式碼框架總結
關於YOLO程式碼的框架,大概總結下darknet的優缺點。
優點:
1.程式碼依賴項少,只有cuda,甚至連opencv都可以不需要,如果在cpu平臺,cuda都可以扔了(當然darknet的cup程式碼並沒有做什麼優化,跑起來就很慢)。可以較容易得將程式碼移植到其他平臺;
缺點:
1.在darknet中,所有層的lr都一樣,這對微調造成了很大的困難,因為微調需要把前面幾層的lr都設定的很小很小,然後主要訓練最後一層的權重
2.總的來說就是darknet的介面確實很差,如果想把網路改成inception或者resnet的構架,需要改大量的程式碼,這對於驗證模型可行性來說,非常浪費時間。
補充:
YOLO v1訓練流程:
1.輸入圖片,接受輸入維度為([None, 448, 448, 3]);
2.隨機初始化網路權重(若是基於已有的網路模型,則在已有的模型上進行微調);
3.根據各層初始化的權重,得到輸出bounding box的初始位置(x,y,w,h),置信度(confidence),類別概率C,對於一張輸入圖片,輸出為S*S*(5*B+C)維的向量,其中B=2,C=20,輸出維度為輸出維度為([None,1470]);
4.根據輸出向量計算損失值(detection 層才有cost);根據損失值指導權重更新;
5.當達到最大迭代次數時結束訓練;
YOLO v1測試流程:
1.輸入測試圖片;
2.根據網路模型計算輸出向量,即為圖片的cell預測的bounding box位置、置信度資訊及類別概率資訊;
3.每個網格預測的類別概率資訊和每個bounding box預測的confidence資訊相乘,得到每個bounding box屬於某一類的置信得分(class-specific confidence score);對每一個網格預測的每一個bbox執行同樣的操作:7*7*2=98 bbox(每個bbox既有對應的class資訊又有座標資訊);
4.得到每個bbox的class-specific confidence score以後,設定閾值,濾掉得分低的boxes,對保留的boxes進行NMS處理,就得到最終的檢測結果;