YOLOv8從環(huán)境搭建到推理訓(xùn)練
共 16234字,需瀏覽 33分鐘
·
2024-05-09 08:30
0、引言
硬件配置:使用Mobaxterm_personal_21.4遠程操控3060服務(wù)器(Linux系統(tǒng)),CUDA版本11.7。
使用anaconda作為python環(huán)境環(huán)境,python為3.8版本。(最好使用3.8版本)
本文最終安裝的是1.13.1,版本是0.14.1,其他的依賴庫按照requirements.txt文件安裝即可。
YOLOv8創(chuàng)新點:??????
1??Backbone。使用的依舊是CSP的思想,不過YOLOv5中的C3模塊被替換成了C2f模塊,實現(xiàn)了進一步的輕量化,同時YOLOv8依舊使用了YOLOv5等架構(gòu)中使用的SPPF模塊;
2??PAN-FPN。毫無疑問YOLOv8依舊使用了PAN的思想,不過通過對比YOLOv5與YOLOv8的結(jié)構(gòu)圖可以看到,YOLOv8將YOLOv5中PAN-FPN上采樣階段中的卷積結(jié)構(gòu)刪除了,同時也將C3模塊替換為了C2f模塊
3??Decoupled-Head。是不是嗅到了不一樣的味道?是的,YOLOv8走向了Decoupled-Head;
4??Anchor-Free。YOLOv8拋棄了以往的Anchor-Base,使用了Anchor-Free的思想;
5??損失函數(shù)。YOLOv8使用VFL Loss作為分類損失,使用DFL Loss+CIOU Loss作為分類損失;
6??樣本匹配。YOLOv8拋棄了以往的IOU匹配或者單邊比例的分配方式,而是使用了Task-Aligned Assigner匹配方式。
1、代碼下載
代碼連接:
https://github.com/ultralytics/ultralytics
權(quán)重連接:
https://github.com/ultralytics/assets/releases
先睹為快:
下載:點擊右上角的綠色Code按鈕,再點擊Download,即可完成代碼下載。下載之后導(dǎo)入到服務(wù)器端解壓。
解壓之后如下圖所示。
2、環(huán)境準(zhǔn)備
2.1創(chuàng)建新環(huán)境
啟動遠程軟件,進入base環(huán)境,創(chuàng)建新環(huán)境yolov8。
conda create -n yolov8 python=3.8
激活新環(huán)境yolov8。
conda activate yolov8
2.2安裝依賴(各種第三方庫)
運行requirements.txt文件即可完成對所有庫的安裝,包括pytorch等眾多第三方庫。
運行該文件需要先進入到該文件所在的文件夾:cd 各層文件夾。進入所在文件夾之后再運行該文件。
pip install -r requirements.txt -i https://mirrors.bfsu.edu.cn/pypi/web/simple/
2.3安裝ultralytics
ultralytics集成了yolo的各種包以及模型等,程序中直接調(diào)用。
pip install ultralytics
2.4手動下載權(quán)重
雖然在(2)中可以自動下載yolov8n.pt,但是經(jīng)常打不開,所以給出手動下載連接。
下載鏈接:https://github.com/ultralytics/assets/releases/download/v0.0.0/yolov8n.pt
位置:拷到y(tǒng)olov8\ultralytics-main\ultralytics\yolo\v8\detect\yolov8n.pt
3、測試運行
操作:首先進入到y(tǒng)olov8\ultralytics-main\ultralytics\yolo\v8\detect\predict.py,運行predict.py
python predict.py
完成測試:
查看結(jié)果:
4、訓(xùn)練自己的數(shù)據(jù)
4.1數(shù)據(jù)準(zhǔn)備
由于本文的實驗是進行圖像檢測,故將數(shù)據(jù)集放在detect目錄下。
操作:在detect文件下新建mydata_tuomin文件夾(可自定義),再在mydata_tuomin目錄下新建Annotations, images, ImageSets, labels 四個文件夾。
??Annotations目錄下存放圖片的xml文件
??images目錄下存放數(shù)據(jù)集的圖片文件
??ImageSets 目錄之后會在Main文件夾內(nèi)自動生成train.txt,val.txt,test.txt和trainval.txt四個文件
??labels目錄下存放xml文件轉(zhuǎn)換后的txt標(biāo)準(zhǔn)格式標(biāo)簽
4.2按比例劃分?jǐn)?shù)據(jù)集
操作:在detect目錄下新建一個文件splitDataset.py,運行。
作用:隨機分配訓(xùn)練/驗證/測試集圖片,會在ImageSet 目錄下生成四個txt文件,存放訓(xùn)練集、驗證集、測試集的劃分文件(各集合包含的圖片)。
代碼如下所示:
import os
import random
trainval_percent = 0.9
train_percent = 0.9
xmlfilepath = 'mydata_tuomin/Annotations'
txtsavepath = 'mydata_tuomin/ImageSets'
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('mydata_tuomin/ImageSets/trainval.txt', 'w')
ftest = open('mydata_tuomin/ImageSets/test.txt', 'w')
ftrain = open('mydata_tuomin/ImageSets/train.txt', 'w')
fval = open('mydata_tuomin/ImageSets/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()
查看結(jié)果:
4.3標(biāo)簽格式轉(zhuǎn)換
由于yolov8使用的labels是txt格式的文件,故需將原始數(shù)據(jù)集xml格式的標(biāo)簽轉(zhuǎn)換為txt格式。
即將每個xml標(biāo)注提取box信息為txt格式,每個圖像對應(yīng)一個txt文件,文件每一行為一個目標(biāo)的信息,包括class, x_center, y_center, width, height格式。
操作:在detect目錄下新建一個文件XML2TXT.py,運行。
??注意代碼第11行,classes = ['…']一定需要填寫自己數(shù)據(jù)集的類別,在這里我是三個類別'greenplate','blueplate','face'。
??如果數(shù)據(jù)集中的類別不知道或者比較多不想手敲,可以使用4.4中的腳本直接獲取類別,如果不需要可以直接跳過4.4。
結(jié)果:生成的標(biāo)簽存放在labels目錄下,并且在mydata_tuomin目錄下生成三個txt文件,文件內(nèi)是訓(xùn)練集、驗證集、測試集的圖片路徑。
代碼如下:
# -*- coding: utf-8 -*-
# xml解析包
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
sets = ['train', 'test', 'val']
classes = ['greenplate','blueplate','face']
# 進行歸一化操作
def convert(size, box): # size:(原圖w,原圖h) , box:(xmin,xmax,ymin,ymax)
dw = 1./size[0] # 1/w
dh = 1./size[1] # 1/h
x = (box[0] + box[1])/2.0 # 物體在圖中的中心點x坐標(biāo)
y = (box[2] + box[3])/2.0 # 物體在圖中的中心點y坐標(biāo)
w = box[1] - box[0] # 物體實際像素寬度
h = box[3] - box[2] # 物體實際像素高度
x = x*dw # 物體中心點x的坐標(biāo)比(相當(dāng)于 x/原圖w)
w = w*dw # 物體寬度的寬度比(相當(dāng)于 w/原圖w)
y = y*dh # 物體中心點y的坐標(biāo)比(相當(dāng)于 y/原圖h)
h = h*dh # 物體寬度的寬度比(相當(dāng)于 h/原圖h)
return (x, y, w, h) # 返回 相對于原圖的物體中心點的x坐標(biāo)比,y坐標(biāo)比,寬度比,高度比,取值范圍[0-1]
# year ='2012', 對應(yīng)圖片的id(文件名)
def convert_annotation(image_id):
# 對應(yīng)的通過year 找到相應(yīng)的文件夾,并且打開相應(yīng)image_id的xml文件,其對應(yīng)bund文件
in_file = open('mydata_tuomin/Annotations/%s.xml' % (image_id), encoding='utf-8')
# 準(zhǔn)備在對應(yīng)的image_id 中寫入對應(yīng)的label,分別為
# <object-class> <x> <y> <width> <height>
out_file = open('mydata_tuomin/labels/%s.txt' % (image_id), 'w', encoding='utf-8')
# 解析xml文件
tree = ET.parse(in_file)
# 獲得對應(yīng)的鍵值對
root = tree.getroot()
# 獲得圖片的尺寸大小
size = root.find('size')
# 如果xml內(nèi)的標(biāo)記為空,增加判斷條件
if size != None:
# 獲得寬
w = int(size.find('width').text)
# 獲得高
h = int(size.find('height').text)
# 遍歷目標(biāo)obj
for obj in root.iter('object'):
# 獲得difficult ??
difficult = obj.find('difficult').text
# 獲得類別 =string 類型
cls = obj.find('name').text
# 如果類別不是對應(yīng)在我們預(yù)定好的class文件中,或difficult==1則跳過
if cls not in classes or int(difficult) == 1:
continue
# 通過類別名稱找到id
cls_id = classes.index(cls)
# 找到bndbox 對象
xmlbox = obj.find('bndbox')
# 獲取對應(yīng)的bndbox的數(shù)組 = ['xmin','xmax','ymin','ymax']
b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
float(xmlbox.find('ymax').text))
print(image_id, cls, b)
# 帶入進行歸一化操作
# w = 寬, h = 高, b= bndbox的數(shù)組 = ['xmin','xmax','ymin','ymax']
bb = convert((w, h), b)
# bb 對應(yīng)的是歸一化后的(x,y,w,h)
# 生成 calss x y w h 在label文件中
out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
# 返回當(dāng)前工作目錄
wd = getcwd()
print(wd)
for image_set in sets:
# 先找labels文件夾如果不存在則創(chuàng)建
if not os.path.exists('mydata_tuomin/labels/'):
os.makedirs('mydata_tuomin/labels/')
# 讀取在ImageSets/Main 中的train、test..等文件的內(nèi)容
# 包含對應(yīng)的文件名稱
image_ids = open('mydata_tuomin/ImageSets/%s.txt' % (image_set)).read().strip().split()
# 打開對應(yīng)的2012_train.txt 文件對其進行寫入準(zhǔn)備
list_file = open('mydata_tuomin/%s.txt' % (image_set), 'w')
# 將對應(yīng)的文件_id以及全路徑寫進去并換行
for image_id in image_ids:
list_file.write('mydata_tuomin/images/%s.jpg\n' % (image_id))
# 調(diào)用 year = 年份 image_id = 對應(yīng)的文件名_id
convert_annotation(image_id)
# 關(guān)閉文件
list_file.close()
4.4查看自己的數(shù)據(jù)集標(biāo)簽類別
操作:在detect目錄下新建一個文件ViewCategory.py,運行。
代碼如下:(文件路徑也可以使用絕對路徑)
# coding=gbk
import xml.dom.minidom as xmldom
import os
#voc數(shù)據(jù)集獲取所有標(biāo)簽的所有類別數(shù)"
annotation_path="/mydata_tuomin/Annotations/"
annotation_names=[os.path.join(annotation_path,i) for i in os.listdir(annotation_path)]
labels = list()
for names in annotation_names:
xmlfilepath = names
domobj = xmldom.parse(xmlfilepath)
# 得到元素對象
elementobj = domobj.documentElement
#獲得子標(biāo)簽
subElementObj = elementobj.getElementsByTagName("object")
for s in subElementObj:
label=s.getElementsByTagName("name")[0].firstChild.data
#print(label)
if label not in labels:
labels.append(label)
print(labels)
4.5創(chuàng)建數(shù)據(jù)加載配置文件
操作:在mydata_tuomin文件夾下新建一個tuomin.yaml文件(可以自定義命名),用來存放訓(xùn)練集、驗證集、測試集的路徑文件(train.txt、val.txt、test.txt),以上三個文件是在步驟4.3中生成的路徑文件(存放在mydata_tuomin目錄下),然后是目標(biāo)的類別數(shù)目和具體類別列表。
代碼如下:???注意txt需要使用絕對路徑。
train: /home/xxxxxx/Yolov8/ultralyticsmain/ultralytics/yolo/v8/detect/mydata_tuomin/train.txt
val: /home/xxxxxx/Yolov8/ultralyticsmain/ultralytics/yolo/v8/detect/mydata_tuomin/val.txt
test: /home/xxxxxx/Yolov8/ultralyticsmain/ultralytics/yolo/v8/detect/mydata_tuomin/test.txt
# number of classes
nc: 3
# class names
names: ['greenplate', 'blueplate', 'face']
4.6選擇模型
在ultralytics/models/v8/目錄下是模型的配置文件,提供了n、s、m、l、x版本,逐漸增大(隨著架構(gòu)的增大,訓(xùn)練時間也是逐漸增大),五種模型對比圖如下所示。
操作:本文限于硬件配置,采用yolov8s.yaml,接下來只用修改一個參數(shù),把nc改成自己的類別數(shù)
代碼如下:
# Ultralytics YOLO 馃殌, GPL-3.0 license
# Parameters
nc: 3 # number of classes(只需要改這里!!!!!!!)
depth_multiple: 0.33 # scales module repeats
width_multiple: 0.50 # scales convolution channels
# YOLOv8.0s backbone
backbone:
# [from, repeats, module, args]
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 3, C2f, [128, True]]
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 6, C2f, [256, True]]
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 6, C2f, [512, True]]
- [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
- [-1, 3, C2f, [1024, True]]
- [-1, 1, SPPF, [1024, 5]] # 9
# YOLOv8.0s head
head:
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 3, C2f, [512]] # 13
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
- [-1, 3, C2f, [256]] # 17 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 12], 1, Concat, [1]] # cat head P4
- [-1, 3, C2f, [512]] # 20 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]]
- [[-1, 9], 1, Concat, [1]] # cat head P5
- [-1, 3, C2f, [1024]] # 23 (P5/32-large)
- [[15, 18, 21], 1, Detect, [nc]] # Detect(P3, P4, P5)
4.7開始訓(xùn)練
輸入如下命令開始訓(xùn)練。
yolo task=detect mode=train model=yolov8s.yaml data=mydata_tuomin/tuomin.yaml epochs=100 batch=4
以上參數(shù)解釋如下:
??task:選擇任務(wù)類型,可選['detect', 'segment', 'classify', 'init']。
??mode: 選擇是訓(xùn)練、驗證還是預(yù)測的任務(wù)蕾西 可選['train', 'val', 'predict']。
??model: 選擇yolov8不同的模型配置文件,可選yolov8s.yaml、yolov8m.yaml、yolov8x.yaml等。
??data: 選擇生成的數(shù)據(jù)集配置文件
??epochs:指的就是訓(xùn)練過程中整個數(shù)據(jù)集將被迭代多少次,顯卡不行你就調(diào)小點。
??batch:一次看完多少張圖片才進行權(quán)重更新,梯度下降的mini-batch,顯卡不行你就調(diào)小點。
查看訓(xùn)練過程:
查看結(jié)果:
