一.下載yolov3工程項目
git clone https://github.com/pjreddie/darknet
cd darknet
將makefile的相應部分參數改為1,
#如果使用GPU設置為1,CPU設置為0,GPU=0
#如果使用CUDNN設置為1,否則為0,CUDNN=0
#如果使用OPENCV設置為1,否則為0,OPENCV=1
修改后保存,再make一下。
將官網的預訓練權重先下載到darknet下
二.准備訓練數據集
按照下面文件夾的結構,將訓練數據集放到各個文件夾下面,生成2個文件一個train.txt,一個是val.txt。這里使用到的腳本為getfile.py,
VOCdevkit
—VOC2012
——Annotations
——ImageSets
———Layout
———Main
———Segmentation
——JPEGImages
注意:其中Annotations中是所有的xml文件
JPEGImages中是所有的訓練文件
Main中是2個txt文件:train.txt與val.txt文件(前一個用來驗證,后一個用來測試)
三.生成2007_train.txt和2007_val.txt文件
下載voc_label.py,或者直接在scripts中找到voc_labels.py將該文件與VOCdevkit數據集放到同一級路徑下。
首先修改voc_label.py里面的值:
修改sets為自己訓練樣本集的名稱,以及classes為訓練樣本集的類標簽
文件最后兩行注釋掉。
在當前終端運行 python voc_label.py
生成
① 訓練和驗證的文件列表(2007_train.txt和2007_val.txt)主要存儲的是圖片位置信息;
② 生成與Annotations等同級的label文件,label里面的文件是每張圖片位置坐標以及類別的標簽信息。
四.修改cfg/voc.data文件
#classes為訓練樣本集的類別總數:classes= 1
#train的路徑為訓練樣本集所在的路徑
train = /home/njust/darknet_model/darknet_person/2007_train.txt
#valid的路徑為驗證樣本集所在的路徑
valid = /home/njust/darknet_model/darknet_person/2007_val.txt
#names的路徑為data/voc.names文件所在的路徑
names = data/voc.names
backup = backup
五.在darknet文件夾下面新建文件夾backup
六.修改voc.name為樣本集的標簽名
七.修改cfg/yolov3-voc.cfg
這里我只是以一類目標檢測為例,主要有4處地方調整:
[net]
# Testing
# batch=1
# subdivisions=1
# Training
batch=64
subdivisions=16
......
[convolutional]
size=1
stride=1
pad=1
filters=18###75
activation=linear
[yolo]
mask = 6,7,8
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
classes=1###20
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0###1
......
[convolutional]
size=1
stride=1
pad=1
filters=18###75
activation=linear
[yolo]
mask = 3,4,5
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
classes=1###20
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0###1
......
[convolutional]
size=1
stride=1
pad=1
filters=18###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=1###20
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0###1
A.filters數目是怎么計算的:3x(classes數目+5),和聚類數目分布有關,論文中有說明;
B.如果想修改默認anchors數值,使用k-means即可;
C.如果顯存很小,將random設置為0,關閉多尺度訓練;
D.其他參數基本與V2一致,不再說明;
E.前100次迭代loss較大,后面會很快收斂;
八.開始訓練
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74
九.識別
./darnket detector test cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc.backup data/test.jpg
常見問題解決:
- 1. 什么時候停止訓練:
通常每個類(對象)有足夠的2000次迭代。但是,當你應該停止訓練時,為了更准確的定義,請使用以下指標:
9002:是迭代次數
0.060730:是平均損失,當看到平均損失0.xxxxx avg在許多吃迭代不再減少時,應該停止訓練。一旦停止訓練,可以得到最后的.weights文件,可以在backup里面找到最佳的文件,也可以使用yolov3-voc.backup這個文件。
***利用YOLOv2訓練數據---https://blog.csdn.net/echoKangYL/article/details/79445587
1.下載YOLO
yolo的官網:https://pjreddie.com/darknet/yolo/
2.數據預處理(該處理方法與參考博客中的方法相同)該階段建立的文件夾的名稱最好與該文檔中的相同,否則需要改動圖片處理等python腳本中的文件名。a.建立文件夾"Image",並在其下存放所有圖片樣本(jpg、png均可)b.利用labelImg工具進行標注c.與Image文件件同級建立"xml"文件夾,存放利用labelImg標注后得到的所有圖片的xml文件d.下載腳本,放在Image、xml文件夾的同級腳本下載地址:http://pan.baidu.com/s/1hs22I7U 密碼:wdv0(該下載地址在參考博客中有提供,十分感謝原作者的幫助)在運行腳本之前,先做幾處改動:a.將traindata.py中大概在65行和71行的:shutil.copy(xmlolddir, newdir1);shutil.copy(xmlolddir, newdir2);兩句刪掉(或前面加‘#’)否則在訓練過程中報類似這樣的error:“Cannot load image "/home/ts/tensorflow/objectRecognition/Augmentation/KNIFE/Getdata/trainImage/000018.png"STB Reason: unknown image type”b.若之前建立文件夾時文件夾名稱並非Image和xml,那么在traindata.py中的對應文件夾名稱處將其改為自己的文件夾名稱改動之后,運行腳本運行traindata.py:生成trainImage文件夾,存放訓練圖片;生成trainImageXML文件夾,存放訓練圖片xml標簽;生成validateImage文件夾,存放驗證集圖片;生成validateImageXML文件夾,存放驗證集圖片的xml標簽;生成trainImageId.txt、validateImageId.txt,存放訓練、驗證集圖片索引(一般為文件名)。運行trans.py,生成trainImageLabelTxt文件夾,存放訓練圖片通過xml標簽轉化得到的txt文件(若在訓練過程提示txt文件找不到,則把此文件夾下的txt文件夾移動到trainImage文件夾);生成validateImageLabelTxt文件夾,道理一樣。另外,得到的trainImagePath.txt和validateImagePath.txt存放着訓練圖片和驗證圖片的路徑。此后,將生成的validateImageLabelTxt文件夾中的所有txt文件復制到validateImage文件夾中;同理,將trainImageLabelTxt文件夾中的所有txt文件復制到trainImage文件夾中。否則會在訓練過程中報類似這樣的error:“cannot open file xxxxxx.txt”
3.修改配置文件a.cfg/voc.data文件中:classes= 3train = /home/ts/tensorflow/objectRecognition/YOLOv2/YOLOtraining/trainImagePath.txtvalid = /home/ts/tensorflow/objectRecognition/YOLOv2/YOLOtraining/validateImagePath.txtnames = data/knifes.namesbackup = backupclasses存放類別總數(這里有knife、swissknife、jackknife三種,根據使用者不同的需要進行改動),train 和valid 中存的是訓練圖片集和驗證圖片集的路徑;在data文件夾中新建文件knifes.names,存放的是方框注釋,本例中有三行(根據使用者不同的需要進行改動):knifeswissknifejackknifeb.yolo-voc.cfg文件中:將[region]中的classes改為3(這里有knife、swissknife、jackknife三類,根據使用者不同的需要進行改動);將最后一個[convolutional](緊挨着[region]的前一個)中的filter改為40(filter的公式filters=(classes+coords+1)*(NUM),這里是(3+4+1)*5=30,根據使用者不同的需要進行改動)。 c.knifes.names:具體見a4.下載預訓練文件cfg/darknet19_448.conv.23以在其他數據集上pretrain的模型做為初值。下載地址:http://pan.baidu.com/s/1dFgUk4x 密碼:ynhg(該下載地址為參考博客原文作者提供,再次感謝原作者的幫助)下載之后將其放在darknet文件夾下。在訓練之前,要先在darknet文件夾下新建backup文件夾,在backup文件夾中新建一個以yolo-voc.backup為文件名的文件,以保存訓練參數。否則將在訓練過程中報類似這樣的error:“cannot open backup/yolo-voc.backup”5.訓練在darknet文件夾路徑下運行命令:./darknet detector train cfg/voc.data cfg/yolo-voc.cfg darknet19_448.conv.23系統默認會迭代45000次batch,如果需要修改訓練次數,進入cfg/yolo_voc.cfg修改max_batches的值。6.測試訓練完成后,模型成功保存,輸入命令測試模型:./darknet detector test cfg/voc.data cfg/yolo-voc.cfg backup/yolo-voc_final.weights testpicture/001.jpg在該步驟中,將最后一個參數 testpicture/001.jpg 改為自己想要測試的圖片路徑;若提前終止訓練,則將倒數第二個參數 backup/yolo-voc_final.weights 改為backup文件夾下的最新權重備份文件名稱,例如:我提前終止后,最新權重備份文件為 backup/yolo-voc_900.weights。否則將提示error:“Couldn't open file: backup/yolo-voc_final.weights”參考原文中訓練類別為1,本文中的訓練類別為3,相互比較之下可以知道所有類別的情況下配置文件應該如何改動。
原文:https://blog.csdn.net/echoKangYL/article/details/79445587
***YOLO訓練自己的數據集---https://blog.csdn.net/qq_34484472/article/details/73135354#reply
1.yolo
yolo的官網:https://pjreddie.com/darknet/yolo/
yolo的官網介紹了yolo的安裝與測試。建議大家多看看英文官網,因為中文網更新的慢,而且有部分內容省略了。按照官網的步驟就不會有錯。(建議先跑一下Pscal VOC)
2.數據的預處理
yolo的數據包括訓練數據和驗證數據(訓練數據用來訓練模型,驗證數據用來調整模型)。訓練數據和驗證數據都包括:a.圖片;b.標簽。需要說明的是,如果采用VCC的話,標簽需要特定xml格式,還要轉化為txt。下面以我目標檢測“貓”為例講解。
a.在“Image”文件夾下存放所有的圖片樣本(包括訓練數據和驗證數據,而且最好是jpg格式)
b.下載labelImg(一種圖像標記工具,給圖像中的目標打上標簽,且可以生成訓練需要的xml格式),具體的使用方法可以百度,操作起來很簡單。
c.與“Image”文件夾同級新建“xml”文件夾,“xml”文件夾存放labelImg得到的所有圖片樣本的標簽。
標注工具labelImg在Ubuntu系統的安裝和使用--- https://blog.csdn.net/learning_tortosie/article/details/80947301
若是標中文則要進行整改--- https://www.cnblogs.com/datou-swag/articles/10658822.html
d.現在就是要將所有的樣本分成訓練集和驗證集,而且要將訓練集和驗證集對應的xml也分開。這里下載python腳本,直接放在“Image”和“xml”文件夾同級路徑。
下載:
鏈接:http://pan.baidu.com/s/1hs22I7U 密碼:wdv0
在運行腳本之前,先做幾處改動:a.將traindata.py中大概在65行和71行的:shutil.copy(xmlolddir, newdir1);shutil.copy(xmlolddir, newdir2);兩句刪掉(或前面加‘#’)否則在訓練過程中報類似這樣的error:“Cannot load image
運行traindata.py:生成trainImage文件夾,存放訓練圖片;生成trainImageXML文件夾,存放訓練圖片xml標簽;生成validateImage文件夾,存放驗證集圖片;生成validateImageXML文件夾,存放驗證集圖片的xml標簽。
運行trans.py(改一下自己的類別),生成trainImageLabelTxt文件夾,存放訓練圖片通過xml標簽轉化得到的txt文件(若在訓練過程提示txt文件找不到,則把此文件夾下的txt文件夾移動到trainImage文件夾);生成validateImageLabelTxt文件夾,道理一樣。
另外得到的trainImagePath.txt和validateImagePath.txt存放着訓練圖片和驗證圖片的路徑。
3.修改配置文件
接下來就是修改配置文件了:
a.cfg/voc.data文件中:
classes= 1
train = /home/pdd/pdwork/darknet2/darknet/VOC/cat/trainImagePath.txt
valid = /home/pdd/pdwork/darknet2/darknet/VOC/cat/validateImagePath.txt
names = data/cats.names
classes存放類別總數(這里只有cat一種),train 和valid 放着的是訓練圖片和驗證圖片的路徑,cats.names存放的是方框注釋,這里只有cat一行:
b.yolo-voc.cfg
將[region]中的classes改為1(這里只有cat一類),將最后一個[convolutional](緊挨着[region]的前一個)中的filter改為30(filter的公式filters=(classes+ coords+ 1)* (NUM) ,我的是(1+4+1)* 5=30)。
c.cats.names
在data文件夾下新建cats.names,具體見a。
4.下載預訓練文件cfg/darknet19_448.conv.23
以在其他數據集上pretrain的模型做為初值,下載地址:
鏈接:http://pan.baidu.com/s/1dFgUk4x 密碼:ynhg。放在darknet文件夾下。
(最新的預訓練權中參數darknet53.conv.74--- wget https://pjreddie.com/media/files/darknet53.conv.74)
5.訓練
在darknet文件夾路徑下運行命令:
./darknet detector train cfg/voc.data cfg/yolo-voc.cfg cfg/darknet19_448.conv.23
系統默認會迭代45000次batch,如果需要修改訓練次數,進入cfg/yolo_voc.cfg修改max_batches的值。
6.測試
訓練完成后,模型成功保存,輸入命令測試一下這個模型吧:
./darknet detector test cfg/voc.data cfg/yolo-voc.cfg backup/yolo-voc_final.weights testpicture/001.jpg
darknet detector train cfg/chinese.data cfg/chinese-voc.cfg darknet53.conv.74
./darknet detector test cfg/chinese.data cfg/chinese-voc.cfg chinese_output/chinese-voc_final.weights chinese_data/Image/6420.jpg
---------------------
作者:Panda_Peng
來源:CSDN
原文:https://blog.csdn.net/qq_34484472/article/details/73135354
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!
yolo v2使用總結---http://www.cnblogs.com/shepherd2015/p/8671646.html
【Darknet 】Darknet 源碼理解---https://zhuanlan.zhihu.com/p/37726435
【YOLO】訓練voc數據集沒有框??解決方法
https://blog.csdn.net/shangpapa3/article/details/76277869
如果你想保存輸出的結果,在后面加句 | tee yolo-voc.txt
./darknet detector train cfg/voc.data cfg/yolo-voc.cfg darknet19_448.conv.23 | tee yolo-voc.txt
./darknet detector test cfg/voc.data cfg/yolo-voc.2.0.cfg yolo-voc_final.weights data/dog.jpg -thresh 0.25
./darknet detector train plate_12651/plate_12651.data plate_12651/p3-voc.cfg darknet53.conv.74
###traindata.py### # -*- coding: utf-8 -*- import os; import shutil; def rename_by_count(path): #按序號命名 count = 1000; filelist = os.listdir(path) # 該文件夾下所有的文件(包括文件夾) for files in filelist: # 遍歷所有文件 Olddir = os.path.join(path, files); # 原來的文件路徑 if os.path.isdir(Olddir): # 如果是文件夾則跳過 continue; filename = os.path.splitext(files)[0]; # 文件名 filetype = os.path.splitext(files)[1]; # 文件擴展名 Newdir = os.path.join(path, str(count) + filetype); # 新的文件路徑 os.rename(Olddir, Newdir); # 重命名 count += 1; def listname(path,idtxtpath): filelist = os.listdir(path); # 該文件夾下所有的文件(包括文件夾) f = open(idtxtpath, 'w'); for files in filelist: # 遍歷所有文件 Olddir = os.path.join(path, files); # 原來的文件路徑 if os.path.isdir(Olddir): # 如果是文件夾則跳過 continue; filename = os.path.splitext(files)[0]; # 文件名 filetype = os.path.splitext(files)[1]; # 文件擴展名 #Newdir = os.path.join(path, "1000" + filetype); # 新的文件路徑: path+filename+type f.write(filename); f.write('\n'); f.close(); def imgid_list(imgpath, savepath, num): #rename_by_count(imgpath); path1 = savepath + "/validateImage"; path2 = savepath + "/trainImage"; if os.path.exists(path1)== False: os.mkdir(path1); if os.path.exists(path2) == False: os.mkdir(path2); xmlpath1 = savepath + "/validateImageXML"; xmlpath2 = savepath + "/trainImageXML"; if os.path.exists(xmlpath1)== False: os.mkdir(xmlpath1); if os.path.exists(xmlpath2) == False: os.mkdir(xmlpath2); filelist = os.listdir(imgpath); count = 0; for files in filelist: olddir = os.path.join(imgpath, files); newdir1 = os.path.join(path1, files); newdir2 = os.path.join(path2, files); filename = os.path.splitext(files)[0]; # 文件名 xmldir = savepath + "/xml"; xmldir1 = savepath + "/validateImageXML"; xmldir2 = savepath + "/trainImageXML"; if count<num: shutil.copy(olddir, newdir1); #validate xmlolddir = os.path.join(xmldir, filename + ".xml"); xmlnewdir = os.path.join(xmldir1,filename+".xml"); shutil.copy(xmlolddir,xmlnewdir); #shutil.copy(xmlolddir, newdir1); else: shutil.copy(olddir, newdir2); xmlolddir = os.path.join(xmldir, filename + ".xml"); xmlnewdir = os.path.join(xmldir2, filename + ".xml"); shutil.copy(xmlolddir, xmlnewdir); #shutil.copy(xmlolddir, newdir2); count=count+1; imgidtxtpath1 = savepath + "/validateImageId.txt"; imgidtxtpath2 = savepath + "/trainImageId.txt"; listname(path1, imgidtxtpath1); listname(path2, imgidtxtpath2); #rename_by_count; # 給圖片按序號給名字 savepath = os.getcwd()#取得當前工作目錄 imgpath = savepath+"/Image" val_num=16 #驗證集數量,可修改 imgid_list(imgpath,savepath,val_num);
###trans.py import xml.etree.ElementTree as ET import pickle import string import os import shutil from os import listdir, getcwd from os.path import join sets=[('2012', 'train')] classes = ["plate"] #分類集,我這里是識別貓,所以是一個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,flag,savepath): #s = '\xef\xbb\xbf' #nPos = image_id.index(s) #if nPos >= 0: # image_id = image_id[3:] if flag == 0: in_file = open(savepath+'/trainImageXML/%s.xml' % (image_id)) labeltxt = savepath+'/trainImageLabelTxt'; if os.path.exists(labeltxt) == False: os.mkdir(labeltxt); out_file = open(savepath+'/trainImageLabelTxt/%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) elif flag == 1: in_file = open(savepath+'/validateImageXML/%s.xml' % (image_id)) labeltxt = savepath + '/validateImageLabelTxt'; if os.path.exists(labeltxt) == False: os.mkdir(labeltxt); out_file = open(savepath+'/validateImageLabelTxt/%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() for year, image_set in sets: #savepath = "/home/wurui/CAR/wrz/pillar"; savepath = os.getcwd(); idtxt = savepath + "/validateImageId.txt"; pathtxt = savepath + "/validateImagePath.txt"; image_ids = open(idtxt).read().strip().split() list_file = open(pathtxt, 'w') s = '\xef\xbb\xbf' for image_id in image_ids: nPos = image_id.find(s) if nPos >= 0: image_id = image_id[3:] list_file.write('%s/validateImage/%s.jpg\n' % (wd, image_id)) print(image_id) convert_annotation(image_id, 1, savepath) list_file.close() idtxt = savepath + "/trainImageId.txt"; pathtxt = savepath + "/trainImagePath.txt" ; image_ids = open(idtxt).read().strip().split() list_file = open(pathtxt, 'w') s = '\xef\xbb\xbf' for image_id in image_ids: nPos = image_id.find(s) if nPos >= 0: image_id = image_id[3:] list_file.write('%s/trainImage/%s.jpg\n'%(wd,image_id)) print(image_id) convert_annotation(image_id,0,savepath) list_file.close()