深度學習之 YOLO v1,v2,v3詳解


(寫在前面:如果你想 run 起來,立馬想看看效果,那就直接跳轉到最后一張,動手實踐,看了結果再來往前看吧,開始吧······)

一、YOLOv1 簡介

這里不再贅述,之前的我的一個 GitChat 詳盡的講述了整個代碼段的含義,以及如何一步步的去實現它

二、YOLOv2 簡介

V1 版本的缺陷和不足,就是 V2 版本出現的源泉與動力,而 V1 版本究竟在哪些地方是它的短板之處呢:

V1 缺陷之處:

  1. 輸入尺寸固定:由於輸出層為全連接層,因此在檢測時,YOLO 訓練模型只支持與訓練圖像相同的輸入分辨率。其它分辨率需要縮放成此固定分辨率;
  2. 占比較小的目標檢測效果不好:雖然每個格子可以預測 B 個 bounding box,但是最終只選擇只選擇 IOU 最高的 bounding box 作為物體檢測輸出,即每個格子最多只預測出一個物體。當物體占畫面比例較小,如圖像中包含畜群或鳥群時,每個格子包含多個物體,但卻只能檢測出其中一個。

2.1 anchor box 的思想引入

為提高物體定位精准性和召回率,YOLO 作者提出了 《YOLO9000: Better, Faster, Stronger》 (Joseph Redmon, Ali Farhadi, CVPR 2017, Best Paper Honorable Mention),也就是 YOLOv2 的論文全名,相比 v1 提高了訓練圖像的分辨率;引入了 faster rcnn 中 anchor box 的思想,對網絡結構的設計進行了改進,使得模型更易學習。

什么是(候選區域框)anchor box?

假設特征可以看做一個尺度 6448 像素的 256 通道圖像,對於該圖像的每一個位置,考慮 9 個可能的候選窗口:三種面積三種比例。這些候選窗口稱為 anchors。下圖示出 6448 圖像 anchor 中心,在每個面積尺寸下,取三種不同的長寬比例(1:1,1:2,2:1),這樣一來,我們得到了一共 9 種面積尺寸各異的 anchor。示意圖如下:

anchor box

以一個點 9 種尺寸來取 proposal,重復區域多。而且 feature map 相鄰兩個點對應原圖的 9 個 proposal 也是很多重復區域。只是整個 faster RCNN 中的第一步,只是對候選區域進行提取 (RPN, region proposal networks, 候選區域生成網絡)。這個過程只是希望能夠得到覆蓋目標的候選區域,所以有不同尺寸不同比例的 proposal(這樣才有最大可能可以在一個候選框中包括完整的目標)。而在這之后,確實會有很多重復區域,而這其實是候選區域生成之后的下一個問題。針對這個問題,一般會采用非極大值抑制算法進行去重 (NMS, non maximum suppression)。

至於這個 anchor 到底是怎么用的,這個是理解整個問題的關鍵。

下面是整個 faster RCNN 結構的示意圖:

faster rcnn

輸入圖像無論是什么大小的樣本,都要轉化為 224*224(可根據情況自己設定)大小的圖片,送進網絡進行訓練。( 為什么要固定輸入網絡圖片尺寸呢?后面解釋。)

對於每個 3x3 的窗口,作者就計算這個滑動窗口的中心點所對應的原始圖片的中心點。然后作者假定,這個 3x3 窗口,是從原始圖片上通過 SPP 池化 得到的,而這個池化的區域的面積以及比例,就是一個個的 anchor。換句話說,對於每個 3x3 窗口,作者假定它來自 9 種不同原始區域的池化,但是這些池化在原始圖片中的中心點,都完全一樣。這個中心點,就是剛才提到的,3x3 窗口中心點所對應的原始圖片中的中心點。如此一來,在每個窗口位置,我們都可以根據 9 個不同長寬比例、不同面積的 anchor,逆向推導出它所對應的原始圖片中的一個區域,這個區域的尺寸以及坐標,都是已知的。而這個區域,就是我們想要的 proposal。所以我們通過滑動窗口和 anchor,成功得到了 51x39x9 個原始圖片的 proposal。接下來,每個 proposal 我們只輸出 6 個參數:每個 proposal 和 ground truth 進行比較得到的前景概率和背景概率 (2 個參數)(對應圖上的 clsscore);由於每個 proposal 和 ground truth 位置及尺寸上的差異,從 proposal 通過平移放縮得到 ground truth 需要的 4 個平移放縮參數(對應圖上的 bboxpred)。

