1. 程式人生 > >YOLO---Darknet下的學習筆記

YOLO---Darknet下的學習筆記

重要 for art self 後臺進程 pandas 數字 his loading

YOLO.V3-Darknet下的學習筆記

wp20180927

【目錄】

一、 安裝Darknet(僅CPU下) 2

1.1在CPU下安裝Darknet方式 2

1.2在GPU下安裝Darknet方式 4

二、 YOLO.V3訓練官網數據集(VOC數據集/COCO數據集) 4

2.1下載VOC數據集/COCO數據集 4

2.2下載預訓練的模型(.weights文件) 8

三、 YOLO.V3訓練自己的數據集(以3類別的為例) 8

3.1制作自己的VOC格式訓練集 8

3.1.1圖像(.jpg)進行重命名(00000X.jpg) 9

3.1.2制作圖像的.xml文件 11

3.1.3將.xml文件轉換成.txt文件【表述圖像及框的四點坐標信息】 14

3.1.4將.jpg文件轉換成.txt文件【訓練、測試、驗證數據集的路徑】 15

3.2訓練網絡 17

3.3測試 19

3.4計算準確率 20

3.5問題匯集 20

四、 YOLO.V3的可視化 20

4.0格式化訓練的日誌文件logextract_log.py腳本 21

4.1可視化訓練日誌中的loss(train_loss_visualization.py腳本 21

4.2可視化訓練日誌中的參數(train_iou_visualization.py腳本 24

【正文】

一、安裝Darknet(僅CPU下)

安裝環境:Ubuntu18.04

內存:3.9GiB,處理器:Intel? Core?2 Duo CPU E7500 @ 2.93GHz × 2 

圖形:Intel? Core?2 Duo CPU E7500 @ 2.93GHz × 2

GNOME:3.28.3

操作系統:64位

磁盤:492GB.

【說明:以下安裝主要參考YOLO官網https://pjreddie.com/darknet/yolo/ 】

1.1在CPU下安裝Darknet方式

官網安裝:https://pjreddie.com/darknet/install/Darknet

安裝相對caffe來說非常簡單。Opencv和cuda作為選裝的部分,可以不安裝。推薦安裝這兩個,只有安裝的cuda才能使用gpu。提示:只有安裝了opencv才能調用攝像頭進行實時檢測。

Opencv和cuda的安裝方法,可以參考安裝caffe時的安裝方法:可以是自己以前安裝Caffe時安裝Opencv的方法,也可以參考 http://blog.csdn.net/vvyuervv/article/details/60755653者 https://blog.csdn.net/samylee/article/details/51684856/ 。

Darknet的安裝簡單來說就三個步驟:下載安裝包+修改Makefile文件+編譯。

(1)下載安裝包:

使用命令行下載的命令:git clone https://github.com/pjreddie/darknet.git。

當然也可以直接輸入網址進行下載: https://github.com/pjreddie/darknet.git

(2)修改Makefile文件:

下載之後打開文件夾裏的Makefile文件,如果安裝了opencv和cuda,則將Makefile文件中的GPU和OPENCV修改成1 (GPU=1,OPENCV=1)。如果沒有安裝opencv和cuda就不需要進行修改之後就是對安裝包進行編譯了。提示:安裝opencv需要聯網,耗時較長。

我自己使用CPU+opencv,所以修改CPU=0,opencv=1。

(3)編譯make。

使用命令cd到文件根目錄下make這樣就可以了,沒有安裝opencv和cuda的情況下編譯很快,安裝了的編譯時稍等一會兒。安裝過caffe的都知道,編譯過程中經常會出現錯誤。不過編譯darknet時不用擔心。

$ cd darknet

$ make

(4)測試YOLO-Darknet

測試yolov3.weights模型。將訓練得到的weights文件拷貝到darknet/weights文件夾下面,執行語句:

$ wget https://pjreddie.com/media/files/yolov3.weights #下載模型

$ cd darknet

$ ./darknet detect cfg/yolov3-voc.cfg weights/yolov3.weights data/dog.jpg

也可以執行:

$ wget https://pjreddie.com/media/files/yolov3.weights #下載模型

$ cd darknet

$ ./darknet detect cfg/yolov3-voc.cfg weights/yolov3.weights

終端下,過一會兒會顯示

Loading weights from weights/yolov3.weights...Done!

Enter Image Path: data/person.jpg

data/person.jpg: Predicted in 26.276781 seconds.

備註:這裏可能會報錯

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

處理方法:

darknet目錄下先meak clean清除掉原有編譯文件,然後sudo ldconfig然後make一下後重新輸入:

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

便可成功運行。

運行成功後會出現下面的圖片,並在darknet目錄下生成predictions.png文件

(5)訓練測試YOLO-Darknet(這裏是繼續訓練)

$ cd darknet

$ ./darknet detector train VOC/cfg/voc.data VOC/cfg/yolov3-voc.cfg VOC/darknet53.conv.74

1.2在GPU下安裝Darknet方式

(1)下載安裝包。(2)修改GPU=1。(3)make編譯一下。

二、YOLO.V3訓練官網數據集(VOC數據集/COCO數據集)

2.1下載VOC數據集/COCO數據集

下載數據集

新建文件夾VOC:/home/wp/darknet/VOC,在VOC文件夾下下載數據集:

wget https://pjreddie.com/media/files/VOCtrainval_11-May-2012.tar

wget https://pjreddie.com/media/files/VOCtrainval_06-Nov-2007.tar

wget https://pjreddie.com/media/files/VOCtest_06-Nov-2007.tar

tar xf VOCtrainval_11-May-2012.tar

tar xf VOCtrainval_06-Nov-2007.tar

tar xf VOCtest_06-Nov-2007.tar

請,參考官網例子https://pjreddie.com/darknet/yolo/ 下的”Training YOLO on VOC”

There will now be a VOCdevkit/ subdirectory with all the VOC training data in it.

Generate Labels for VOC

Now we need to generate the label files that Darknet uses. Darknet wants a .txt file for each image with a line for each ground truth object in the image that looks like:

<object-class> <x> <y> <width> <height>

Where x, y, width, and height are relative to the image‘s width and height. To generate these file we will run the voc_label.py script in Darknet‘s scripts/ directory. Let‘s just download it again because we are lazy.

$ wget https://pjreddie.com/media/files/voc_label.py

$ python voc_label.py

After a few minutes, this script will generate all of the requisite files. Mostly it generates a lot of label files in VOCdevkit/VOC2007/labels/ and VOCdevkit/VOC2012/labels/. In your directory you should see:

$ ls

2007_test.txt VOCdevkit

2007_train.txt voc_label.py

2007_val.txt VOCtest_06-Nov-2007.tar

2012_train.txt VOCtrainval_06-Nov-2007.tar

2012_val.txt VOCtrainval_11-May-2012.tar

The text files like 2007_train.txt list the image files for that year and image set. Darknet needs one text file with all of the images you want to train on. In this example, let‘s train with everything except the 2007 test set so that we can test our model. Run:

$ cat 2007_train.txt 2007_val.txt 2012_*.txt > train.txt

Now we have all the 2007 trainval and the 2012 trainval set in one big list. That‘s all we have to do for data setup!

Modify Cfg for Pascal Data

Now go to your Darknet directory. We have to change the cfg/voc.data config file to point to your data:

$ classes= 20

$ train = <path-to-voc>/train.txt

$ valid = <path-to-voc>2007_test.txt

$ names = data/voc.names

$ backup = backup

You should replace <path-to-voc> with the directory where you put the VOC data.

Download Pretrained Convolutional Weights

For training we use convolutional weights that are pre-trained on Imagenet. We use weights from the darknet53 model. You can just download the weights for the convolutional layers here (76 MB).

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

Train The Model

Now we can train! Run the command:

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

自己的詳細步驟如下:

(1)下載VOC數據集並解壓

$ cd /home/wp/darknet/VOC

wget https://pjreddie.com/media/files/VOCtrainval_11-May-2012.tar

wget https://pjreddie.com/media/files/VOCtrainval_06-Nov-2007.tar

wget https://pjreddie.com/media/files/VOCtest_06-Nov-2007.tar

tar xf VOCtrainval_11-May-2012.tar

tar xf VOCtrainval_06-Nov-2007.tar

tar xf VOCtest_06-Nov-2007.tar

VOC數據集的文件夾詳細介紹:

(2)制作.jpg數據集的.txt文件

$ cd darknet/VOC

$ wget https://pjreddie.com/media/files/voc_label.py

$ python voc_label.py

執行完後,生成2007_test.txt;2007_train.txt;2007_val.txt;2012_train.txt;2012_val.txt

(3) 修改 cfg/voc.data文件裏的路徑

classes= 20

train = /home/wp/darknet/VOC/train.txt

valid = /home/wp/darknet/VOC/2007_test.txt

names = /home/wp/darknet/VOC/data/voc.names

backup = /home/wp/darknet/backup

2.2下載預訓練的模型(.weights文件)

(1)訓練

1.在已訓練好的模型上繼續訓練:

$ cd darknet

$ wget https://pjreddie.com/media/files/darknet53.conv.74 #先下載模型,再使用

$ ./darknet detector train VOC/cfg/voc.data VOC/cfg/yolov3-voc.cfg VOC/darknet53.conv.74

2.自己重新訓練

為方便後面的可視化,這裏最好保存訓練的日誌。

$ ./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg 2>&1 | tee visualization/train_yolov3.log

說明:下載可以執行語句執行(wget+網址鏈接),也可以手動下載(到網頁下載)。

三、YOLO.V3訓練自己的數據集(以3類別的為例)

3.1制作自己的VOC格式訓練集

核心思想:仿照VOC數據集的文件夾及其格式進行制作。

--VOC

--Annotations

--ImageSets

--Main

--Layout

--Segmentation

--JPEGImages

--SegmentationClass

--SegmentationObject

  說明:這裏面用到的文件夾是Annotation、ImageSets和JPEGImages。其中文件夾Annotation中主要存放xml文件,每一個xml對應一張圖像,並且每個xml中存放的是標記的各個目標的位置和類別信息,命名通常與對應的原始圖像一樣;而ImageSets我們只需要用到Main文件夾,這裏面存放的是一些文本文件,通常為train.txt、test.txt等,該文本文件裏面的內容是需要用來訓練或測試的圖像的名字(無後綴無路徑);JPEGImages文件夾中放我們已按統一規則命名好的原始圖像。

因此,需要:

1.新建文件夾VOC2007(通常命名為這個,也可以用其他命名,但一定是名字+年份,例如MYDATA2016,無論叫什麽後面都需要改相關代碼匹配這裏,本例中以VOC2007為例)

2.在VOC2007文件夾下新建三個文件夾Annotation、ImageSets和JPEGImages,並把準備好的自己的原始圖像放在JPEGImages文件夾下

3.在ImageSets文件夾中,新建三個空文件夾Layout、Main、Segmentation,然後把寫了訓練或測試的圖像的名字的文本拷到Main文件夾下,按目的命名,我這裏所有圖像用來訓練,故而Main文件夾下只有train.txt文件。上面說的小代碼運行後會生成該文件,把它拷進去即可。

3.1.1圖像(.jpg)進行重命名(00000X.jpg)

方法:用python、C++、MATLAB等寫一個重命名的腳本,批量修改。也可以借助美圖秀秀、ACDsee工具修改。

結果:在/home/wp/darknet/wp_data/VOCdevkit/VOC2012/JPEGImages文件夾下產生一系列重命名的00000x.jpg圖像。

可以參考網址https://blog.csdn.net/u011574296/article/details/72956446。

首先準備好自己的數據集,最好固定格式,此處以VOC為例,采用jpg格式的圖像,在名字上最好使用像VOC一樣類似000001.jpg、000002.jpg這樣。

本文用的是images_rename_001.py,內容如下:

=====================================================

# -*- coding: utf-8 -*-

#!/usr/bin/python

import os

path = "/home/wp/darknet/wp_data/VOCdevkit/VOC2012/JPEGImages"

filelist = os.listdir(path) #該文件夾下所有的文件(包括文件夾)

count=0

for file in filelist:

print(file)

for file in filelist: #遍歷所有文件

Olddir=os.path.join(path,file) #原來的文件路徑

if os.path.isdir(Olddir): #如果是文件夾則跳過

continue

filename=os.path.splitext(file)[0] #文件名

filetype=os.path.splitext(file)[1] #文件擴展名

Newdir=os.path.join(path,str(count).zfill(6)+filetype) #用字符串函數zfill,以0補全所需位數

os.rename(Olddir,Newdir) #重命名

count+=1

====================================================

Matlab版本

%%

%圖片保存路徑為:

%E:\image\car

%E:\image\person

%car和person是保存車和行人的文件夾

%這些文件夾還可以有多個,

%放在image文件夾裏就行

%該代碼的作用是將圖片名字改成000123.jpg這種形式

%%

clc;

clear;

maindir=‘E:\image\‘;

name_long=6; %圖片名字的長度,如000123.jpg為6,最多9位,可修改

num_begin=1; %圖像命名開始的數字如000123.jpg開始的話就是123

subdir = dir(maindir);

n=1;

for i = 1:length(subdir)

if ~strcmp(subdir(i).name ,‘.‘) && ~strcmp(subdir(i).name,‘..‘)

subsubdir = dir(strcat(maindir,subdir(i).name));

for j=1:length(subsubdir)

if ~strcmp(subsubdir(j).name ,‘.‘) && ~strcmp(subsubdir(j).name,‘..‘)

img=imread([maindir,subdir(i).name,‘\‘,subsubdir(j).name]);

imshow(img);

str=num2str(num_begin,‘%09d‘);

newname=strcat(str,‘.jpg‘);

newname=newname(end-(name_long+3):end);

system([‘rename ‘ [maindir,subdir(i).name,‘\‘,subsubdir(j).name] ‘ ‘ newname]);

num_begin=num_begin+1;

fprintf(‘當前處理文件夾%s‘,subdir(i).name);

fprintf(‘已經處理%d張圖片\n‘,n);

n=n+1;

pause(0.1);%可以將暫停去掉

end

end

end

end

==================================

3.1.2制作圖像的.xml文件

方法:借助LabelImg工具,手動制作。說明:因為是一張張的手動制作,數據集大的話,需要一定的時間。

結果:在/home/wp/darknet/wp_data/VOCdevkit/VOC2012/Annotations文件夾下產生一系列與圖像名稱相對應的0000xx.xml文件。

可以參考網址https://blog.csdn.net/xunan003/article/details/78720189,來實現標記圖像目標區域。

(1)下載labelImg-master.zip並解壓

方式1:下載地址https://github.com/tzutalin/labelImg。

方式2:使用git命令

git clone https://github.com/tzutalin/labelImg

下載後是自動在home目錄下解壓好的,文件名為LabelImg,裏面的內容同上圖。

(2)labelImg安裝

$ sudo apt-get install pyqt4-dev-tools  #安裝PyQt4

$ sudo pip install lxml      #安裝lxml,如果報錯,可以試試下面語句

$ sudo apt-get install python-lxml #然後打開終端,進入LabelImg目錄後使用make編譯

不出錯誤的話,繼續執行:

$ cd LabelImg

$ make all

(3)

labelImg使用

labelImg目錄下使用終端執行:

$ python labelImg.py

3.1快捷鍵

Ctrl + u 加載目錄中的所有圖像,鼠標點擊Open dir同功能

Ctrl + r 更改默認註釋目標目錄(xml文件保存的地址)

Ctrl + s 保存

Ctrl + d 復制當前標簽和矩形框

space 將當前圖像標記為已驗證

w 創建一個矩形框

d 下一張圖片

a 上一張圖片

del 刪除選定的矩形框

Ctrl++ 放大

Ctrl-- 縮小

↑→↓← 鍵盤箭頭移動選定的矩形框

3.2具體事項

  想要修改圖2中的標簽類別內容(如默認的dog、person、cat等)則在主目錄下data文件夾中的predefined_classes.txt文件中修改。

  使用時,使用ctrl+u快捷鍵加載圖片後,使用ctrl+r快捷鍵指定生成的xml文件的保存位置,然後開始按照類別將圖片中的目標進行矩形框標註,每標註一個目標後軟件自動彈出類別信息以供選擇,在彈出的類別信息中選擇對應的類別名稱雙擊即可。當一張圖片中各個類別所需要標註的目標全部標註後,點擊保存按鍵或者使用ctrl+s快捷鍵保存就生成了相對應的xml位置信息文件,此時可以開始下一張圖片的標註。

3.3註意

現在github上更新的最新版本可能在某些使用較久的老電腦上無法使用,原因不知,如遇到新版本無法使用,請首先考慮使用labelImg的老版本使用(老版本地址:http://pan.baidu.com/s/1b5qyke密碼:jkz0),我們這裏提供百度雲地址。另外,老版本中在4當中提到的某些快捷鍵無法使用,請用鼠標點擊使用相同功能。另外,如果.xml文件裏filename中的文件名沒有.jpg後綴,則需要統一加上後綴.jpg。只需一段命令即可find -name ‘*.xml‘ |xargs perl -pi -e ‘s|</filename>|.jpg</filename>|g‘ 。在對應目錄下執行即可,這樣就可以把後綴添上。這樣就做按照VOC做好了我們的數據集,接下來就是放到算法中去訓練跑起來。

(4)Labelimg窗口的使用方法:

? 修改默認的XML文件保存位置,可以用“Ctrl+R”,改為自定義位置,這裏的路徑不能包含中文,否則無法保存。

? 源碼文件夾中使用notepad++打開data/predefined_classes.txt,可以修改默認類別,比如改成bus、car、building三個類別。

?“Open Dir”打開需要標註的樣本圖片文件夾,會自動打開第一張圖片,開始進行標註

? 使用“Create RectBox”開始畫框

? 完成一張圖片後點擊“Save”,此時XML文件已經保存到本地了。

? 點擊“Next Image”轉到下一張圖片。

? 標註過程中可隨時返回進行修改,後保存的文件會覆蓋之前的。

? 完成標註後打開XML文件,發現確實和PASCAL VOC所用格式一樣。

每個圖片和標註得到的xml文件,JPEGImages文件夾裏面的一個訓練圖片,對應Annotations裏面的一個同名XML文件,一一對應,命名一致。

標註自己的圖片的時候,類別名稱請用小寫字母,比如汽車使用car,不要用Car

pascal.py中讀取.xml文件的類別標簽的代碼:

cls = self._class_to_ind[obj.find(‘name‘).text.lower().strip()]

寫的只識別小寫字母,如果你的標簽含有大寫字母,可能會出現KeyError的錯誤。

3.1.3將.xml文件轉換成.txt文件【表述圖像及框的四點坐標信息】

方法:寫一個make_xml2txt.py腳本。

結果:/home/wp/darknet/wp_data/VOCdevkit/VOC2012/labels文件夾下產生與圖像名稱相對應的00000x.txt文件,記錄了圖像的類別+畫框的位置坐標信息。

============make_xml2txt.py==================================

import os

import random

trainval_percent = 0.66

train_percent = 0.5

xmlfilepath = ‘/home/wp/darknet/wp_data/VOCdevkit/VOC2012/Annotations‘

txtsavepath = ‘/home/wp/darknet/wp_data/VOCdevkit/VOC2012/ImageSets/Main‘

total_xml = os.listdir(xmlfilepath)

num=len(total_xml)

list=range(num)

tv=int(num*trainval_percent)

tr=int(tv*train_percent)

trainval= random.sample(list,tv)

train=random.sample(trainval,tr)

ftrainval = open(‘/home/wp/darknet/wp_data/VOCdevkit/VOC2012/ImageSets/Main/trainval.txt‘, ‘w‘)

ftest = open(‘/home/wp/darknet/wp_data/VOCdevkit/VOC2012/ImageSets/Main/test.txt‘, ‘w‘)

ftrain = open(‘/home/wp/darknet/wp_data/VOCdevkit/VOC2012/ImageSets/Main/train.txt‘, ‘w‘)

fval = open(‘/home/wp/darknet/wp_data/VOCdevkit/VOC2012/ImageSets/Main/val.txt‘, ‘w‘)

for i in list:

name=total_xml[i][:-4]+‘\n‘

if i in trainval:

ftrainval.write(name)

if i in train:

ftrain.write(name)

else:

fval.write(name)

else:

ftest.write(name)

ftrainval.close()

ftrain.close()

fval.close()

ftest .close()

==============================================

備註:【3.1.2制作圖像的.xml文件】VS【3.1.3將.xml文件轉換成.txt文件】

說明:YOLO-V3 XML和TXT標註文本解釋。

.xml】包含了圖像名稱、圖像路徑、圖像size和深度、標記框的坐標信息

.txt】包含了<object-class> <x> <y> <width> <height>

參考https://blog.csdn.net/qq_34806812/article/details/82355614

3.1.4將.jpg文件轉換成.txt文件【訓練、測試、驗證數據集的路徑】

  方法:利用voc_label.py腳本,修改相應的信息即可為我們所用。

結果:生成了2012_train.txt、2012_test.txt、2012_val.txt等文件,由voc_label.py設置決定。其中xxx_*.txt記錄的是圖像的絕對路徑。

=====================voc_label.py==or==make_jpg2txt.py=======

import xml.etree.ElementTree as ET

import pickle

import os

from os import listdir, getcwd

from os.path import join

#sets=[(‘2012‘, ‘train‘), (‘2012‘, ‘val‘), (‘2007‘, ‘train‘), (‘2007‘, ‘val‘), (‘2007‘, ‘test‘)]

sets=[(‘2012‘, ‘train‘), (‘2012‘, ‘val‘), (‘2012‘, ‘test‘)] ###############

classes = ["person", "dog", "cat"] ########################

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):

in_file = open(‘/home/wp/darknet/wp_data/VOCdevkit/VOC2012/Annotations/%s.xml‘%(image_id))

out_file = open(‘/home/wp/darknet/wp_data/VOCdevkit/VOC2012/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‘):

difficult = obj.find(‘difficult‘).text

cls = obj.find(‘name‘).text

if cls not in classes or int(difficult) == 1:

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]) + ‘\n‘)

