如何使用YOLOV4的darknet訓練自己的數據集?

0 我的環境

ubuntu 16.04

GPU 2080Ti

CUDA: 10.0.0

cuDNN: 7.4.1

 

1 下載darknet源碼

方式一:首先我們需要下載yolov4的darknet源碼:https://github.com/AlexeyAB/darknet

方式二:因爲從github下載源碼比較慢,可是使用另外一種方法,將github上的源碼保存在gitee中,然後從gitee上下載源碼。gitee畢竟是國內的嘛,下載速度會開很多。

具體操作就是:

(1) 創建gitee賬號並且登錄

(2) 點擊新建倉庫

(3) 新建倉庫會彈出一個新的界面,然後將界面拉到最底部,點擊import

點擊import之後,然後在其中輸入github上darknet的地址就行

(4) 這樣你就會創建一個darknet的倉庫,內容和github的內容一樣

 然後點擊copy複製地址,使用git clone 的方在終端中進行下載。

 

2 創建數據集文件目錄

首先我們需要下載yolov4的darknet源碼:https://github.com/AlexeyAB/darknet

因爲從github下載源碼比較慢,可是使用另外一種方法,將github上的源碼保存在gitee中,然後從gitee上下載源碼。gitee畢竟是國內的嘛,下載速度會開很多。

如果不對yolov4源碼進行修改的,但是想使用yolov4訓練自己的數據集,我們需要按照yolov4讀取數據集的方式,創建相應的數據集文件目錄。最終的數據集目錄結構是這個樣子的:

darknet-master

    ---- data
         
         ---- obj.names        # 物體類別名稱(如果有兩類物體,就寫上兩類物體的名稱)

         ---- obj.data         # 將數據集的信息保存在這個文件中,yolov4從這個文件中讀取數據集信息
        
         ---- obj              # 存放圖片以及每個圖片的標籤信息
    
         ---- train.txt        # 存放訓練集地址 (相對地址,比如: data/obj/image1.jpg)

         ---- test.txt          # 存在訓練集地址 (相對地址,比如: data/obj/image3.jpg)

我分別介紹一個data文件夾下五個文件或文件夾的作用以及格式:

(1) obj.names 該文件中保存的是檢測物體的名稱。假設有一個安全帽檢測的項目,檢測有沒有戴安全帽。沒有戴安全帽的標籤是people,戴安全帽的標籤是hat。那麼obj.names文件中就這樣寫:

people
hat

每一類名稱獨佔一行,這樣是爲了方便讀取文件中的內容,我們只需要通過換行符就可以輕鬆分割並讀取obj.names中每個類別的名稱。

(2) obj.data  該文件中保存着五類信息:類別數量,訓練集,驗證集,類別名稱和保存權重的文件

classes= 2                        # 2表示數據集中只有兩類可檢測的物體
train  = data/train.txt           # 表示保存訓練數據集的地址
test= data/test.txt            # 表示保存驗證數據集的地址
names = data/obj.names            # 表示可檢測物體的名稱
backup = backup/                  # 表示保存訓練權重的文件

obj.data文件其實就是一個彙總文件,yolov4需要的數據集地址,數據集標籤以及信息的時候就是從這個文件中得到的。該文件涉及的內容在上下文都有涉及,這裏就不再贅述。

(3) obj  該文件夾中存放着整個數據集(訓練集和驗證集)的圖片(.jpg格式)以及它們的標籤(.txt)文件。也就是說每一張圖片都對應一個txt標籤文件。比如image1.jpg圖片對應的標籤文件就是image1.txt文件。將數據集圖片和標籤放在一起有一個好處就是,我們不需要單獨將圖片和標籤放在不同的文件夾下,只需要提供一個文件路徑,得到所有的.jpg圖片之後將其後綴改成.txt就可以得到相應的標籤文件,這樣做方便有簡潔。

每個標籤文件中包含如下五個信息:

   <object-class>  <x_center>  <y_center>  <width>  <height>

object-class: 表示物體的數字標籤。比如0, 1, 2等整數。

<x_center>  <y_center>  <width>  <height>: 表示物體的相對中心座標及其相對寬高(這四個值的大小在0-1之間)。

舉例來說:

<x_center> = <absolute_x> / <image_width> = bounding box中心x實際座標 / 圖片實際寬度

