DarkNet-YOLOv3 訓練自己的數據集 Ubuntu16.04+cuda8.0

  • 配置DarkNet

參考YOLO官網

(1)安裝相關依賴項(可選)

  1. opencv:參考教程
  2. cuda:參考教程

(2)下載源碼:

git clone https://github.com/pjreddie/darknetcd darknet

(3)更改Makefile文件:

vim Makefile

如果用GPU運行:

GPU=1

如果安裝了CUDNN:

CUDNN=1NVCC=/usr/local/cuda-8.0/bin/nvcc

如果安裝了opencv:

OPENCV=1

(4)編譯

make

配置完以後可以下載作者的預訓練模型測試一下:

wget https://pjreddie.com/media/files/yolov3.weights

下載之後用圖片進行測試:

./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg

一切正常的話會輸出測試圖片的檢測結果:


  • 用自己打數據集進行訓練

(1)數據集處理

我做的項目是檢測水面上的物體,一共5類:客船、貨船、小船、帆船、浮標,每類大概500張圖,並且我用類似labelimg的工具對圖片進行了標註,這裡附上大神的labelimg的github鏈接。需要的可以自行下載使用。

用標註工具標註完圖片,先將數據集準備成類似VOC的格式,需要三個文件夾中的兩個。JPEGImages:用於存放所有的圖片,格式為.jpg ; Annotations:用於存放與圖片對應的XML文件。

(2)生成訓練所需要的txt文件

用YOLO訓練時候需要一些txt文件,以我的項目為例,有tarin.txt, val.txt, boat_train.txt, boat_val.txt.還有一個labels文件夾,裡面裝著每張圖片對應的txt文件,名字與圖片命名相同。下面分別說明一下這些txt文件的生成方式以及裡面的內容。

train.txt:存放用於訓練的圖片的名字,每行一個名字(不帶後綴.jpg)。

val.txt:存放用於驗證的圖片的名字,每行一個名字(不帶後綴.jpg)。

boat_train.txt:存放用於訓練的圖片的絕對路徑,每行一個路徑。

boat_val.txt:存放用於驗證的圖片的絕對路徑,每行一個路徑。

labels文件夾的txt:每個文件存放的是對應圖片的標註信息,每行一個目標,若有多行則表示讀應圖片上有多個目標。

下面給一段能利用train.txt,val.txt以及xml文件來生成boat_train.txt,boat_val.txt以及labels文件夾下所有txt文件的python代碼,我直接用voc_label.py改的,改的比較粗糙:

import xml.etree.ElementTree as ETimport pickleimport osfrom os import listdir, getcwdfrom os.path import join#我的項目中有5個類別,類別名稱在這裡修改classes = ["ship","cargoboat","boat","sailboat","buoy"]def convert(size, box): dw = 1./size[0] dh = 1./size[1] x = (box[0] + box[1])/2.0 y = (box[2] + box[3])/2.0 w = box[1] - box[0] h = box[3] - box[2] x = x*dw w = w*dw y = y*dh h = h*dh return (x,y,w,h)def convert_annotation(image_id): #這裡改為xml文件夾的路徑 in_file = open(/home/wlin/darknet/boat_detect/Annotations/%s.xml%(image_id)) #這裡是生成每張圖片對應的txt文件的路徑 out_file = open(/home/wlin/darknet/boat_detect/labels/%s.txt%(image_id),w) tree=ET.parse(in_file) root = tree.getroot() size = root.find(size) w = int(size.find(width).text) h = int(size.find(height).text)# for obj in root.iter(object): cls = obj.find(name).text if cls not in classes : continue cls_id = classes.index(cls) xmlbox = obj.find(bndbox) b = (float(xmlbox.find(xmin).text), float(xmlbox.find(xmax).text), float(xmlbox.find(ymin).text), float(xmlbox.find(ymax).text)) bb = convert((w,h), b) out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) +
)#這裡是train.txt文件的路徑image_ids_train = open(/home/wlin/darknet/boat_detect/train.txt).read().strip().split() #這裡是val.txt文件的路徑image_ids_val = open(/home/wlin/darknet/boat_detect/val.txt).read().strip().split() list_file_train = open(boat_train.txt, w) list_file_val = open(boat_val.txt, w) for image_id in image_ids_train: #這裡改為樣本圖片所在文件夾的路徑 list_file_train.write(/home/wlin/darknet/boat_detect/JPEGImages/%s.jpg
%(image_id)) convert_annotation(image_id) list_file_train.close()for image_id in image_ids_val: #這裡改為樣本圖片所在文件夾的路徑 list_file_val.write(/home/wlin/darknet/boat_detect/JPEGImages/%s.jpg
%(image_id)) convert_annotation(image_id) list_file_val.close()