#wd = getcwd() #get current path

for image_set in sets:

if not os.path.exists(‘/home/wp/darknet/wp_data/VOCdevkit/VOC2012/labels/‘):

os.makedirs(‘/home/wp/darknet/wp_data/VOCdevkit/VOC2012/labels/‘)

image_ids = open(‘/home/wp/darknet/wp_data/VOCdevkit/VOC%s/ImageSets/Main/%s.txt‘%(image_set)).read().strip().split()

list_file = open(‘/home/wp/darknet/wp_data/VOCdevkit/VOC2012/%s_%s.txt‘%(image_set), ‘w‘)

#list_file = open(‘/home/wp/darknet/wp_data/VOCdevkit/VOC2012/voc_train.txt‘, ‘w‘)

for image_id in image_ids:

list_file.write(‘/home/wp/darknet/wp_data/VOCdevkit/VOC2012/JPEGImages/%s.jpg\n‘%(image_id))

convert_annotation(image_id)

list_file.close()

os.system("cat /home/wp/darknet/wp_data/VOCdevkit/VOC2012/2012_train.txt /home/wp/darknet/wp_data/VOCdevkit/VOC2012/2012_val.txt > /home/wp/darknet/wp_data/VOCdevkit/VOC2012/train.txt")

os.system("cat /home/wp/darknet/wp_data/VOCdevkit/VOC2012/2012_train.txt /home/wp/darknet/wp_data/VOCdevkit/VOC2012/2012_val.txt /home/wp/darknet/wp_data/VOCdevkit/VOC2012/2012_test.txt > /home/wp/darknet/wp_data/VOCdevkit/VOC2012/train_all.txt")