為什么之前的 CNN 要固定輸入網絡圖片尺寸呢?

CNN 大體包含 3 部分:卷積、池化、全連接

  1. 卷積層。卷積操作對圖片輸入的大小會有要求嗎?比如一個 5 * 5 的卷積核,我輸入的圖片是 30 * 81 的大小,可以得到 (26,77) 大小的圖片,並不會影響卷積操作。我輸入 600 * 500,它還是照樣可以進行卷積,也就是卷積對圖片輸入大小沒有要求,只要你喜歡,任意大小的圖片進入,都可以進行卷積。
  2. 池化層。池化對圖片大小會有要求嗎?比如我池化大小為(2,2)我輸入一張 30 * 40 的,那么經過池化后可以得到 15 * 20 的圖片。輸入一張 53 * 22 大小的圖片,經過池化后,我可以得到 26 * 11 大小的圖片。因此池化這一步也沒對圖片大小有要求。只要你喜歡,輸入任意大小的圖片,都可以進行池化。
  3. 全連接層。既然池化和卷積都對輸入圖片大小沒有要求,那么就只有全連接層對圖片結果又要求了。因為全連接層我們的連接勸值矩陣的大小 W,經過訓練后,就是固定的大小了,比如我們從卷積到全連層,輸入和輸出的大小,分別是 50、30 個神經元,那么我們的權值矩陣(50,30)大小的矩陣了。因此空間金字塔池化,要解決的就是從卷積層到全連接層之間的一個過度。

這里插入卷積、池化層的輸入輸出計算方法:

enter image description here 例子計算詳情 例子

怎么改變這個現狀呢,也就是無論輸入圖片是什么大小,不需要都轉化為統一大小的圖片,再送入網絡的預處理過程。這就出現了大神何凱明的 CNN 應用之 SPP。空間金字塔池化的卷積神經網絡物體檢測,很詳細,能看懂其中原因和機理,不贅述。

2.2 YOLOv2 多處改進

2.2.1 輸出層使用卷積層替代 YOLOv1 的全連接層

附 darknet-19 的結構表:

darknet-19

包含 19 conv + 5 maxpooling。用 1x1 卷積層替代 YOLOv1 的全連接層。

1x1 卷積層(此處 1x1 卷積層的存在是為了跨通道信息整合)如上圖的紅色矩形框部分。

引入一點:YOLO,YOLOv2、YOLO9000,Darknet-19,Darknet-53,YOLOv3 分別是什么關系?

  1. YOLOv2 是 YOLO 的升級版,但並不是通過對原始加深或加寬網絡達到效果提升,反而是簡化了網絡。
  2. YOLO9000 是 CVPR2017 的最佳論文提名。首先講一下這篇文章一共介紹了 YOLOv2 和 YOLO9000 兩個模型,二者略有不同。前者主要是 YOLO 的升級版,后者的主要檢測網絡也是 YOLOv2,同時對數據集做了融合,使得模型可以檢測 9000 多類物體。而提出 YOLO9000 的原因主要是目前檢測的數據集數據量較小,因此利用數量較大的分類數據集來幫助訓練檢測模型。
  3. YOLOv2 使用了一個新的分類網絡作為特征提取部分,參考了前人的先進經驗,比如類似於 VGG,作者使用了較多的 3 * 3 卷積核,在每一次池化操作后把通道數翻倍。借鑒了 network in network 的思想,網絡使用了全局平均池化(global average pooling),把 1 * 1 的卷積核置於 3 * 3 的卷積核之間,用來壓縮特征。也用了 batch normalization(前面介紹過)穩定模型訓練。最終得出的基礎模型就是 Darknet-19,如上圖,其包含 19 個卷積層、5 個最大值池化層(maxpooling layers )

