1. 程式人生 > >深度學習之---yolov1,v2,v3詳解

深度學習之---yolov1,v2,v3詳解

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

一、YOLOv1 簡介

這裡不再贅述,之前的我的一個 GitChat 詳盡的講述了整個程式碼段的含義,以及如何一步步的去實現它,可參照這裡手把手實踐YOLO深度殘差神經網路拐點檢測

二、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 資料集上預測的 [email protected] 的精度。無論是在耗費時間,還是預測精度上面,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

參考資料:

  1. https://timebutt.github.io/static/understanding-yolov2-training-output/
  2. https://www.zhihu.com/question/42205480
  3. https://blog.csdn.net/qq_30401249/article/details/51694298

轉載:https://gitbook.cn/books/5aceab0afafeca4b1a33e7b4/index.html