#os.system("cat 2012_train.txt 2012_val.txt > train.txt")

#os.system("cat 2012_train.txt 2012_val.txt 2012_test.txt > train_all.txt")

========================================================

3.2訓練網絡

首先,建立所需的配置文件voc.data、yolov3-voc.cfg、data/voc.names。

(1)建立cfg文件下的voc.data和yolov3-voc.cfg。建立data/voc.names。

可以參考voc數據集裏的voc.data、yolov3-voc.cfg、voc.names,拷貝過來做修改。

(2)修改cfg文件下的voc.data和yolov3-voc.cfg.

第一步:修改voc.data

==================修改voc.data==================

classes= 3  #有幾類就改成幾類

train = /home/wp/darknet/wp_data/VOCdevkit/VOC2012/2012_train.txt

valid = /home/wp/darknet/wp_data/VOCdevkit/VOC2012/2012_test.txt

names = /home/wp/darknet/wp_data/data/voc.names

backup = /home/wp/darknet/wp_data/results

=============================================

第二步:修改yolov3-voc.cfg.

==================修改yolov3-voc.cfg.==================

註意:重點修改幾點

  1. learning_rate、max_batches等參數.
  2. 訓練階段。註釋掉testing,打開train。

[net]

# Testing

#batch=1

#subdivisions=1