2.2.2 卷積層全部使用 Batch Normalization

v1 中也大量用了 Batch Normalization,同時在定位層后邊用了 dropout,v2 中取消了 dropout,在卷積層全部使用 Batch Normalization。

2.2.3 K-Means 算法

我們知道在 Faster R-CNN 中 anchor box 的大小和比例是按經驗設定的,然后網絡會在訓練過程中調整 anchor box 的尺寸。但是如果一開始就能選擇到合適尺寸的 anchor box,那肯定可以幫助網絡越好地預測 detection。所以作者采用 k-means 的方式對訓練集的 bounding boxes 做聚類,試圖找到合適的 anchor box。

另外作者發現如果采用標准的 k-means(即用歐式距離來衡量差異),在 box 的尺寸比較大的時候其誤差也更大,而我們希望的是誤差和 box 的尺寸沒有太大關系。所以通過 IOU 定義了如下的距離函數,使得誤差和 box 的大小無關:

Faster R-CNN 采用的是手選先驗框方法,YOLOv2 對其做了改進,采用 k-means 在訓練集 bbox 上進行聚類產生合適的先驗框. 由於使用歐氏距離會使較大的 bbox 比小的 bbox 產生更大的誤差,而 IOU 與 bbox 尺寸無關, 因此使用 IOU 參與距離計算, 使得通過這些 anchor boxes 獲得好的 IOU 分值。距離公式:

k-means

如下圖 Figure2,左邊是聚類的簇個數核 IOU 的關系,兩條曲線分別代表兩個不同的數據集。在分析了聚類的結果並平衡了模型復雜度與 recall 值,作者選擇了 K=5,這也就是 Figure2 中右邊的示意圖是選出來的 5 個 box 的大小,這里紫色和黑色也是分別表示兩個不同的數據集,可以看出其基本形狀是類似的。而且發現聚類的結果和手動設置的 anchor box 大小差別顯著。聚類的結果中多是高瘦的 box,而矮胖的 box 數量較少。

enter image description here

K-Means 算法概述:k-means 是非監督學習中的聚類算法; 基本 K-Means 算法的思想很簡單,事先確定常數 K,常數 K 意味着最終的聚類類別數,首先隨機選定初始點為質心,並通過計算每一個樣本與質心之間的相似度 (這里為歐式距離),將樣本點歸到最相似的類中,接着,重新計算每個類的質心 (即為類中心),重復這樣的過程,知道質心不再改變,最終就確定了每個樣本所屬的類別以及每個類的質心。由於每次都要計算所有的樣本與每一個質心之間的相似度,故在大規模的數據集上,K-Means 算法的收斂速度比較慢。

enter image description here

使用聚類進行選擇的優勢是達到相同的 IOU 結果時所需的 anchor box 數量更少, 使得模型的表示能力更強, 任務更容易學習。

2.2.4 Multi-Scale Training

和 YOLOv1 訓練時網絡輸入的圖像尺寸固定不變不同,YOLOv2(在 cfg 文件中 random=1 時)每隔幾次迭代后就會微調網絡的輸入尺寸。訓練時每迭代 10 次,就會隨機選擇新的輸入圖像尺寸。因為 YOLOv2 的網絡使用的 downsamples 倍率為 32,所以使用 32 的倍數調整輸入圖像尺寸 {320,352,…,608}。訓練使用的最小的圖像尺寸為 320 x 320,最大的圖像尺寸為 608 x 608。 這使得網絡可以適應多種不同尺度的輸入。更多詳細的資料可查看這里目標檢測之 YOLOv3,YOLOv3 才是全文的的重點。

