一、环境准备
安装好Anaconda3和pycharm;
Anaconda3官网下载:Free Download | Anaconda
Download PyCharm: The Python IDE for data science and web development by JetBrainspycharm下载:Download PyCharm: The Python IDE for data science and web development by JetBrains
安装完毕后可以做以下几件事情:
1、更换pip下载源
在c盘用户目录下创建名为pip的文件夹,在文件夹下新建一个名为pip的文本,写入
我这里用的全局清华源,读者也可以自行寻找其他镜像源;
写完之后将pip.txt文件后缀改为.ini配置文件 。
2、conda换源
还是在C盘用户目录下找到.condarc文件,写入
3、 conda虚拟环境路径修改
conda新建的虚拟环境默认路径为C盘,可以在.condarc中添加最后两行,最后一行路径可自行更改。
4、更改pychram配置文件路径
pychram运行程序后生成的配置文件默认存在C盘,右键pycharm打开安装目录,在bin文件夹下找到idea.properties文件,右键用记事本打开,打不开的话就先用pycharm打开
根据自己的路径写入:
idea.config.path=D:Pycharm/PyCharm 2021.2.2/configuration_files/.PyCharm/config
idea.system.path=D:/Pycharm/PyCharm 2021.2.2/configuration_files/.PyCharm/system
idea.plugins.path=D:/Pycharm/PyCharm 2021.2.2/configuration_files/plugins
idea.log.path=D:/Pycharm/PyCharm 2021.2.2/configuration_files/log
接下来就可以开始使用conda和pycahrm了。
二、建立虚拟环境并下载源码
1、新建虚拟环境
在左下角开始栏中找到conda命令行,点击启动。
输入conda create -n yolov8 python=3.8
其中yolov8时环境名可自行更改。
输入conda activate yolov8激活虚拟环境;前面的括号变成yolov8表示环境激活成功。
2、安装cuda和pytorch
依次输入一下命令,第一个时cuda包,第二个时cudnn包,第三个时对应版本的pytorch,三者的版本需要对应好,可以去pytorch官网查看。PyTorch
conda install cudatoolkit=11.3 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/win-64/
conda install cudnn=8.4.0 -c https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/win-64/
conda install pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 cudatoolkit=11.3 -c pytorch
下载完之后验证一下是否安装成功;在命令行输入python打开解释器,然后
输入 import torch
输入 torch.cuda.is_available(),输入出为True表示安装成功,可以进入下一步。
3、进入yolov8官网下载源码
github官网 http://git clone https://github.com/ultralytics/ultralytics
gitee国内源:ultralytics: YOLOv8 🚀 Ultralytics 同步更新官方最新版 YOLOv8 (gitee.com)
找到下载的文件解压:
然后cd到解压的yolov8路径:
如果发现没有成功进入,输入D:回车进到D盘,此时就可以看到成功进入yolov8源码路径;
输入 pip install ultralytics 安装扩展包;然后执行路径下的requirment.txt依赖文件;
pip install -r requirements.txt
三、数据集制作
在yolov8目录下新建一个名为data的文件夹,在其中新建mydata文件夹,将图片和标签存放其中。
相信各位都会使用labelimg制作标签了,我们直接看生成的结果
然后在这里新建一个Imagesets文件夹后续有用;
在根目录下新建两个python文件,spildataset.py和xml2txt.py
spildataset.py划分数据集,路径改成自己的;
import os
import random
trainval_percent = 0.8
train_percent = 0.8
xmlfilepath = r'D:\360MoveData\Users\hp\Desktop\maduo\annotations'
txtsavepath = r'D:\360MoveData\Users\hp\Desktop\maduo\imageset'
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(r'D:\360MoveData\Users\hp\Desktop\maduo\imageset\trainval.txt', 'w')
ftest = open(r'D:\360MoveData\Users\hp\Desktop\maduo\imageset\test.txt', 'w')
ftrain = open(r'D:\360MoveData\Users\hp\Desktop\maduo\imageset\train.txt', 'w')
fval = open(r'D:\360MoveData\Users\hp\Desktop\maduo\imageset\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()
xml2txt.py
# -*- 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 = ['yan']
# 进行归一化操作
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坐标
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(r'D:\360MoveData\Users\hp\Desktop\maduo\annotations\%s.xml' % (image_id), encoding='utf-8')
# 准备在对应的image_id 中写入对应的label,分别为
# <object-class> <x> <y> <width> <height>
out_file = open(r'D:\360MoveData\Users\hp\Desktop\maduo\labels\%s.txt' % (image_id), 'w', encoding='utf-8')
# 解析xml文件
tree = ET.parse(in_file)
# 获得对应的键值对
root = tree.getroot()
# 获得图片的尺寸大小
size = root.find('size')
# 如果xml内的标记为空,增加判断条件
if size != None:
# 获得宽
w = int(size.find('width').text)
# 获得高
h = int(size.find('height').text)
# 遍历目标obj
for 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
# 通过类别名称找到id
cls_id = classes.index(cls)
# 找到bndbox 对象
xmlbox = obj.find('bndbox')
# 获取对应的bndbox的数组 = ['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的数组 = ['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:
'''
对所有的文件数据集进行遍历
做了两个工作:
1.将所有图片文件都遍历一遍,并且将其所有的全路径都写在对应的txt文件中去,方便定位
2.同时对所有的图片文件进行解析和转化,将其对应的bundingbox 以及类别的信息全部解析写到label 文件中去
最后再通过直接读取文件,就能找到对应的label 信息
'''
# 先找labels文件夹如果不存在则创建
if not os.path.exists(r'D:\360MoveData\Users\hp\Desktop\maduo\labels/'):
os.makedirs(r'D:\360MoveData\Users\hp\Desktop\maduo\labels/')
# 读取在ImageSets/Main 中的train、test..等文件的内容
# 包含对应的文件名称
image_ids = open(r'D:\360MoveData\Users\hp\Desktop\maduo\imageset\%s.txt' % (image_set)).read().strip().split()
# 打开对应的2012_train.txt 文件对其进行写入准备
list_file = open(r'D:\360MoveData\Users\hp\Desktop\maduo\%s.txt' % (image_set), 'w')
# 将对应的文件_id以及全路径写进去并换行
for image_id in image_ids:
list_file.write('D:/360MoveData/Users/hp/Desktop/maduo/pic/%s.bmp/n' % (image_id))
# 调用 year = 年份 image_id = 对应的文件名_id
convert_annotation(image_id)
# 关闭文件
list_file.close()
依次执行两个脚本文件后mydata为如下格式,不包括labels.cache
四、更改配置文件
1、在data中新建一个data.yaml文件写入数据集路径,种类数量,以及标签名称:
train: D:/360MoveData/Users/hp/Desktop/yolov8/dete_data/train.txt
val: D:/360MoveData/Users/hp/Desktop/yolov8/dete_data/val.txt
test: D:/360MoveData/Users/hp/Desktop/yolov8/dete_data/test.txt
# number of classes
nc: 5
# class names
names: ['diao','pai', 'waji', 'fire','pile']
2、找到yolov8.yaml文件
在cfg/models/v8中;这里写的是模型的结构,我们目前只需要更改种类数量nc就行。
五、 开始训练
1、在根目录下新建一个mytrain.py脚本,yolov8n.yaml就是刚才的那个yolov8.yaml,yolov8有n,s,m,l,x五个型号,这里使用n型号;
data参数就是刚才新建的data.yaml文件路径,epochs时训练轮次,imgsz输入图片大小,yolov8自行将原始图片进行尺度变换;batch批训练大小,gpu不行的话设置小一点,save_dir参数需要再default.yaml文件中添加,这样训练结果才会保存到save_dir路径下。
from ultralytics import YOLO
if __name__ == '__main__':
'''
如果是3个模块(A, B, C)要进行测试,排列组合数是3+2+1=7次实验+1次baseline=8次
如果考虑模块插入部位的变化,组合数剧增。
'''
# TODO 实验0:baseline
model = YOLO('yolov8n.yaml')
model.train(data=r'D:\360MoveData\Users\hp\Desktop\maduo\data.yaml', epochs=300, imgsz=640, batch=2, workers=0, pretrained=False, save_dir="D:/DeepLearning/ultralytics-main/runs/detect/yolov8yan")
2.default.yaml文件在cfg目录下,里面存放各种参数,读者可以自行了解其含义。
3、最后执行mytrain.py程序就可以开始训练了
训练完毕后文件夹如下,其中有最优模型参数,模型配置,训练曲线图等等。
六、图片预测
新建一个mypredict.py脚本,只需要更改最后三个路径参数就行,第一个是最优模型路径,第二个是待预测的图片文件夹路径,第三个是存放预测结果图的文件夹路径。
from ultralytics.engine.predictor import BasePredictor
from ultralytics.engine.results import Results
from ultralytics.utils import ASSETS, DEFAULT_CFG, ops
class DetectionPredictor(BasePredictor):
"""
A class extending the BasePredictor class for prediction based on a detection model.
Example:
```python
from ultralytics.utils import ASSETS
from ultralytics.models.yolo.detect import DetectionPredictor
args = dict(model='yolov8n.pt', source=ASSETS)
predictor = DetectionPredictor(overrides=args)
predictor.predict_cli()
```
"""
def postprocess(self, preds, img, orig_imgs):
"""Post-processes predictions and returns a list of Results objects."""
preds = ops.non_max_suppression(preds,
self.args.conf,
self.args.iou,
agnostic=self.args.agnostic_nms,
max_det=self.args.max_det,
classes=self.args.classes)
if not isinstance(orig_imgs, list): # input images are a torch.Tensor, not a list
orig_imgs = ops.convert_torch2numpy_batch(orig_imgs)
results = []
for i, pred in enumerate(preds):
orig_img = orig_imgs[i]
pred[:, :4] = ops.scale_boxes(img.shape[2:], pred[:, :4], orig_img.shape)
img_path = self.batch[0][i]
results.append(Results(orig_img, path=img_path, names=self.model.names, boxes=pred))
return results
def predict(cfg=DEFAULT_CFG, use_python=False,model='', source='',save_dir=''):
"""Runs YOLO object detection on an image or video source."""
# source = cfg.source or ASSETS
args = dict(model=model, source=source, save_dir=save_dir)
if use_python:
from ultralytics import YOLO
YOLO(model)(**args)
else:
predictor = DetectionPredictor(overrides=args)
predictor.predict_cli()
if __name__ == '__main__':
predict(model='D:/DeepLearning/ultralytics-main/runs/detect/yolov8yan/weights/best.pt',
source=r'D:\360MoveData\Users\hp\Desktop\maduo\images',
save_dir=r'D:\360MoveData\Users\hp\Desktop\maduo\pre_pic')
自此训练完毕!