# Training

batch=1 ####

subdivisions=1 ####

  1. 共三個yolo層都要改,yolo層中的class為類別數,每一個yolo層前的conv層中的filters =(類別+5)* 3,電腦內存不夠的話設置random=0。

類似這樣的位置3處。

[convolutional]

size=1

stride=1

pad=1

filters=24 ###75

activation=linear

[yolo]

mask = 0,1,2

anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326

classes=3 ###20

num=9

jitter=.3

ignore_thresh = .5

truth_thresh = 1

random=0 ###1

=============================================

第三步:修改voc.names.

==================修改voc.names==================

person

dog

cat

改成自己的類別。也可以把類別設置成簡單的1、2、3.....等。

=============================================

接著,開始訓練。

在終端下開始執行:

$ cd darknet

$ ./darknet detector train wp_data/cfg/voc.data wp_data/cfg/yolov3-voc.cfg 2>&1 | tee wp_data/visualization/train_yolov3.log #保存訓練日誌

或者

$ ./darknet detector train wp_data/cfg/voc.data wp_data/cfg/yolov3-voc.cfg #不保存訓練日誌

或者

$ nohup ./darknet detector train cfg/voc_birds.data cfg/yolov3-voc-birds.cfg darknet53.conv.74 2>1 | tee visualization/train_yolov3_birds.log &