<y_center> = <absolute_y> / <image_height> = bounding box中心y實際座標 / 圖片實際高度

<width> = <absolute_width> / <image_width> = bbox寬度 / 圖片實際寬度

<height> = <absolute_width> / <image_width> = bbox高度 / 圖片實際高度

如果一幅圖片中包含不止一個物體,那麼每幅圖片的標籤信息應該如何填寫?舉例來說,對於image1.jpg圖片有三個物體,image1.txt文件就是這樣:

1 0.716797 0.395833 0.216406 0.147222
0 0.687109 0.379167 0.255469 0.158333
1 0.420312 0.395833 0.140625 0.166667

(4) train.txt  該文件中保存着所有訓練集的相對地址。比如:

data/obj/img1.jpg
data/obj/img2.jpg
data/obj/img3.jpg

(5) test.txt 該文件中保存着所有驗證集的相對地址。比如:

data/obj/img11.jpg
data/obj/img21.jpg
data/obj/img31.jpg

到這,數據集的搭建就已經完成了。下面我們需要對yolov4的配置文件進行修改。

 

3 修改配置文件

(1) 複製yolov4.cfg文件將其重命名爲yolov4-obj.cfg。這樣就不會對原始文件進行修改。

(2) 修改yolov4-obj.cfg如下內容:

# step1: 修改batch和subdivisions
L2: batch=64                # 原來就是64,根據gpu自己選擇
L3: subdivisions=16         # 原來是8,根據自己的gpu選擇

# step2: 修改圖片的尺寸
L7: width=608               # 這邊我就不進行修改了
L8: height=608              # 這邊我也不修改

# step3: 修改classes(每個yolo層都需要修改一次,一共需要修改三次)
L968: classes=2             # 我只需要識別兩類物體,因此需要修改成2
L1056: classes=2
L1144: classes=2

# step4: 需要修改每個yolo相鄰的上一個convolution層的filter
L961: filters=21            # 因爲我預測兩類物體:21 = 3*(5+2)
L1049: filters=21
L1137: filters=21

 

4 修改makefile文件

darknet使用c語言編寫的,因此我們需要對其進行編譯。在編譯之前我們需要修改makefile文件,並修改如下內容:

(1) GPU=1: 表示在訓練的時候使用CUDA進行加速訓練(CUDA應該在 /usr/local/cuda文件夾下)

(2) CUDNN=1: 表示在訓練的過程中使用CUDNN v5-v7進行加速(cuDNN應該在 /usr/local/cudnn文件夾下)

(3) CUDNN_half=1: 爲Tensor Cores (在Titan V / Tesla V100 / DGX-2等)上進行加速訓練和推理。

(4) OPENCV=1: 編譯OpenCV 4.x/3.x/2.4.x等。OpenCV可以讀取視頻或者圖片。

(5) DEBUG=1: 編譯debug版本的Yolo

(6) OPENMP=1:使用OpenMP進行編譯,能夠使用多核的CPU進行加速

(7) LIBOS=1: 編譯構建darknet.so動態庫。

(8) ZED_CAMREA=0: 置爲1的時候表示構建ZED-3D-camera的庫。這裏我們不使用

 

5 配置OpenCV

這裏參考了這位老哥的博客

(1) 下載相關庫文件

# step1
sudo apt-get install build-essential

# step2
sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev

# step3
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev

(2) 安裝cmake

sudo apt-get install cmake

(3) 下載opencv並進行編譯

step1: opencv3.4.9下載地址(選擇sources):https://opencv.org/releases/

step2: 解壓,並且創建build文件夾,對opencv進行編譯(這裏面我是將opencv放在darknet-master文件夾下,然後編譯的)

# step1: 切換到opencv目錄下
cd opencv 

# step2: 創建build文件夾
mkdir build

# step3: 切換到build文件夾
cd build

# step4: 使用camke進行生成CMakeLists文件
cmake -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/usr/local ..

# step5: 使用make命令進行編譯
sudo make -j8

# step6
sudo make install

(4) 將opencv的庫添加到路徑中,從而讓系統能夠找到

# step1: 打開文件
sudo gedit /etc/ld.so.conf.d/opencv.conf 

# step2: 向文件中加上下面命令
export /usr/local/