這里給出官方的 YOLOv2 與其它模型在 VOC 2007 數據集上的效果對比

對比

三:YOLO v3 簡介

本文的重點,先一張圖看看 V3 版本的強大

對比

橫軸是每張圖像的預測推理時間,單位 ms。縱軸是在 COCO 數據集上預測的 mAP@0.5 的精度。無論是在耗費時間,還是預測精度上面,v3 版本都完勝過去的一些模型。

darknet-53 模型

v3 注:YOLO Detection 層: 坐標及類別結果輸出層;Region 82,Region 94,Region 106。

YOLOv3 的改進之處:多尺度預算

  • 坐標預測:bbox 預測仍是 yolov2 的使用維度聚類(dimension clusters )作為 anchor boxes 來預測邊界框. 在訓練期間,我們使用平方誤差損失的總和。

  • 對象分數:YOLOv3 使用邏輯回歸預測每個邊界框(bounding box)的對象分數。 如果先前的邊界框比之前的任何其他邊界框重疊 ground truth 對象,則該值應該為 1。如果以前的邊界框不是最好的,但是確實將 ground truth 對象重疊了一定的閾值以上,我們會忽略這個預測,按照 [15] 進行。我們使用閾值 0.5。與 [15] 不同,我們的系統只為每個 ground truth 對象分配一個邊界框。如果先前的邊界框未分配給 grounding box 對象,則不會對坐標或類別預測造成損失。

  • 類別預測:每個框使用多標簽分類來預測邊界框可能包含的類。在訓練過程中,使用二元交叉熵損失來進行類別預測。

補充:Darknet 框架 Darknet 由 C 語言和 CUDA 實現, 對 GPU 顯存利用效率較高 (CPU 速度差一些, 通過與 SSD 的 Caffe 程序對比發現存在 CPU 較慢,GPU 較快的情況). Darknet 對第三方庫的依賴較少, 且僅使用了少量 GNU linux 平台 C 接口, 因此很容易移植到其它平台, 如 Windows 或嵌入式設備.

四:動手實踐篇

來開始本文的重中之重吧——

第一步:首先根據官網提示,一步步的走一遍,直到能夠訓練 VOC 數據集,就可以停下來歇歇了。官網點這里穿越如果一起正常,恭喜你,就可以開始之后的步驟了。當然有興趣想了解 YOLOv3 中設計上的更多細節,可以去看下詼諧幽默的論文,點這里,看 YOLOv3: An Incremental Improvement后面也會就論文中和修改中的一些聯系,做個解釋。

第二步:上面做完,只是說明你可以檢測和訓練了官方的圖片數據集,下面開始自己的數據集。

注意點: 如果你的電腦設備是有 GPU 加速圖像運算的,那樣在第一步中,默認的還是 CPU 下的訓練,想要使用 GPU 就要改 Makefile 文件這里了

GPU 這是我這一個博客中看到的,將紅色框圈中的部分改為 1,修改了之后,在 darknet 文件目錄下 make clean 清除之前的 make 文件,重新 make,發現速度明顯提高,使用上了 GPU 訓練。(其實在之前第一次我重新 make 時候報 opencv 錯誤,后來盡管發錯 opencv 沒有安裝好,make 也通過了,對這個沒有影響,就沒有太關注這里了,有經驗的求告知)。相同的命令,再來訓練一次 VOC 數據試試看,速度是不是提高杠杠的。

第三步:數據集的采集,制作標簽,這塊還參考手把手實踐 YOLO 深度殘差神經網絡拐點檢測,一句話也就是 labelImg 標記軟件工具了,具體不詳述了。其中有一點就是 ImageSets/Main/ 文件夾下的 train.txt,test.txt,val.txt,這里的文件需要改為自己待訓練的圖片所有名字編號,在生成待訓練的 train.txt 大有用處。

第四步:對待訓練初始配置參數進行修改

**改動一 **