其中,

nohup $ 是防止因為ssh斷開而中斷服務器的進程(如果出現“找不到nohup文件”的錯誤,去掉命令中的“nohup ... &”)

2>1 | tee visualization/train_yolov3_birds.log 是為了保留訓練中的log,為了後續繪制loss曲線。

訓練完後的權重文件,weights應該保存到了darknet/backup下,其中保存的這個模型可以用於繼續訓練。(還沒跑完過,待驗證)

3.3測試

訓練好後可以在backup看到權重文件,嘗試test前要修改cfg文件,切換到test模式:

==================修改yolov3-voc.cfg.==================

測試階段。註釋掉train,打開testing。

[net]

# Testing

batch=1

subdivisions=1

# Training

# batch=1 ####

# subdivisions=1 ####

===================================================

開始測試:

$ ./darknet detector test cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc.weights

執行後,測試集裏的圖片會一張張的顯示出預測結果。

3.4計算準確率

darknet分類沒有像caffe一樣訓練的同時日誌文件輸出測試集的準確率,但是提供了valid函數用於輸出top-1準確率。

$ ./darknet classifier valid cfg/door.data cfg/darknet19.cfg classify_result/darknet19_18.weights

用相同的數據集對比caffe、pytorch框架,用近似的網絡訓練,darknet框架訓練的平均loss更低,準確率更高,模型的泛化也更好。對比caffe,沒有第三方庫,c也更方便移植到嵌入式平臺。

