上海殷行建設網(wǎng)站百度上海分公司
yolov8識別視頻
直接上YOLOv8的結構圖吧,小伙伴們可以直接和YOLOv5進行對比,看看能找到或者猜到有什么不同的地方?
-
Backbone:使用的依舊是CSP的思想,不過YOLOv5中的C3模塊被替換成了C2f模塊,實現(xiàn)了進一步的輕量化,同時YOLOv8依舊使用了YOLOv5等架構中使用的SPPF模塊;
-
PAN-FPN:毫無疑問YOLOv8依舊使用了PAN的思想,不過通過對比YOLOv5與YOLOv8的結構圖可以看到,YOLOv8將YOLOv5中PAN-FPN上采樣階段中的卷積結構刪除了,同時也將C3模塊替換為了C2f模塊;
-
Decoupled-Head:是不是嗅到了不一樣的味道?是的,YOLOv8走向了Decoupled-Head;
-
Anchor-Free:YOLOv8拋棄了以往的Anchor-Base,使用了Anchor-Free的思想;
-
損失函數(shù):YOLOv8使用VFL Loss作為分類損失,使用DFL Loss+CIOU Loss作為分類損失;
-
樣本匹配:YOLOv8拋棄了以往的IOU匹配或者單邊比例的分配方式,而是使用了Task-Aligned Assigner匹配方式。
-
SPPF改進
SPP結構又被稱為空間金字塔池化,能將任意大小的特征圖轉換成固定大小的特征向量。
接下來我們來詳述一下SPP是怎么處理滴~
輸入層:首先我們現(xiàn)在有一張任意大小的圖片,其大小為w * h。
輸出層:21個神經(jīng)元 -- 即我們待會希望提取到21個特征。
分析如下圖所示:分別對1 * 1分塊,2 * 2分塊和4 * 4子圖里分別取每一個框內(nèi)的max值(即取藍框框內(nèi)的最大值),這一步就是作最大池化,這樣最后提取出來的特征值(即取出來的最大值)一共有1 * 1 + 2 * 2 + 4 * 4 = 21個。得出的特征再concat在一起。
PAN-FPN改進
YOLOv6的neck結構圖
我們再看YOLOv8的結構圖:
YOLOv8的neck結構圖
可以看到,相對于YOLOv5或者YOLOv6,YOLOv8將C3模塊以及RepBlock替換為了C2f,同時細心可以發(fā)現(xiàn),相對于YOLOv5和YOLOv6,YOLOv8選擇將上采樣之前的1×1卷積去除了,將Backbone不同階段輸出的特征直接送入了上采樣操作。
2.4、Head部分都變了什么呢?
先看一下YOLOv5本身的Head(Coupled-Head):
YOLOv5的head結構圖
而YOLOv8則是使用了Decoupled-Head,同時由于使用了DFL 的思想,因此回歸頭的通道數(shù)也變成了4*reg_max的形式:
YOLOv8的head結構圖
對比一下YOLOv5與YOLOv8的YAML
二、下載yolov8源碼
yolov8源碼鏈接:https://github.com/ultralytics/ultralytics
三、環(huán)境準備
環(huán)境如下:
Ubuntu18.04
cuda11.3
pytorch:1.11.0
torchvision:0.12.0
準備好環(huán)境后,先進入自己帶pytorch的虛擬環(huán)境,與之前的yolo系列安裝都不太一樣,yolov8僅需要安裝ultralytics這一個庫就ok了。
pip install ultralytics
另一種方法稍顯麻煩,需要先克隆git倉庫,再進行安裝;二者取其一即可。
git clone https://github.com/ultralytics/ultralytics
cd ultralytics
pip install -e .
測試:
運行之后出現(xiàn)兩張預測完的圖片說明已經(jīng)成功:
?
四、數(shù)據(jù)處理
在yolov8/data目錄下新建Annotations, images, ImageSets, labels 四個文件夾
images目錄下存放數(shù)據(jù)集的圖片文件
Annotations目錄下存放圖片的xml文件(labelImg標注)?
?
?
?將xml文件轉換成YOLO系列標準讀取的txt文件
在同級目錄下再新建一個文件XML2TXT.py
注意classes = [“…”]一定需要填寫自己數(shù)據(jù)集的類別,在這里我是一個類別"fall",因此classes = [“fall”],代碼如下所示:
如果數(shù)據(jù)集中的類別比較多不想手敲類別的,可以使用(4)中的腳本直接獲取類別,同時還能查看各個類別的數(shù)據(jù)量,如果不想可以直接跳過(4)。
?
# -*- coding: utf-8 -*-
# xml解析包
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import joinsets = ['train', 'test', 'val']
classes = ['fall']# 進行歸一化操作
def convert(size, box): # size:(原圖w,原圖h) , box:(xmin,xmax,ymin,ymax)dw = 1./size[0] # 1/wdh = 1./size[1] # 1/hx = (box[0] + box[1])/2.0 # 物體在圖中的中心點x坐標y = (box[2] + box[3])/2.0 # 物體在圖中的中心點y坐標w = box[1] - box[0] # 物體實際像素寬度h = box[3] - box[2] # 物體實際像素高度x = x*dw # 物體中心點x的坐標比(相當于 x/原圖w)w = w*dw # 物體寬度的寬度比(相當于 w/原圖w)y = y*dh # 物體中心點y的坐標比(相當于 y/原圖h)h = h*dh # 物體寬度的寬度比(相當于 h/原圖h)return (x, y, w, h) # 返回 相對于原圖的物體中心點的x坐標比,y坐標比,寬度比,高度比,取值范圍[0-1]# year ='2012', 對應圖片的id(文件名)
def convert_annotation(image_id):'''將對應文件名的xml文件轉化為label文件,xml文件包含了對應的bunding框以及圖片長款大小等信息,通過對其解析,然后進行歸一化最終讀到label文件中去,也就是說一張圖片文件對應一個xml文件,然后通過解析和歸一化,能夠將對應的信息保存到唯一一個label文件中去labal文件中的格式:calss x y w h 同時,一張圖片對應的類別有多個,所以對應的bunding的信息也有多個'''# 對應的通過year 找到相應的文件夾,并且打開相應image_id的xml文件,其對應bund文件in_file = open('data/Annotations/%s.xml' % (image_id), encoding='utf-8')# 準備在對應的image_id 中寫入對應的label,分別為# <object-class> <x> <y> <width> <height>out_file = open('data/labels/%s.txt' % (image_id), 'w', encoding='utf-8')# 解析xml文件tree = ET.parse(in_file)# 獲得對應的鍵值對root = tree.getroot()# 獲得圖片的尺寸大小size = root.find('size')# 如果xml內(nèi)的標記為空,增加判斷條件if size != None:# 獲得寬w = int(size.find('width').text)# 獲得高h = int(size.find('height').text)# 遍歷目標objfor obj in root.iter('object'):# 獲得difficult ??difficult = obj.find('difficult').text# 獲得類別 =string 類型cls = obj.find('name').text# 如果類別不是對應在我們預定好的class文件中,或difficult==1則跳過if cls not in classes or int(difficult) == 1:continue# 通過類別名稱找到idcls_id = classes.index(cls)# 找到bndbox 對象xmlbox = obj.find('bndbox')# 獲取對應的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 對應的是歸一化后的(x,y,w,h)# 生成 calss x y w h 在label文件中out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')# 返回當前工作目錄
wd = getcwd()
print(wd)for image_set in sets:'''對所有的文件數(shù)據(jù)集進行遍歷做了兩個工作:1.將所有圖片文件都遍歷一遍,并且將其所有的全路徑都寫在對應的txt文件中去,方便定位2.同時對所有的圖片文件進行解析和轉化,將其對應的bundingbox 以及類別的信息全部解析寫到label 文件中去最后再通過直接讀取文件,就能找到對應的label 信息'''# 先找labels文件夾如果不存在則創(chuàng)建if not os.path.exists('data/labels/'):os.makedirs('data/labels/')# 讀取在ImageSets/Main 中的train、test..等文件的內(nèi)容# 包含對應的文件名稱image_ids = open('data/ImageSets/%s.txt' % (image_set)).read().strip().split()# 打開對應的2012_train.txt 文件對其進行寫入準備list_file = open('data/%s.txt' % (image_set), 'w')# 將對應的文件_id以及全路徑寫進去并換行for image_id in image_ids:list_file.write('data/images/%s.jpg\n' % (image_id))# 調(diào)用 year = 年份 image_id = 對應的文件名_idconvert_annotation(image_id)# 關閉文件list_file.close()
查看自定義數(shù)據(jù)集標簽類別及數(shù)量
在yolov8目錄下再新建一個文件ViewCategory.py,將代碼復制進去
import os
from unicodedata import name
import xml.etree.ElementTree as ET
import globdef count_num(indir):label_list = []# 提取xml文件列表os.chdir(indir)annotations = os.listdir('.')annotations = glob.glob(str(annotations) + '*.xml')dict = {} # 新建字典,用于存放各類標簽名及其對應的數(shù)目for i, file in enumerate(annotations): # 遍歷xml文件# actual parsingin_file = open(file, encoding='utf-8')tree = ET.parse(in_file)root = tree.getroot()# 遍歷文件的所有標簽for obj in root.iter('object'):name = obj.find('name').textif (name in dict.keys()):dict[name] += 1 # 如果標簽不是第一次出現(xiàn),則+1else:dict[name] = 1 # 如果標簽是第一次出現(xiàn),則將該標簽名對應的value初始化為1# 打印結果print("各類標簽的數(shù)量分別為:")for key in dict.keys():print(key + ': ' + str(dict[key]))label_list.append(key)print("標簽類別如下:")print(label_list)if __name__ == '__main__':# xml文件所在的目錄,修改此處indir = 'data/Annotations'count_num(indir) # 調(diào)用函數(shù)統(tǒng)計各類標簽數(shù)目
修改數(shù)據(jù)加載配置文件
進入data/文件夾,新建fall.yaml,內(nèi)容如下,注意txt需要使用絕對路徑
train: /home/xxx/yolov8/data/train.txt
val: /home/xxx/yolov8/data/val.txt
test: /home/xxx/yolov8/data/test.txt# number of classes
nc: 1# class names
names: ['fall']
五、模型訓練
打開終端(或者pycharm等IDE),進入虛擬環(huán)境,隨后進入yolov8文件夾,在終端中輸入下面命令,即可開始訓練。
yolo task=detect mode=train model=yolov8n.pt data=data/fall.yaml batch=32 epochs=100 imgsz=640 workers=16 device=0
六、模型驗證
yolo task=detect mode=val model=runs/detect/train3/weights/best.pt data=data/fall.yaml device=0
七、模型預測
yolo task=detect mode=predict model=runs/detect/train3/weights/best.pt source=data/images device=0
八、模型導出
yolo task=detect mode=export model=runs/detect/train3/weights/best.pt