首先確定你需要做幾個類別的物體檢測,也就是 classes=1,還是 classes=5 或者 7,或者 20。我這里待檢測的類別為一類,所以 classes=1, 如下圖的 cfg 文件夾下的.data 文件:

  • class 為訓練的類別數
  • train 為訓練集 train.txt
  • valid 為驗證集 val.txt(未標識添加,后期可加入)
  • names 為 my_target.names,里面為自己訓練的目標名稱
  • backup 為 weights 的存儲位置

將 VOC 格式的 xml 文件轉換成 YOLO 格式的 txt 文件。

  • train.txt 為 python voclabel.py 自動生成的,為自己的待訓練樣本文件位置。其中在 voclabel.py 文件我對其進行了修改,sets=[] 也進行了刪減,只留下自己需要的那一部分;lasses=[" "], 里面為自己的檢測類別;生成的 train.txt 也只是自己需要的部分,如下圖(如有不妥或者錯誤,求批評指正,自己想着改的,並未看到相關材料指導)

enter image description here

  • <文件名>.names 文件 原始的部分為 coco.data。如果你不想惹麻煩,直接將此處更名為 coco.data 即可。如若你想將此處的.data 文件更改為自己的特有命名,如 my_yolov3.data。這就需要在 examples 里面的 darknet.c 文件的 440 行處進行修改為自己的命名,然后 cd 到 darknet 文件夾下 make clean 刪除之前的 make 文件,然后重新 make 即可。

沒改之前直接使用,會出現這個錯誤提示(訓練和檢測報錯都有):

提示

改動就是在這里修改:

coco.names

make 命令百科

在軟件開發中,make 是一個工具程序(Utility software),經由讀取叫做“makefile”的文件,自動化建構軟件。它是一種轉化文件形式的工具,轉換的目標稱為“target”;與此同時,它也檢查文件的依賴關系,如果需要的話,它會調用一些外部軟件來完成任務。它的依賴關系檢查系統非常簡單,主要根據依賴文件的修改時間進行判斷。大多數情況下,它被用來編譯源代碼,生成結果代碼,然后把結果代碼連接起來生成可執行文件或者庫文件。它使用叫做“makefile”的文件來確定一個 target 文件的依賴關系,然后把生成這個 target 的相關命令傳給 shell 去執行。

許多現代軟件的開發中 (如 Microsoft Visual Studio),集成開發環境已經取代 make,但是在 Unix 環境中,仍然有許多任務程師采用 make 來協助軟件開發。

  • /backup/ 文件夾下用於存放訓練好的.weights 參數文件,源代碼里面是迭代次數小於 1000 時,每 100 次保存一次,大於 1000 時,沒 10000 次保存一次。自己可以根據需求進行更改,然后重新編譯即可。代碼位置在 examples 里面的 detector.c line 138,和上面的一樣,cd 到 darknet 文件夾下 make clean 刪除之前的 make 文件,然后重新 make 即可。這樣.data 文件就這么些內容。

10000

**改動二 **

cfg 文件夾下的.cfg 文件,有很多,用到的只是 yolov3-voc.cfg(現在還不知道別的.cfg 文件該怎么用,求指點,於是我把別的文件全刪除了,只留下 coco.data 和 yolov3-voc.cfg)一切正常,還沒發現出錯。刪了 -- 改名,就這樣了(改了名之后報錯?就需要改動一處的指示了,回看改動一)

cfg

最重要的改動,是在 my_yolov3.cfg(已圖片處的名字為例)下的參數,欲知詳情,娓娓道來······

  • my_yolov3.cfg 下參數改動:Training or Testing pattern?

pattern