3.5問題匯集

(1)Error: out of memory

  原因:1. 可能是有人占用資源,查查後臺進程

     2. batch size過大,超出了顯卡能夠承受的範圍。可以適當改小cfg文件中的batch, 同時讓batch和subdivisions保持在一個比較合適的比例,每次傳入的圖片數量=進行forward propagation的圖片數量=batch/subdivisions,進行backward propagation的圖片數量=batch (我的理解是這樣,如果不對歡迎指正)

解決:增大cfg文件中subdivisions,16、32或者64(最多為batch值)

subdivision:這個參數很有意思的,它會讓你的每一個batch不是一下子都丟到網絡裏。而是分成subdivision對應數字的份數,一份一份的跑完後,在一起打包算作完成一次iteration。這樣會降低對顯存的占用情況。如果設置這個參數為1的話就是一次性把所有batch的圖片都丟到網絡裏,如果為2的話就是一次丟一半。

(2)其他參考“Darknet YOLO 訓練問題集錦”

網址:https://blog.csdn.net/Pattorio/article/details/80051988

四、YOLO.V3的可視化

Yolo.v3訓練日誌可視化,主要是loss和iou曲線的可視化,是查看訓練效果的重要依據。等待訓練結束後(有時還沒等訓練結束,模型就開始發散了),因此需要檢測各項指標(如loss)是否達到了我們的預期期望值;如果沒有,要分析為什麽。

