目錄
1??訓練yolov4-tiny
1.1??文件準備
1.1.1??Annotations
1.1.2??JPEGImages
1.1.3??labels
1.1.4??trained_models
1.1.5??classes.name
1.1.6??create_labels_txt.py
1.1.7??custom_training.data
1.1.8??get_labels.py
1.1.9??get_train_val.py
1.1.10??train.txt
1.1.11??val.txt
1.1.12??yolov4-tiny.cfg
1.1.13??yolov4-tiny.conv.29
1.1.14??yolov4-tiny-test.cfg
1.2??訓練過程
1.3??訓練結果
2??制作預訓練模型
1??訓練yolov4-tiny
首先在darknet創建一個文件夾custom_training
文件夾中包含這些文件
我們從左往右來講,在文章的最后有識別效果,如果想先看效果的可以拉下去,看完再拉上來
1.1??文件準備
1.1.1??Annotations
獲取方式:標注軟件標注圖像后獲得
這里面放的都是標注好的xml文件,使用不同的標注軟件標注結果可能略有不同,但xml的文件格式都是一樣的,我們打開一個看一下
下面這個xml是一個圖中只有一個框子的
下面這個是一個圖中有多個框子的
1.1.2??JPEGImages
獲取方式:把標注的圖像放進去
這里面放的都是被標注的圖片,注意要與標注文件對應(比如0.jpg與0.xml)
1.1.3??labels
獲取方式:由create_labels_txt.py轉換xml文件獲得
這個文件夾中都是放的xml轉換過來的項目專用的txt文件(我們后面有一個文件專門轉換它),由于是轉換過來的,所以自然也是與圖像一一對應的
我們打開一個看一下
下面這個是一個框的情況,發現里面有5個數,這5個數的含義依次是
- 標簽號,從0開始
- 標注框的中心點x坐標 除 圖像寬度 的比值
- 標注框的中心點y坐標 除 圖像高度 的比值
- 標注框的寬度 除 圖像寬度 的比值
- 標注框的高度 除 圖像高度 的比值
我們下面再看一個多個框的情況
有幾個框就有幾行,最后不要有換行符
1.1.4??trained_models
創建一個空的文件夾就行了,這個文件夾是專門放訓練好的模型文件的,沒訓練之前文件夾中是空的
在訓練之后每1000個batch會自動保存一次,我訓練了4000個batch,現在里面是這樣的
后面要用的話用 yolov4-tiny_final.weights就可以了
1.1.5??classes.name
獲取方式:用記事本寫一個文件,后綴為.name就可以了
這里面寫的是所有標注的標簽,有幾個就寫幾個,標簽用換行符隔開,最后一行末尾沒有換行符
我再舉個例子
這里的順序要與后續create_labels_txt.py的順序一致
如果你不知道有多少標簽,后面可以通過get_labels.py來查詢
1.1.6??create_labels_txt.py
獲取方式:一個py文件
文件中的內容是這樣的
import xml.etree.ElementTree as ET
import os
import rewith open('classes.names','r') as f:classes = f.read().splitlines()p = re.compile(r'(.*)\.')
for i in os.listdir('Annotations'):i = p.findall(i)[0]xml_file = '/home/nvidia/darknet/custom_training/Annotations/{}.xml'.format(i)tree = ET.parse(xml_file)root = tree.getroot()for size in root.iter('size'):width = int(size.find('width').text)height = int(size.find('height').text)all_content = ''for obj in root.iter('object'):cls = obj.find('name').textcls_id = classes.index(cls)xmlbox = obj.find('bndbox')xmin = int(xmlbox.find('xmin').text)ymin = int(xmlbox.find('ymin').text)xmax = int(xmlbox.find('xmax').text)ymax = int(xmlbox.find('ymax').text)x = (xmin+xmax)/2/widthy = (ymin+ymax)/2/heightw = (xmax-xmin)/widthh = (ymax-ymin)/heightone_content = '{} {:.4f} {:.4f} {:.4f} {:.4f}'.format(cls_id,x,y,w,h)all_content = all_content + one_content + '\n'all_content = all_content.strip('\n')file = open('./labels/{}.txt'.format(i),'w')print(all_content,file=file,flush=True)
有幾個參數需要隨著數據集變動
- classes 這個是訓練的標簽,需要與classes.name的內容一致,注意順序也要一致
- xml_file 放的是Annotations中xml的文件,我這里放的絕對路徑,也可以放相對路徑
- xmin,ymin,ymin,ymax 我不確定所有的標注文件是否都是這四個點(有的可能是直接給寬度),如果你的xml文件中寫的是別的,那么你就對應改一下
- cls_id 這個是labels中產生txt的第一個內容
- x,y,w,h 這四個就是labels中產生的txt的后四個內容
如果按照我寫的結構放置文件的話,直接運行就可以了
1.1.7??custom_training.data
獲取方式:用記事本寫,后綴改為data,最后一行末尾沒有換行符
這里的信息的含義如下,注意所有路徑都是絕對路徑
字段 | 含義 |
---|---|
classes | 類別總數 |
train | train.txt的絕對路徑,train.txt我們后面會提到 |
valid | val.txt的絕對路徑,val.txt我們后面會提到 |
names | classes.name的絕對路徑 |
backup | trained_models的絕對路徑,注意后面要再加一個斜杠 |
1.1.8??get_labels.py
原理是用python的set()變量,set()變量中的元素不重復,訪問xml中的name,將所有的內容添加的set中
1.1.9??get_train_val.py
這個是用來輔助創建train.txt與val.txt的
import osa = 0
train_txt = open('train.txt','w')
val_txt = open('val.txt','w')
for i in os.listdir('JPEGImages'):a = a + 1if a < 15712: #trainprint('/home/nvidia/darknet/custom_training/JPEGImages/' + i,file=train_txt,flush=True)else: #testprint('/home/nvidia/darknet/custom_training/JPEGImages/' + i,file=val_txt,flush=True)
6065是我當前有7581張圖片,我想選擇其中的80%(6065張)作為訓練圖片,其余的作為測試圖片
1.1.10??train.txt
獲取方式:筆記本搞
這里放的是訓練圖像的絕對路徑
1.1.11??val.txt
獲取方式:筆記本搞
這里放的是所有測試圖像的絕對路徑,方法與train.txt相同,讓其余圖像作為測試圖像
1.1.12??yolov4-tiny.cfg
獲取方式:在darkent的cfg中有,復制過來
yolov4-tiny.cfg與其余的yolo模型修改起來差不多,我比較常用yolov4-tiny.cfg與yolov4-custom.cfg,這兩個cfg文件在這個文件夾中都有,tiny速度快但精度差,custom精度高但速度慢,下面說幾個經常改的參數
- batch與subdivisions
訓練模型時可能會出現CUDA爆掉的情況,這個時候我們需要修改batch與subdivisions,batch是會影響訓練結果的,太小是不行的,subdivisions的意思是把batch分成多少份,我下面這種圖就是batch為64,然后把batch再分成64份一點一點兒給,這樣就不會出現CUDA爆掉的問題了
- width與height
這個并不是圖像的寬與高,這個實際上是模型的輸入大小,寬和高必須為32的倍數
你的模型寬高越大,訓練時間越長,模型越精準,預測的更慢
你的模型寬高越小,訓練時間越短,模型越不精準,預測的更快
- learning_rate
learning_reate是學習速率,我們在訓練的過程中可能會出現loss為NaN的情況,這個時候就不用再訓練了,這個情況叫梯度爆炸或梯度消失,這個時候可以嘗試改一下學習率
- max_batches與steps
在幫助文檔中建議 max_batches的值設置為(種類數)*2000
step有兩個值,第一個值是max_batches的80%,第二個值是max_batches的90%
- classes與filters
classes是訓練的類別數量,比如你要識別5種不同的東西classes就給5,識別7種類別不同的東西就給7
filters計算公式為(種類數+5)*3,我下面圖片種類數為2,所以這里的filters是21
在yolov4-custom.cfg中一共有三處,在yolv4-tiny.cfg有兩處,都要改
1.1.13??yolov4-tiny.conv.29
獲取方式:從我上面的網盤鏈接中搞,或者用這個github鏈接?https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v4_pre/yolov4-tiny.conv.29
這個鏈接是在項目?GitHub - AlexeyAB/darknet: YOLOv4 / Scaled-YOLOv4 / YOLO - Neural Networks for Object Detection (Windows and Linux version of Darknet )?中的這里
1.1.14??yolov4-tiny-test.cfg
獲取方式:把yolov4-tiny.cfg復制過來,然后改一些東西
只改batch,把下面的batch注釋掉
這個其實你改不改都行,在測試的時候直接使用yolv4-tiny.cfg進行使用就行
1.2??訓練過程
在darkent路徑下打開終端,之后輸入
./darknet detector train custom_training/custom_training.data custom_training/yolov4-tiny.cfg custom_training/yolov4-tiny.conv.29
輸入之后終端的情況是這樣的
而且會出現一個圖,這里會記錄我們每一個batch的loss情況
訓練接觸后會顯示模型已保存,我大致訓練了兩個小時左右
我的loss情況是這樣的
最終loss是0.1498左右
1.3??訓練結果
在darknet下打開終端后輸入
./darknet detector test custom_training/custom_training.data custom_training/yolov4-tiny-test.cfg custom_training/trained_models/yolov4-tiny_final.weights custom_training/JPEGImages/000001.jpg
最后的圖片路徑你可以自定義,輸入之后終端是這樣的
之后會出現一個小圖像
把它放大后的效果是這樣的
2??制作預訓練模型
我們先說層這個概念,在訓練的開始你可以看到你選用的模型一共有多少層。
你可以將訓練好的模型作為預訓練模型,比如
./darknet partial ./custom_training/yolov3-tiny.cfg ./custom_training/yolov3-tiny_final.weights ./yolov3-tiny.conv.15 15
- ./darknet partial[訓練模型用到的cfg位置] [訓練好的模型文件位置] [要生成的預訓練模型文件位置] [保留網絡層數權重]
之后就在執行代碼的位置就會得到 yolov3-tiny.conv.15 這個預訓練模型文件?