- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
一、配置环境
在进行本周任务之前,先运行一下入门篇确保环境是正常的
1.官网下载源码
2.安装环境
使用之前学习安装的pytorch环境即可
二、使用自己的数据集
这里使用训练营提供的水果数据集
Annoattions里面是xml文件
image文件夹下是JPG文件
1.运行split_train_val.py文件
ImageSets文件夹下面有个Main子文件夹,其下面存放了train.txt、val.txt、test.txt 和 trainval.txt 四个文件,它们是通过split_train val.py 文件来生成的
文件内容如下
python
# 导入必要的库
# 导入必要的库
import os
import random
import argparse
# 创建一个参数解析器
parser = argparse.ArgumentParser()
# 添加命令行参数,用于指定XML文件的路径,默认为"Annotations"文件夹
parser.add_argument('--xml_path', default='annotations/', type=str, help='input xml label path')
# 添加命令行参数,用于指定txt标签文件的路径,默认为"ImageSets/Main"文件夹
parser.add_argument('--txt_path', default='ImageSets/Main/', type=str, help='output txt label path')
# 解析命令行参数opt = parser.parse_args()
args = parser.parse_args(args=[])
opt =args
# 定义训练验证和测试集的划分比例
trainval_percent = 1.0 # 使用全部数据
train_percent = 0.9 # 训练集占验证集的90%
# 设置xml文件的路径,并根据命令行参数指定
xmlfilepath = opt.xml_path
print("xmlfilepath: ", xmlfilepath)
# 设置txt文件的路径,并根据命令行参数指定
txtfilepath = opt.txt_path
# 获取xml文件夹中的所有xml文件列表
total_xml = os.listdir(xmlfilepath)
# 如果输出txt标签文件的文件夹不存在,创建它
if not os.path.exists(txtfilepath):
os.makedirs(txtfilepath)
# 获取xml文件的总数
num = len(total_xml)
# 创建一个包含所有xml文件索引的列表
list_index = range(num)
# 计算训练验证集的数量
tv = int(num*trainval_percent)
# 计算训练集的数量
tr = int(num*train_percent)
# 从所有xml文件索引中随机选择出训练验证集的索引
trainval = random.sample(list_index, tv)
# 从训练验证集的索引中随机选择出训练集的索引
train = random.sample(list_index, tr)
# 打开要写入的训练验证集、测试集、训练集、验证集的txt文件
file_trainval = open(txtfilepath + '/trainval.txt', 'w')
file_test = open(txtfilepath + '/test.txt', 'w')
file_train = open(txtfilepath + '/train.txt', 'w')
file_val = open(txtfilepath + '/val.txt', 'w')
# 遍历所有xml文件的索引
for i in list_index:
name = total_xml[i][:-4] + '\n' # 获取所有文件的名称(去掉后缀.xml),并添加换行符
# 如果该索引在训练验证集中, 写入训练验证集txt文件,否则写入测试集txt文件
if i in trainval:
file_trainval.write(name) #
if i in train: # 如果该索引在训练集中, 写入训练集txt文件,否则写入验证集txt文件
file_train.write(name)
else:
file_val.write(name)
else:
file_test.write(name)
# 关闭所有打开的文件
file_trainval.close()
file_train.close()
file_val.close()
file_test.close()
运行得到四个文件
2.运行val_label.py
python
#-*- coding:utf-8 -*-
#导入必要的库
import xml.etree.ElementTree as ET
import os
from os import getcwd
#定义数据集的名称
sets =['train','val','test']
#请根据您的数据集修改这些类别名称
# 下面的两行代码,列表的里面的单词,除了首字母的大小写不一样,其他的是一样的,如果运行首字母是大写的代码,那么labels文件夹的txt文件的内容是空的,如果运行首字母是小写的代码,那么labels文件夹的txt文件的内容是有的,这很神奇,不知道原因是什么。
# classes =['Banana','Snake fruit','Dragon fruit','Pineapple']
classes = ["banana","snake fruit","dragon fruit","pineapple"]
#获取当前工作目录的绝对路径
abs_path = os.getcwd()
print(abs_path)
#定义一个函数,将边界框的坐标从绝对值转换为相对于图像大小的比例
def convert(size,box):
dw = 1./(size[0]) #计算图像宽度的倒数
dh = 1./(size[1]) #计算图像高度的倒数
x = (box[0]+box[1])/2.0-1 #计算中心点的x坐标
y = (box[2]+box[3])/2.0-1 # 计算中心点的y坐标
w= box[1]- box[0] # 计算边界框的宽度
h = box[3] - box[2] # 计算边界框的高度
x = x * dw # 缩放x坐标
w = w * dw # 缩放宽度
y = y * dh # 缩放y坐标
h = h * dh # 缩放高度
return x, y, w, h
# 定义一个函数,将标注文件从XML格式转换为YOLO格式
def convert_annotation(image_id):
in_file = open('annotations/%s.xml' % (image_id),encoding='UTF-8') # 打开XML标注文件
out_file = open('labels/%s.txt'%(image_id),'w') # 打开要写入的YOL0格式标签文件
tree =ET.parse(in_file) #解析XML文件
root = tree.getroot()
filename = root.find('filename').text # 获取图像文件名
filenameFormat=filename.split(".")[1] # 获取文件格式
size = root.find('size') # 获取图像尺寸信息
w = int(size.find('width').text) # 获取图像宽度
h = int(size.find('height').text) #获取图像高度
for obj in root.iter('object'):
difficult = obj.find('difficult').text # 获取对象的难度标志
cls = obj.find('name').text #获取对象的类别名称
if cls not in classes or int(difficult)== 1:
continue
cls_id = classes.index(cls) # 获取类别的索引
xmlbox = obj.find('bndbox') # 获取边界框坐标信息
b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),float(xmlbox.find('ymax').text))
b1,b2,b3,b4 = b
# 标注越界修正
if b2 > w:
b2 = w
if b4 > h:
b4 = h
b=(b1,b2,b3,b4)
bb=convert((w,h),b) #调用convert函数,将边界框坐标转换为Y0OLO格式
out_file.write(str(cls_id)+" "+" ".join([str(a) for a in bb])+'\n') #写入YOLO格式标签文件
return filenameFormat
#获取当前工作目录
wd = getcwd()
#遍历每个数据集(train、val、test)
for image_set in sets:
#如果labels目录不存在,创建它
if not os.path.exists('./labels/'):
os.makedirs('./labels/')
#从数据集文件中获取图像ID列表
image_ids = open('ImageSets/Main/%s.txt'%(image_set)).read().strip().split()
#打开要写入的文件,写入图像的文件路径和格式
list_file =open('./%s.txt'%(image_set),'w')
for image_id in image_ids:
filenameFormat=convert_annotation(image_id)
list_file.write(abs_path +'images/%s.%s\n'%(image_id,filenameFormat)) #注意你的图片格式,如果是.jpg记得修改
list_file.close()
生成下面三个文件
3.创建yaml文件
python
train: ultralytics/fruit_recongize/data_fruit_recongize/train.txt #这里需要换成绝对路径
val: ultralytics/fruit_recongize/data_fruit_recongize/val.txt #这里需要换成绝对路径
nc: 4 #number of classes,根据类别数目实际填写,本次训练的类别有4种
names: ["banana","snake fruit","dragon fruit","pineapple"] #改成自己的类别
三、训练
编写训练文件
python
from ultralytics import YOLO
if __name__ == '__main__':
# Load a model
model = YOLO("yolov8s.yaml") # build a new model from scratch 2-ByK
#Use the model
model.train(data=r"ultralytics/fruit_recongize/data_fruit_recongize/fruit.yaml",
seed=0,
epochs=200,
batch=4,
workers=2)
四、训练参数设置
python
#ultralytics YOLO,AGPL-3.0 许可证,由K同学啊注解
#默认的训练设置和超参数,用于中度增强 COC0 训练
task:detect #(str)YOL0 任务,例如 detect、segment、classify、pose
mode:train #(str)YOL0 模式,例如 train、val、predict、export、track、benchmark
# 训练设置-------------------------------------------
model: #(str,可选)模型文件路径,例如yolov8n.pt、yolov8n.yaml
data: #./paper data/ab.yaml #(str,可选) 数据文件路径,例如 coco128.yamldata:
epochs: 100 #(int)训练的轮次数
patience: 50 #(int)提前停止训练的等待周期数,如果没有明显的改进
batch: 1 #(int)每批处理的图像数量(-1 表示自动批处理)
imgsz: 640 #(int | list)输入图像的大小,以像素为单位,用于训练和验证模式,或以列表[w,h]形式用于预测和导出模式
save: True #(bool)保存训练检查点和预测结果
save_period: -1 #(int)每隔 x 个周期保存一个检査点(如果 <1 则禁用)
cache: False #(bool)使用缓存加载数据(True/ram、disk或False)
device: 0 #(int | str | list,可选)运行模型的设备,例如 cuda device=0 或 device=0,1,2,3 或 device=cpu
workers: 4 #(int)数据加载的工作线程数(每个 DDP 会有一个)
project: #(str,可选)项目名称
name: #(str,可选)实验名称,结果保存在project/name'目录下
exist_ok: False #(bool)是否覆盖现有的实验
pretrained: True #(bool| str)是否使用预训练模型(True 或加载权重的模型路径字符串)
optimizer: auto #(str)优化器选择,选项=[SGD、Adam、Adamax、AdamW、NAdam、RAdam、RMSProp、auto]
verbose: True #(bool)是否打印详细输出
seed: 0 #(int)随机种子,用于可重复性
deterministic: True #(bool)是否启用确定性模式
single_cls: False #(bool)是否将多类数据训练为单一类别
rect: False #(bool)如果模式='train',则进行矩形训练;如果模式='val',则进行矩形验证
cos_lr: False #(bool)是否使用余弦学习率调度器
close_mosaic: 10 #(int)在最后几个周期内禁用马赛克增强(0 表示禁用)
resume: False #(bool)是否从上次检查点恢复训练
amp: True #(bool)是否启用自动混合精度(AMP)训练,选项=[True,False],True 表示运行 AMP 检查
fraction: 1.0 #(float)训练集数据分数(默认为 1.0,使用训练集中的所有图像)
profile: False #(bool)在训练期间记录 ONNX 和 TensorRT 速度以供记录器使用
freeze: None #(int | list,可选)冻结前n层,或在训练期间冻结的层索引列表
# 分割
overlap_mask: True #(bool)训练期间是否允许蒙版重叠(仅适用于分割训练)
mask_ratio: 4 #(int)蒙版下采样比率(仅适用于分割训练)
#分类
dropout: 0.0 #(float)是否使用 dropout 正则化(仅适用于分类训练)
#验证/测试设置----------------------------------------
val: True #(boo1)训练期间是否进行验证/测试
split: val #(str)用于验证的数据集分制,例如 'val'、'test'或'train'
save_json: False #(bool)是否将结果保存为 JSON 文件
save_hybrid: False #(bool)是否保存标签的混合版本(标签 + 额外的预测)
conf #(float,可选)用于检测的对象置信度阈值(默认 0.25 用于预测,0.001 用于验证)
iou: 0.7 #(float)NMS的交并比(IoU)阈值
max_det: 300 #(int)每张图像的最大检测数
half: False #(bool)是否使用半精度(FP16)
dnn: False #(bool)是否使用 OpenCV DNN 进行 ONNX 推理
plots: True #(bool)在训练/验证期间保存图形
# 预测设置-------------------------------------------
source: #(str,可选)图像或视频的源目录
show: False #(bool)如果可能的话是否显示结果
save_txt: False #(bool)是否将结果保存为.txt 文件
save_conf: False #(bool)是否保存带有置信度分数的结果
save_crop: False #(bool)是否保存裁剪后的带有结果的图像
show_labels: True #(bool)是否在图形中显示对象标签
show_conf: True #(bool)是否在图形中显示对象置信度分数
vid_stride: 1 #(int)视频帧率跨度
stream_buffer: False #(bool)是否缓存所有流式帧(True)或返回最新的帧(False)
line_width: #(int, 可选)边界框的线宽,如果缺失则自动设置
visualize: False #(bool)是否可视化模型特征
augment: False #(bool)是否对预测源应用图像增强
agnostic_nms: False #(bool)是否进行类别无关的 NMS
classes: #(int | list[int],可选)按类别筛选结果,例如 classes=0,或 classes=[0,2,3]
retina_masks: False #(bool)是否使用高分辨率分割蒙版
boxes: True #(bool)在分割预测中显示边界框
#导出设置--------------------------------------------
format: torchscript #(str)导出格式,可选项请査看 https://docs.ultralytics.com/modes/export/#export-formats
keras: False #(bool)是否使用 Kera=s
optimize: False #(bool) Torchscript: 优化为移动设备
int8: False #(bool) CoreML/TF INT8 量化
dynamic: False #(bool)ONNX/TF/TensorRT: 动态轴
simplify: False #(bool) ONNX: 简化模型
opset: #(int,可选)ONNX: opset版本
workspace: 4 #(int)TensorRT:工作空间大小(GB)
nms: False #(bool)CoreML:添加 NMS
# 超参数---------------------------------------------
lro: 0.01 #(float) 初始学习率(例如,SGD=1E-2,Adam=1E-3)
lrf: 0.01 #(float)最终学习率(1r0 *lrf)
momentum: 0.937 #(float)SGD 动量/Adam betal
weight_decay: 0.0005 #(float) 优化器权重衰减 5e-4
warmup_epochs: 3.0 #(float)预热周期数(分数也可以)
warmup_momentum: 0.8 #(float)预热初始动量
warmup_bias_lr: 0.1 #(float)预热初始偏置 lr
box: 7.5 #(float)目标框损失增益
cls: 0.5 #(float)类别损失增益(与像素一起缩放)
dfl: 1.5 #(float)DFL 损失增益
pose: 12.0 #(float)姿势损失增益
kobj: 1.0 #(float)关键点 obj 损失增益
label_smoothing: 0.0 #(float)标签平滑化(分数)
nbs: 64 #(int)名义批次大小
hsv_h: 0.015 #(float)图像 HSV-Hue 增强(分数)
hsv_s: 0.7 #(float)图像 HSV-Saturation 增强(分数)
hsv_v: 0.4 #(float)图像 HSV-Value 增强(分数)
degrees: 0.0 #(float)图像旋转( +/- 度)
translate: 0.1 #(float)图像平移( +/- 分数)
scale: 0.5 #(float)图像缩放( +/- 增益)
shear: 0.0 #(float)图像剪切( +/- 度)
perspective: 0.0 #(float)图像透视变换( +/- 分数),范围 0-0.001
flipud: 0.0 #(float)图像上下翻转(概率)
fliplr: 0.5 #(float)图像左右翻转(概率)
mosaic: 1.0 #(float)图像马赛克增强(概率)
mixup: 0.0 #(float)图像混合增强(概率)
copy_paste: 0.0 #(float)段复制粘贴(概率)
#自定义 config.yaml----------------------------------
cfg: #(str,可选)用于覆盖默认.yaml 的自定义配置
#跟踪器设置------------------------------------------
tracker: botsort.yaml #(str)跟踪器类型,选项=[botsort.yaml, bytetrack.yaml]
五、总结
这次任务和Y2很像,也算是一种复习,把这一个步骤来过。对与召回率较低的,要进行数据增强来改善结果