可視化訓練過程的中間參數,可以幫助我們分析問題,可視化中間參數需要用到訓練時保存的log文件(命令中的路徑根據自己實際修改):

$ cd darknet

$ ./darknet detector train wp_data/cfg/voc.data wp_data/cfg/yolov3-voc.cfg 2>&1 | tee wp_data/visualization/train_yolov3.log

4.0格式化訓練的日誌文件logextract_log.py腳本

在使用腳本繪制變化曲線之前,需要先使用extract_log.py腳本,格式化log,用生成的新的log文件供可視化工具繪圖,格式化log的extract_log.py腳本如下(和生成的log文件同一目錄):

====================================================

# coding=utf-8

# 該文件用來提取訓練log,去除不可解析的log後使log文件格式化,生成新的log文件供可視化工具繪圖

import inspect

import os

import random

import sys

def extract_log(log_file,new_log_file,key_word):

with open(log_file, ‘r‘) as f:

with open(new_log_file, ‘w‘) as train_log:

#f = open(log_file)

#train_log = open(new_log_file, ‘w‘)

for line in f:

# 去除多gpu的同步log

if ‘Syncing‘ in line:

continue

# 去除除零錯誤的log

if ‘nan‘ in line:

continue

if key_word in line:

train_log.write(line)

f.close()

train_log.close()

extract_log(‘train_yolov3.log‘,‘train_log_loss.txt‘,‘images‘)

extract_log(‘train_yolov3.log‘,‘train_log_iou.txt‘,‘IOU‘)

====================================================

運行之後,會解析log文件的loss行和iou行得到兩個txt文件.