(3)兩個很重要的文件夾的放置位置

這裡指的是JPEGImages(存放樣本圖片)與labels(與每張圖片對應的txt文件),建議這兩個文件夾放在同一個目錄下,因為好像代碼裡面是在同一個目錄下搜索這兩個文件夾,然後就是名字也最好別變,不然可能需要修改相應代碼。

(4)修改相應文件

1.在項目目錄下建立一個.names文件(也可以把data文件夾中的voc.names複製過來修改並重命名),比如我的叫做boat_voc.names,裡面存放類別名,每行存一個。

2.把cfg文夾中的voc.data複製到自己項目目錄下,改名為boat_voc.data,並修改:

classes= 5 #類別數train = /home/wlin/darknet/boat_detect/boat_train.txt #boat_train.txt路徑valid = /home/wlin/darknet/boat_detect/boat_val.txt #boat_val.txt路徑names = /home/wlin/darknet/boat_detect/boat_voc.names #boat_voc.names路徑backup = /home/wlin/darknet/boat_detect/backup/ #建一個backup文件夾用於存放中間結果

3.把cfg文夾中的yolov3-voc.cfg複製到自己項目目錄下,並修改:

[net]# Testing# batch=1# subdivisions=1 #訓練時候把上面Testing的參數注釋# Trainingbatch=64subdivisions=32 #這個參數根據自己GPU的顯存進行修改,顯存不夠就改大一些... #因為訓練時每批的數量 = batch/subdivisions......learning_rate=0.001 #根據自己的需求還有訓練速度學習率可以調整一下burn_in=1000max_batches = 30000 #根據自己的需求還有訓練速度max_batches可以調整一下policy=stepssteps=10000,20000 #跟著max_batches做相應調整.........[convolutional]size=1stride=1pad=1filters=30 #filters = 3*(classes + 5)activation=linear[yolo]mask = 0,1,2anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326classes=5 #修改類別數num=9jitter=.3ignore_thresh = .5truth_thresh = 1random=1 #顯存小的話 =0#這個文件的最下面有3個YOLO層,這裡我才放上來了一個,這三個地方的classes做相應修改#每個YOLO層的上一層的convolutional層的filters也要修改

4.下載預訓練模型(權重)

在項目目錄下打開終端,運行命令:

wget https://pjreddie.com/media/files/darknet53.conv.74

5.訓練

到此,訓練所需的文件就準備好了,可以嘗試著開始訓練,在darknet目錄下執行:

./darknet detector train boat_detect/boat_voc.data boat_detect/yolov3-voc.cfg darknet53.conv.74

這個命令可能跟大多數博主的不同,原因是我沒有直接更改一些文件,而是把他們複製出來放在我的項目目錄里重命名後再修改,我的項目文件夾是boat_detect,根據你們自己的文件夾在相應地方做修改,我覺得這樣做能避免下次使用時候重複修改相同的文件,造成混亂。

  • 測試自己訓練的模型

我的訓練集有大概2500圖片,顯卡是1080,max_batch = 30000,訓練了40多個小時把模型訓練出來了,最後的模型存在 /backup目錄下。

(1)單張圖片測試:

在darknet目錄下打開終端,運行:

./darknet detector test ./boat_detect/boat_voc.data ./boat_detect/yolov3-voc.cfg ./boat_detect/backup/yolov3-voc_30000.weights ./boat_detect/test_data/test_img.jpg

效果還是挺好的:


  • 遇到的問題與解決方案

./darknet: error while loading shared libraries: libcudnn.so.6.0: cannot open shared object file: No such file or directory

網站上搜索了一下大多數博主的解釋是libcudnn.so.6.0的許可權問題,需要刪除軟鏈接後修改許可權再次建立新打軟鏈接,可參考這篇教程。

我跟同學討論後的解決方案比較粗暴:

(1)改變libcudnn.so.6.0的許可權(我這裡給了所有許可權,可以根據自己需要調整):

cd /usr/local/cuda/lib64/sudo chmod 777 libcudnn.so.6.0

(2)把libcudnn.so.6.0的路徑添加到bashrc中:

sudo vim ~/.bashrc

在最下面添加libcudnn.so.6.0的路徑:

export LD_LIBRARY_PATH=/usr/local/cuda/lib64/

(3)跟新下bashrc,然後就能運行了:

sudo source ~/.bashrc

推薦閱讀:

機器學習技法筆記3:核函數SVM
鋼鐵直男的救世主來了!讓AI告訴你妹子到底是啥意思
機器學習基本套路
《淺談人工智慧:現狀、任務、構架與統一》·第二期
基於信息瓶頸的空間聚類(一)

TAG:深度學習DeepLearning | 計算機視覺 | 機器學習 |