Windos10 linux同樣過程
現有問題:
本文過程在linux下類似,可以正常通過。windons下,運作python腳本出現問題,無法正常輸出0001.txt(标定檔案),是以隻能使用linux生成标定檔案和路徑檔案txt,然後複制到windons下使用。
待解決問題:
重寫訓練部分代碼,使得windons程式直接讀取原始圖像和标記檔案,其餘檔案自動生成,然後開始訓練、
1 準備資料
輸入原始資料--yolo2訓練----輸出權重檔案
這裡用100張做樣例:
原始資料
- 原始圖像0001.jpg - 0100.jpg 10張
- 描述圖像中目标資訊的0001.txt - 0100.txt 10個
- 存儲每個訓練圖像絕對完整路徑的train.txt 1個
- 存儲每個測試圖像絕對完整路徑 var.txt 1個
問題1 無法直接得到 原始資料 2.描述圖像中目标資訊的txt,采間接的辦法
- 使用标圖軟體得到描述圖像資訊的0001.xml 每個圖象對應一張
- 0001.xml 通過python腳本轉換 0001.txt
問題2 無法直接得到3,4完整路徑,間接先擷取圖檔名,然後加上路徑名
- 擷取 訓練圖像的名字到一個 train.txt
- 将這個txt轉換成完整路徑
- 擷取 測試圖像的名字到一個var.txt
1.1 原始圖像
首先準備好自己的資料集,最好固定格式,此處為例,采用jpg格式的圖像,在名字上最好使用像VOC一樣類似000001.jpg、000002.jpg這樣