如圖:

  • batch:每次迭代要進行訓練的圖片數量
  • subdivisions:batch 中的圖片再產生子集,源碼中的圖片數量 int imgs = net.batch * net.subdivisions * ngpus (一次傳入 batch 張圖像,細分成 subdivisions 組行迭代訓練,此時的 subdivisions=8,就會發現 train 時候,兩次迭代輸出之間,共輸出了 8 次 Region 82,Region 94,Region 106。這里的 batch 是 16,即 8 組 2 個圖像。你也可以設定 batch=64,此時的訓練迭代就有 8 組 8 個圖像了。)
  1. Training pattern:注釋掉 Testing 下的 batch 和 subdivisions 兩個初始參數,讓 Training 下的 batch 和 subdivisions 兩個初始參數參與運算;
  2. Testing pattern:反之,注釋掉 Training 下的 batch 和 subdivisions 兩個初始參數,讓 Testing 下的 batch 和 subdivisions 兩個初始參數參與運算。(上圖就是在 test 下的參數模式,切記)

YOLOv3 預測 3 個不同尺度的 box

我們的系統使用類似的概念以金字塔網絡(SPP)從這些量表中提取特征。最后一層網絡預測一個 3D 張量編碼的邊界框,對象和類的預測(classes)。COCO 試驗中,我們預測每個尺度上的 3 個盒子,所以這個張量是 NN3(4+1+80)的 4 個邊界框偏移量,1 個目標預測,和 80 個類的預測。如果 classes=1,也就是上面的 my_yolov3.data,文件里面定義的,此時的最后一層 filters=3*(4+1+1)=18。

論文對最后一層網絡的解釋如下

論文

第五步:Now we can train my target_yolo!

參考這個官方提示來做對應的修改,改為自己的命名形式,如果還是不行,恐怕就是你的 make 步驟沒有做。make clean-- --make

三色

  • 紅色框:cfg 文件夾下的.data 文件
  • 綠色框:cfg 文件夾下的.cfg 文件
  • 黃色框:darknet-53 的預訓練參數作為整個 train 的初始參數

train 具體的輸出詳解 enter image description here

Region Avg IOU: ----0.326577 is the average of the IOU of every image in the current subdivision. A 32,66% overlap in this case, this model still requires further training. Class: -----0.742537 still figuring this out Obj: -----0.033966 still figuring this out No Obj:----- 0.000793 still figuring this out The Avg Recall:------ 0.12500 is defined in code as recall/count, and thus a metric for how many positives YOLOv2 detected out of the total amount of positives in this subdivision. In this case only one of the eight positives was correctly detected. count: -----8 is the amount of positives (objects to be detected) present in the current subdivision of images (subdivision with size 8 in our case). Looking at the other lines in the log, you'll see there are also subdivision that only have 6 or 7 positives, indicating there are images in that subdivision that do not contain an object to be detected.

如果不幸,輸出的是這個樣子

樣子

那就是你在 2.1.1 節時候,把 Training or Testing 注釋錯了,更改下,再試試。

如果成功了,那就出去溜溜等着吧,記得回來看看 loss 參數,迭代輸出像這樣

enter image description here

9798----- indicates the current training iteration/batch. 0.370096 -----is the total loss. 0.451929 ------avg is the average loss error, which should be as low as possible. As a rule of thumb, once this reaches below 0.060730 avg, you can stop training. 0.001000----- rate represents the current learning rate, as defined in the .cfg file. 3.300000 -----seconds represents the total time spent to process this batch. The 627072 -----images at the end of the line is nothing more than 9778 * 64, the total amount of images used during training so far.

序列測試,這里將 cfg/myyolov3.data 進行修改,加入 valid 的測試序列地址,重新 python voclabel.py

valid

valid 測試

./darknet detector valid cfg/myyolov3.data cfg/myyolov3.cfg backup/yolo-voc_final.weights

/在終端只返回用時,在./results/comp4dettest_[類名].txt 里保存測試結果/

打開查看內容

valid

依次表示的是:文件名;每個框中存在該分類物體的概率;框框坐標 xmin;框框坐標 ymin;框框坐標 xmax;框框坐標 ymax,代碼區如下截圖,位置 examples/detector.c code

當然也有別的測試方式,並返回評價指標,如圖,可自己嘗試

 enter image description here


免責聲明!

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



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