# step3: 讓動戴鏈接庫爲系統所享
sudo ldconfig 

# step4: 配置bashrc
sudo gedit /etc/bash.bashrc 

# step5: 在文件中加上下面兩行命令
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
export PKG_CONFIG_PATH  

# step6: 最後再終端中source一下
source /etc/bash.bashrc

(5) 最後,我們需要編譯darknet

darknet是使用c語言開發的框架,如果要使用的話,我們需要對其進行編譯。具體操作就是打開終端,然後轉到darnet-master文件夾下,輸入make進行編譯就可以了。

# step1: 轉到darknet所在的文件夾
cd darknet-master

# step2: 使用make進行編譯
make

這時候你會發現文件夾下會多出來一些東西,比如darknet可執行文件,backup文件等。我們通過運行darknet就可以進行訓練或者檢測,backup是存放我們訓練權重的文件夾。

 

6 進行訓練

(1) 下載預訓練權重: yolov4.conv.137

(2) 執行下面命令:

./darknet detector train data/obj.data cfg/yolov4-obj.cfg yolov4.conv.137 -map

(3) 在訓練的過程中,darknet會自動保存權重文件

  • backup文件夾下的yolo-obj_last.weights文件會每隔100個iterations保存一次,新的會替代舊的
  • backup文件夾下的yolo-obj_xxxx.weights文件會每隔1000個iterations保存一次

darknet總的訓練步長可以在yolov4-obj.cfg文件中修改max_batches的大小(默認max_batches = 500500)

 

7 什麼時候該停止訓練

隨着訓練的進行,不可避免的會出現過擬合現象的發生,那我們什麼時候應該停止訓練呢?

通常來說每一類都要充分訓練2000個iterator,而且不少於訓練集中圖片的數量,總共不應小於6000個iterations。但是爲了獲得一個更好的訓練精度,你應該手動停止訓練,停止的時機可以參考下面;

(1) 在訓練的過程中,你會看到各種各樣的指標,當0.xxxxxxx avg不再變化的時候,你就應該停止訓練

  • 9002:表示當前的iteration

  • 0.600730:表示平均的損失函數(越小越好

當你觀察到平均損失函數(average loss)0.xxxxxxx avg不再變化的時候,你就應該停止訓練。最終的平均損失函數在0.5(對於小的模型、簡單的數據集)到3.0(對於較大的模型、複雜的數據集)之間。

或者當你在終端中加上 -map 參數的時候,你就會看到mAP指標,Last accuracy [email protected] = 18.50%,這個指標比損失函數作爲指標要合適的多,因此在訓練的過程中mAP不斷增加,你就應該繼續進行訓練。

(2) 一旦你停止了訓練,你就應該在backup文件夾中選擇最合適的權重。

舉例來說,如果你在9000 iterations停止訓練,但是最好的模型在7000, 8000, 9000之間,而且不確定會不會產生過擬合,因此你需要找到提前停止訓練的點(Early Stopping Point)。

首先,準備驗證集。你需要在 obj.data中將valid  = data/test.txt 修改成 valid  = data/valid.txt (valid.txt的格式和train.txt的合適一樣),如果你沒有驗證集,你可以直接將train.txt的內容直接複製到valid.txt文件中。

其次,對候選的權重測試mAP。如果你是在9000 iterations停止訓練的,你就需要對之前保存的權重進行測試。

# step1: 測試7000 iterations的mAP
./darknet detector map data/obj.data yolo-obj.cfg backup\yolo-obj_7000.weights

# step2: 測試8000 iterations的mAP
./darknet detector map data/obj.data yolo-obj.cfg backup\yolo-obj_8000.weights

# step3: 測試9000 iterations的mAP
./darknet detector map data/obj.data yolo-obj.cfg backup\yolo-obj_9000.weights

然後選擇一個mAP最高的權重作爲最優的訓練權重。

(3) 當然,你也可以在訓練的時候就顯示mAP,然後根據訓練過程圖選擇最合適的權重(上文使用的就是這樣方式)

由上圖所示,我們可以選擇8000 iteration的權重作爲最終的訓練權重。

 

8 進行檢測

訓練好權重之後,我們可以使用權重進行檢測,在終端中輸入下面命令就行:

./darknet detector detect cfg/yolov4.cfg backup/yolov4.weights data/dog.jpg

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章