1.2 xml檔案 描述圖像中要識别的目标資訊
每一個xml對應一張圖像,并且每個xml中存放的是标記的各個目标的位置和類别資訊,命名通常與對應的原始圖像一樣
因為做的是目标檢測,是以接下來需要标記原始圖像中的目标區域。相關方法和工具有很多,這裡需用labelImg,相關用法也有說明,基本就是框住目标區域然後輕按兩下類别,标記完整張圖像後點選儲存即可。操作界面如下:
通常save之後會将标記的資訊儲存在xml檔案,其名字通常與對應的原始圖像一樣。
其中每個xml檔案是這樣的畫風
<?xml version="1.0" ?>
<annotation>
<folder>JPEGImages</folder>
<filename>00000</filename>
<path>/home/kinglch/VOC2007/JPEGImages/00000.jpg</path>
<source>
<database>Unknown</database>
</source>
<size>
<width>704</width>
<height>576</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>person</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>73</xmin>
<ymin>139</ymin>
<xmax>142</xmax>
<ymax>247</ymax>
</bndbox>
</object>
<object>
<name>person</name>
<pose>Unspecified</pose>
<truncated>0</truncated>
<difficult>0</difficult>
<bndbox>
<xmin>180</xmin>
<ymin>65</ymin>
<xmax>209</xmax>
<ymax>151</ymax>
</bndbox>
</object>
1.3 xml-txt檔案 描述圖像中要識别的目标資訊
生成的xml檔案不是yolo2讀取的格式,是以需要轉換為和圖像名稱一樣的txt。
轉換後的txt格式:
<object-class> <x> <y> <width> <height>
- 0 15 4 25 25 目标為第一類 起始位置 (15, 4) 長 25 寬 25
- 0 11 36 25 25 目标為第一類 起始位置 (11, 36) 長 25 寬 25
-
YOLO2 (2) 測試自己的資料
該部分由1.4中的creat_list.py腳本自動完成。
1.4擷取圖像的路徑,以便YOLO程式能夠找到圖檔
圖像分為兩類,一類充當測試資料 剩下的充當訓練資料。是以需要分别建立txt儲存他們的路徑位址。這裡使用python腳本來自動生成路徑。
生成過程分兩步,首先擷取圖像的名字
1.4.1 圖檔名 train.txt 隻存每個訓練的圖象的名字
1.4.2 圖檔名 val.txt 隻存每個驗證的圖像的名字
在生成infrared_train.txt與infrared_val.txt這兩個檔案時,會分别用到這兩個文檔。文檔裡包含了用于訓練/驗證的圖檔的名稱,裡面的資料組成很簡單,每行都是一個圖檔的名稱,并不包含圖檔的字尾(.jpg),比如文檔中:
- 第一行是: 0000
- 第二行是: 0001
該部分工作由生成腳本:creat_list.py:完成
自己需要改三個路徑:
- 圖檔原始位址
- 生成用于儲存訓練集圖像名字train.txt的路徑
- 生成用于儲存測試集圖像名字val.txt的路徑
#這個小腳本是用來打開圖檔檔案所在檔案夾,把前900個用于訓練的圖檔的名稱儲存在tain.txt,後103個用于驗證的圖檔儲存在val.txt
import os
from os import listdir, getcwd
from os.path import join
if __name__ == '__main__':
source_folder='/home/yolo_v2_tinydarknet/darknet/infrared/image/dout/'#位址是所有圖檔的儲存地點
dest='/home/yolo_v2_tinydarknet/darknet/infrared/train.txt' #儲存train.txt的位址
dest2='/home/yolo_v2_tinydarknet/darknet/infrared/val.txt' #儲存val.txt的位址
file_list=os.listdir(source_folder) #指派圖檔所在檔案夾的檔案清單
train_file=open(dest,'a') #打開檔案
val_file=open(dest2,'a') #打開檔案
for file_obj in file_list: #通路檔案清單中的每一個檔案
file_path=os.path.join(source_folder,file_obj)
#file_path儲存每一個檔案的完整路徑
file_name,file_extend=os.path.splitext(file_obj)
#file_name 儲存檔案的名字,file_extend儲存檔案擴充名
file_num=int(file_name)
#把每一個檔案命str轉換為 數字 int型 每一檔案名字都是由四位數字組成的 如 0201 代表 201 高位補零
if(file_num<900): #保留900個檔案用于訓練
#print file_num
train_file.write(file_name+'\n') #用于訓練前900個的圖檔路徑儲存在train.txt裡面,結尾加回車換行
else :
val_file.write(file_name+'\n') #其餘的檔案儲存在val.txt裡面
train_file.close()#關閉檔案
val_file.close()
然後通過得到的名字生成完整路徑
3.3 infrared_train.txt 存放訓練的圖像的位址
3.4 infrared_val.txt 存放測試的圖像的位址
文檔裡包含了所有用于訓練/驗證的圖檔的完整路徑,每一行都是一個圖檔的完整路徑,例如
第一行是: /home/yolo_v2_tinydarknet/darknet/infrared/image/dout/0000.jpg
第二行是 :/home/yolo_v2_tinydarknet/darknet/infrared/image/dout/0001.jpg
該部分由以下腳本完成
需要分兩次執行腳本。兩次不一樣的地方标紅
第一次 生成訓練集的完整路徑
- 1修改圖像生成的xml檔案所在地
- in_file = open('/home/yolo_v2_tinydarknet/darknet/infrared/labels/dout_original/%s.xml'%(image_id))#與圖檔對應的xml檔案所在的位址
- 2修改轉化後生成的txt的儲存路徑
- out_file = open('/home/yolo_v2_tinydarknet/darknet/infrared/labels/%s.txt'%(image_id),'w') #與此xml對應的轉換後的txt,這個txt的儲存完整路徑
- 3打開訓練集的兩行代碼注釋,并将測試集的兩行代碼注釋加上
- image_ids = open('/home/yolo_v2_tinydarknet/darknet/infrared/train.txt').read().strip().split() #如果是訓練集資料打開這一行,注釋下一行
- list_file = open('infrared_train.txt', 'w') #把結果寫入到indrared_train.txt檔案中,如果是訓練集資料打開這一行,注釋下一行
- 4修改圖檔路徑
- list_file.write('/home/yolo_v2_tinydarknet/darknet/infrared/image/dout/%s.jpg\n'%(image_id)) #把每一用于訓練或驗證的圖檔的完整的路徑寫入到infrared_train.txt中 這個檔案會被voc.data yolo.c調用
第二次 生成測試集的完整路徑
- 3打開測試集的兩行代碼注釋,并将訓練集的兩行代碼注釋加上
- image_ids = open('/home/yolo_v2_tinydarknet/darknet/infrared/train.txt').read().strip().split() #如果是測試資料打開這一行,注釋下一行
- list_file = open('infrared_train.txt', 'w') #把結果寫入到indrared_train.txt檔案中,如果測試集資料打開這一行,注釋下一行
- list_file.write('/home/yolo_v2_tinydarknet/darknet/infrared/image/dout/%s.jpg\n'%(image_id)) #把每一用于訓練或驗證的圖檔的完整的路徑寫入到infrared_train.txt中 這個檔案會被voc.data yolo.c調用
#此腳本修改自voc_label.py。修改的原因是:我的訓練集跟voc有些不同。
#由于資料集中包括用于訓練的資料和用于驗證的資料,是以此腳本可能需要分别對這兩種資料各運作一次,對兩種資料隻需要簡單地注釋掉相應語句即可
#這個腳本需要train.txt ,這個檔案是我用腳本creat_list.py生成的,儲存了用于訓練的圖檔的名字id,儲存了用于訓練的圖檔的名字
#這個腳本需要val.txt檔案,這個檔案是我用腳本creat_list.py生成的,儲存了用于驗證的圖檔的名字id,儲存了用于驗證的圖檔的名字
#這個腳本還需要xml格式的标簽檔案,我的訓練集xml檔案的格式與voc2007的類似,xml檔案的名稱與對應的用于訓練的圖檔的名稱相同
#這個腳本會生成 indrared_train.txt檔案 ,用于儲存每一用于訓練的圖檔的完整的路徑,随後會被voc.data yolo.c使用
#這個腳本會生成 indrared_val.txt檔案 ,用于儲存每一用于驗證的圖檔的完整的路徑,随後會被voc.data yolo.c使用
#這個腳本還會生成 txt格式的yolo可識别的标簽檔案,轉換自每一個用于訓練或驗證的圖檔對應的xml檔案,txt格式的檔案名稱與對應的xml檔案名相同,但是内容不同,擴充名不同
#這個腳本 需要與圖檔對應的xml檔案所在的位址,需要,轉換後生成的txt的完整儲存路徑
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')] #按照自己的檔案格式改的,不需要判斷是那個voc資料包
classes = ["n00000001"]#因為我的資料集隻有一個類别
def convert(size, box):#voc_label.py 自帶的函數,沒有修改
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('VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id))
in_file = open('/home/yolo_v2_tinydarknet/darknet/infrared/labels/dout_original/%s.xml'%(image_id))#與圖檔對應的xml檔案所在的位址
out_file = open('/home/yolo_v2_tinydarknet/darknet/infrared/labels/%s.txt'%(image_id),'w') #與此xml對應的轉換後的txt,這個txt的儲存完整路徑
tree=ET.parse(in_file)
root = tree.getroot()
size = root.find('size') #通路size标簽的資料
w = int(size.find('width').text)#讀取size标簽中寬度的資料
h = int(size.find('height').text)#讀取size标簽中高度的資料
for obj in root.iter('object'):
# difficult = obj.find('difficult').text #由于自己的檔案裡面沒有diffcult這一個标簽,是以就屏蔽之
cls = obj.find('name').text
if cls not in classes :#or int(difficult) == 1:
continue
cls_id = classes.index(cls)
xmlbox = obj.find('bndbox') #通路boundbox标簽的資料并進行處理,都按yolo自帶的代碼來,沒有改動
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')
#image_ids = open('VOCdevkit/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split() #之前代碼是按照sets裡面的字元來通路儲存有圖檔名字的train或者val的txt檔案
image_ids = open('/home/yolo_v2_tinydarknet/darknet/infrared/train.txt').read().strip().split() #如果是訓練集資料打開這一行,注釋下一行
#image_ids = open('/home/yolo_v2_tinydarknet/darknet/infrared/val.txt').read().strip().split() #如果是驗證資料集資料打開這一行,注釋上一行
#list_file = open('%s_%s.txt'%(year, image_set), 'w')
list_file = open('infrared_train.txt', 'w') #把結果寫入到indrared_train.txt檔案中,如果是訓練集資料打開這一行,注釋下一行
#list_file = open('infrared_val.txt', 'w') #把結果寫入到indrared_train.txt檔案中,如果是驗證資料集資料打開這一行,注釋上一行
for image_id in image_ids:
#list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg\n'%(wd, year, image_id))
list_file.write('/home/yolo_v2_tinydarknet/darknet/infrared/image/dout/%s.jpg\n'%(image_id)) #把每一用于訓練或驗證的圖檔的完整的路徑寫入到infrared_train.txt中 這個檔案會被voc.data yolo.c調用
convert_annotation(image_id) #把圖檔的名稱id傳給函數,用于把此圖檔對應的xml中的資料轉換成yolo要求的txt格式
list_file.close() #關閉檔案
原始資料結果
經過以上步驟,我們現在得到以下資料:
- 原始照片 100張 jpg
- 和原始照片名一樣的,用于儲存圖像中要識别的目标資訊的txt 100個 txt
- 用于參加訓練的圖檔的路徑位址 infrared_train.txt 一個 txt
- 用于參加訓練的圖檔的路徑位址 infrared_val.txt 一個 txt
2 修改工程配置檔案
在工程生成的x64/data路徑下
2.1建立 yolo-obj.cfg 檔案,内容複制yolo-voc.2.0.cfg檔案(x64路徑下),但是修改:
- 第一行
- change line batch to batch=64
- 第二行
- change line subdivisions to subdivisions=8
-
YOLO2 (2) 測試自己的資料 - 修改region層 classes 自己訓練的類 這裡是1類 隻有car
-
YOLO2 (2) 測試自己的資料 - 修改region上一層convolutional層中 filters= (classes+5)*5 這裡 classes為一類 filters= (1+5)*5=30
-
YOLO2 (2) 測試自己的資料
2.2 建立obj.names 在檔案夾build\darknet\x64\data\裡,裡面是你所分的類 這裡為一類 car
如果很多類,例如voc.data 分了很多類資料
2.3 建立obj.data在 build\darknet\x64\data\路徑下
- 我們隻有一類car 是以classes=1
- train= 資料準備生成的 儲存訓練圖檔完整路徑的 train.txt
- valid=資料準備生成的 儲存測試圖檔完整路徑的 var.txt
- backup = backup 存放的是 生成的權重檔案路徑 預設x64/backp下
2.4 将原始圖檔集存在
build\darknet\x64\data\obj\
下
2.4 将資料處理得到的描述每個圖像中 目标資訊的txt檔案 也放在build\darknet\x64\data\obj\ 下
每個txt内容
3 開始訓練
3.1 訓練需要用到一個檔案
下載下傳 pre-trained weights for the convolutional layers (76 MB):
http://pjreddie.com/media/files/darknet19_448.conv.23
放在build\darknet\x64下
3.2 運作訓練指令 指令行進入build\darknet\x64下
darknet.exe detector train data/obj.data data/yolo-obj.cfg darknet19_448.conv.23
3.3生成結果在 build\darknet\x64\backup