4.1可視化訓練日誌中的loss(train_loss_visualization.py腳本

train_loss_visualization.py腳本如下(也是同一目錄新建py文件):

====================================================

# coding=utf-8

#根據train_log_loss.txt行數修改lines行

import pandas as pd

import numpy as np

import matplotlib.pyplot as plt

#%matplotlib inline

#lines =9873

lines=25100

result = pd.read_csv(‘train_log_loss.txt‘, skiprows=[x for x in range(lines)] ,error_bad_lines=False, names=[‘loss‘, ‘avg‘, ‘rate‘, ‘seconds‘, ‘images‘])

result.head()

result[‘loss‘]=result[‘loss‘].str.split(‘ ‘).str.get(1)

result[‘avg‘]=result[‘avg‘].str.split(‘ ‘).str.get(1)

result[‘rate‘]=result[‘rate‘].str.split(‘ ‘).str.get(1)

result[‘seconds‘]=result[‘seconds‘].str.split(‘ ‘).str.get(1)

result[‘images‘]=result[‘images‘].str.split(‘ ‘).str.get(1)

result.head()

result.tail()

#print(result.head())

# print(result.tail())import pandas as pd

import numpy as np

import matplotlib.pyplot as plt

#%matplotlib inline

lines =9873

result = pd.read_csv(‘train_log_loss.txt‘, skiprows=[x for x in range(lines) if ((x<1000))] ,error_bad_lines=False, names=[‘loss‘, ‘avg‘, ‘rate‘, ‘seconds‘, ‘images‘])

result.head()

result[‘loss‘]=result[‘loss‘].str.split(‘ ‘).str.get(1)

result[‘avg‘]=result[‘avg‘].str.split(‘ ‘).str.get(1)

result[‘rate‘]=result[‘rate‘].str.split(‘ ‘).str.get(1)

result[‘seconds‘]=result[‘seconds‘].str.split(‘ ‘).str.get(1)

result[‘images‘]=result[‘images‘].str.split(‘ ‘).str.get(1)

result.head()

result.tail()

#print(result.head())

# print(result.tail())

# print(result.dtypes)

print(result[‘loss‘])

print(result[‘avg‘])

print(result[‘rate‘])

print(result[‘seconds‘])

print(result[‘images‘])

result[‘loss‘]=pd.to_numeric(result[‘loss‘])

result[‘avg‘]=pd.to_numeric(result[‘avg‘])

result[‘rate‘]=pd.to_numeric(result[‘rate‘])

result[‘seconds‘]=pd.to_numeric(result[‘seconds‘])

result[‘images‘]=pd.to_numeric(result[‘images‘])

result.dtypes

fig = plt.figure()

ax = fig.add_subplot(1, 1, 1)

ax.plot(result[‘avg‘].values,label=‘avg_loss‘)

#ax.plot(result[‘loss‘].values,label=‘loss‘)

ax.legend(loc=‘best‘)

ax.set_title(‘The loss curves‘)

ax.set_xlabel(‘batches‘)

fig.savefig(‘avg_loss‘)

#fig.savefig(‘loss‘)

# print(result.dtypes)

print(result[‘loss‘])

print(result[‘avg‘])

print(result[‘rate‘])

print(result[‘seconds‘])

print(result[‘images‘])

result[‘loss‘]=pd.to_numeric(result[‘loss‘])

result[‘avg‘]=pd.to_numeric(result[‘avg‘])

result[‘rate‘]=pd.to_numeric(result[‘rate‘])

result[‘seconds‘]=pd.to_numeric(result[‘seconds‘])

result[‘images‘]=pd.to_numeric(result[‘images‘])

result.dtypes

fig = plt.figure()

ax = fig.add_subplot(1, 1, 1)

ax.plot(result[‘avg‘].values,label=‘avg_loss‘)

#ax.plot(result[‘loss‘].values,label=‘loss‘)

ax.legend(loc=‘best‘)

ax.set_title(‘The loss curves‘)

ax.set_xlabel(‘batches‘)

fig.savefig(‘avg_loss‘)

#fig.savefig(‘loss‘)

====================================================

修改train_loss_visualization.py中lines為train_log_loss.txt行數,並根據需要修改要跳過的行數:

skiprows=[x for x in range(lines) if ((x%10!=9) |(x<1000))]

運行train_loss_visualization.py會在腳本所在路徑生成avg_loss.png。可以通過分析損失變化曲線,修改cfg中的學習率變化策略。

4.2可視化訓練日誌中的參數(train_iou_visualization.py腳本

可視化’Region Avg IOU’, ‘Class’, ‘Obj’, ‘No Obj’, ‘Avg Recall’,’count’這些參數可以使用腳本train_iou_visualization.py,使用方式和train_loss_visualization.py相同,train_iou_visualization.py腳本如下(#lines根據train_log_iou.txt的行數修改):

====================================================

# coding=utf-8

import pandas as pd

import numpy as np

import matplotlib.pyplot as plt

#%matplotlib inline

lines = 122956 #根據train_log_iou.txt的行數修改

result = pd.read_csv(‘train_log_iou.txt‘, skiprows=[x for x in range(lines) if (x%10==0 or x%10==9) ] ,error_bad_lines=False, names=[‘Region Avg IOU‘, ‘Class‘, ‘Obj‘, ‘No Obj‘, ‘Avg Recall‘,‘count‘])

result.head()

result[‘Region Avg IOU‘]=result[‘Region Avg IOU‘].str.split(‘: ‘).str.get(1)

result[‘Class‘]=result[‘Class‘].str.split(‘: ‘).str.get(1)

result[‘Obj‘]=result[‘Obj‘].str.split(‘: ‘).str.get(1)

result[‘No Obj‘]=result[‘No Obj‘].str.split(‘: ‘).str.get(1)

result[‘Avg Recall‘]=result[‘Avg Recall‘].str.split(‘: ‘).str.get(1)

result[‘count‘]=result[‘count‘].str.split(‘: ‘).str.get(1)

result.head()

result.tail()

# print(result.head())

# print(result.tail())

# print(result.dtypes)

print(result[‘Region Avg IOU‘])

result[‘Region Avg IOU‘]=pd.to_numeric(result[‘Region Avg IOU‘])

result[‘Class‘]=pd.to_numeric(result[‘Class‘])

result[‘Obj‘]=pd.to_numeric(result[‘Obj‘])

result[‘No Obj‘]=pd.to_numeric(result[‘No Obj‘])

result[‘Avg Recall‘]=pd.to_numeric(result[‘Avg Recall‘])

result[‘count‘]=pd.to_numeric(result[‘count‘])

result.dtypes

fig = plt.figure()

ax = fig.add_subplot(1, 1, 1)

ax.plot(result[‘Region Avg IOU‘].values,label=‘Region Avg IOU‘)

# ax.plot(result[‘Class‘].values,label=‘Class‘)

# ax.plot(result[‘Obj‘].values,label=‘Obj‘)

# ax.plot(result[‘No Obj‘].values,label=‘No Obj‘)

# ax.plot(result[‘Avg Recall‘].values,label=‘Avg Recall‘)

# ax.plot(result[‘count‘].values,label=‘count‘)

ax.legend(loc=‘best‘)

# ax.set_title(‘The Region Avg IOU curves‘)

ax.set_title(‘The Region Avg IOU curves‘)

ax.set_xlabel(‘batches‘)

# fig.savefig(‘Avg IOU‘)

fig.savefig(‘Region Avg IOU‘)

====================================================

運行train_iou_visualization.py會在腳本所在路徑生成相應的曲線圖。

---20180927第一次實戰筆記

---後續根據實戰在更新

YOLO---Darknet下的學習筆記