YOLOv8教程系列:三、K折交叉验证——让你的每一份标注数据都物尽其用(yolov8目标检测+k折交叉验证法)

YOLOv8教程系列:三、K折交叉验证——让你的每一份标注数据都物尽其用(yolov8目标检测+k折交叉验证法)

0.引言

k折交叉验证(K-Fold
Cross-Validation)是一种在机器学习中常用的模型评估技术,用于估计模型的性能和泛化能力。它的主要作用是在有限的数据集上对模型进行评估,以便更准确地了解模型在新数据上的表现。

K折交叉验证的基本思想是将原始数据集分成K个子集(折),然后依次将每个子集作为验证集,其他K-1个子集作为训练集,进行K次训练和验证。每次验证后,计算模型在验证集上的性能指标,如准确率、精确率、召回率等。最后,将K次验证的性能指标平均,作为模型在整个数据集上的性能估计。

K折交叉验证的作用包括:

  1. 模型性能评估: K折交叉验证可以更准确地评估模型在数据集上的性能,避免因数据分布不均匀而导致评估结果不准确的问题。
  2. 泛化能力估计: 通过在不同的训练集和验证集上进行多次评估,可以更好地估计模型的泛化能力,即模型在新数据上的表现。
  3. 减少过拟合: K折交叉验证可以帮助检测模型是否出现过拟合问题。如果模型在训练集上表现很好,但在验证集上表现较差,可能存在过拟合。
  4. 参数调优: 在每一轮交叉验证中,可以使用不同的参数设置来训练模型,以找到在验证集上表现最好的参数组合。
  5. 数据利用率: K折交叉验证充分利用了数据集中的所有样本,因为每个样本都会在不同的折中被用作训练和验证。

总之,K折交叉验证是一种有助于评估和改进模型性能的重要技术,尤其在数据有限的情况下,它能更准确地估计模型在新数据上的表现。
在这里插入图片描述

1.数据准备

使用交叉验证前,需要把数据准备为yolo格式,不知道如何数据准备的朋友可以看下这篇文章:YOLOv8教程系列:一、使用自定义数据集训练YOLOv8模型(详细版教程,你只看一篇->调参攻略),包含环境搭建/数据准备/模型训练/预测/验证/导出等
.
├── ./data
│ ├── ./data/Annotations
│ │ ├── ./data/Annotations/fall_0.xml
│ │ ├── ./data/Annotations/fall_1000.xml
│ │ ├── ./data/Annotations/fall_1001.xml
│ │ ├── ./data/Annotations/fall_1002.xml
│ │ ├── ./data/Annotations/fall_1003.xml
│ │ ├── ./data/Annotations/fall_1004.xml
│ │ ├── …
│ ├── ./data/images
│ │ ├── ./data/images/fall_0.jpg
│ │ ├── ./data/images/fall_1000.jpg
│ │ ├── ./data/images/fall_1001.jpg
│ │ ├── ./data/images/fall_1002.jpg
│ │ ├── ./data/images/fall_1003.jpg
│ │ ├── ./data/images/fall_1004.jpg
│ │ ├── …
│ ├── ./data/ImageSets
│ └── ./data/labels
│ │ ├── ./data/images/fall_0.txt
│ │ ├── ./data/images/fall_1000.txt
│ │ ├── ./data/images/fall_1001.txt
│ │ ├── ./data/images/fall_1002.txt
│ │ ├── ./data/images/fall_1003.txt
│ │ ├── ./data/images/fall_1004.txt
│ ├── ./data/classes.yaml
其中,特别要注意的一点是,需要新建个classes.yaml的文件,然后将自己的标签按序填写,如下所示:

names:
  0: your_label_1
  1: your_label_2

2.代码准备

下面代码可以什么都不用改直接运行,前提是按我的数据格式,这个代码放在data的上层目录中

import datetime
import shutil
from pathlib import Path
from collections import Counter
import os

import yaml
import numpy as np
import pandas as pd
from ultralytics import YOLO
from sklearn.model_selection import KFold

# 定义数据集路径
dataset_path = Path('./data')  # 替换成你的数据集路径

# 获取所有标签文件的列表
labels = sorted(dataset_path.rglob("*labels/*.txt"))  # 所有标签文件在'labels'目录中

# 获取当前文件的绝对路径
current_file_path = os.path.abspath(__file__)

# 获取当前文件所在的文件夹路径(即当前文件的根目录)
root_directory = os.path.dirname(current_file_path)

print("当前文件运行根目录:", root_directory)

# 从YAML文件加载类名
yaml_file = 'data/classes.yaml'
with open(yaml_file, 'r', encoding="utf8") as y:
    classes = yaml.safe_load(y)['names']
cls_idx = sorted(classes.keys())

# 创建DataFrame来存储每张图像的标签计数
indx = [l.stem for l in labels]  # 使用基本文件名作为ID(无扩展名)
labels_df = pd.DataFrame([], columns=cls_idx, index=indx)

# 计算每张图像的标签计数
for label in labels:
    lbl_counter = Counter()

    with open(label, 'r') as lf:
        lines = lf.readlines()

    for l in lines:
        # YOLO标签使用每行的第一个位置的整数作为类别
        lbl_counter[int(l.split(' ')[0])] += 1

    labels_df.loc[label.stem] = lbl_counter

# 用0.0替换NaN值
labels_df = labels_df.fillna(0.0)

# 使用K-Fold交叉验证拆分数据集
ksplit = 5
kf = KFold(n_splits=ksplit, shuffle=True, random_state=20)  # 设置random_state以获得可重复的结果
kfolds = list(kf.split(labels_df))
folds = [f'split_{n}' for n in range(1, ksplit + 1)]
folds_df = pd.DataFrame(index=indx, columns=folds)

# 为每个折叠分配图像到训练集或验证集
for idx, (train, val) in enumerate(kfolds, start=1):
    folds_df[f'split_{idx}'].loc[labels_df.iloc[train].index] = 'train'
    folds_df[f'split_{idx}'].loc[labels_df.iloc[val].index] = 'val'

# 计算每个折叠的标签分布比例
fold_lbl_distrb = pd.DataFrame(index=folds, columns=cls_idx)
for n, (train_indices, val_indices) in enumerate(kfolds, start=1):
    train_totals = labels_df.iloc[train_indices].sum()
    val_totals = labels_df.iloc[val_indices].sum()

    # 为避免分母为零,向分母添加一个小值(1E-7)
    ratio = val_totals / (train_totals + 1E-7)
    fold_lbl_distrb.loc[f'split_{n}'] = ratio

# 创建目录以保存分割后的数据集
save_path = Path(dataset_path / f'{datetime.date.today().isoformat()}_{ksplit}-Fold_Cross-val')
save_path.mkdir(parents=True, exist_ok=True)

# 获取图像文件列表
images = sorted((dataset_path / 'images').rglob("*.jpg"))  # 更改文件扩展名以匹配你的数据
ds_yamls = []

# 循环遍历每个折叠并复制图像和标签
for split in folds_df.columns:
    # 为每个折叠创建目录
    split_dir = save_path / split
    split_dir.mkdir(parents=True, exist_ok=True)
    (split_dir / 'train' / 'images').mkdir(parents=True, exist_ok=True)
    (split_dir / 'train' / 'labels').mkdir(parents=True, exist_ok=True)
    (split_dir / 'val' / 'images').mkdir(parents=True, exist_ok=True)
    (split_dir / 'val' / 'labels').mkdir(parents=True, exist_ok=True)



    # 创建数据集的YAML文件
    dataset_yaml = split_dir / f'{split}_dataset.yaml'
    ds_yamls.append(dataset_yaml.as_posix())
    split_dir = os.path.join(root_directory, split_dir.as_posix())

    with open(dataset_yaml, 'w') as ds_y:
        yaml.safe_dump({
            'path': split_dir,
            'train': 'train',
            'val': 'val',
            'names': classes
        }, ds_y)
print(ds_yamls)

# 将文件路径保存到一个txt文件中
with open('data/file_paths.txt', 'w') as f:
    for path in ds_yamls:
        f.write(path + '\n')

# 为每个折叠复制图像和标签到相应的目录
for image, label in zip(images, labels):
    for split, k_split in folds_df.loc[image.stem].items():
        # 目标目录
        img_to_path = save_path / split / k_split / 'images'
        lbl_to_path = save_path / split / k_split / 'labels'

        # 将图像和标签文件复制到新目录中
        # 如果文件已存在,可能会抛出SamefileError
        shutil.copy(image, img_to_path / image.name)
        shutil.copy(label, lbl_to_path / label.name)

运行代码后,会在data目录下生成一个文件夹,里面有5种不同划分的数据集

3.开始训练

下面的代码放在和上面代码的同级目录中,训练参数可以根据自己情况进行调整

from ultralytics import YOLO

weights_path = 'checkpoints/yolov8s.pt'
model = YOLO(weights_path, task='train')
ksplit = 5
# 从文本文件中加载内容并存储到一个列表中
ds_yamls = []
with open('data/file_paths.txt', 'r') as f:
    for line in f:
        # 去除每行末尾的换行符
        line = line.strip()
        ds_yamls.append(line)

# 打印加载的文件路径列表
print(ds_yamls)


results = {}
for k in range(ksplit):
    dataset_yaml = ds_yamls[k]
    model.train(data=dataset_yaml, batch=6, epochs=2, imgsz=1280, device=0, workers=8, single_cls=False, ) 

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/85794.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

elaticsearch(1)

1.简介 Elasticsearch是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别的数据。 Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引…

Electron之初体验

Electron是一款使用Html、Css、JS开发跨平台桌面应用的框架。 话不多说直接开搞。 必坑指南: node版本>18.0使用淘宝镜像安装npm相关包;把下面两行配置放到你的npmrc文件中electron_mirrorhttps://npm.taobao.org/mirrors/electron/ ELECTRON_MIRRO…

手写 Mybatis-plus 基础架构(工厂模式+ Jdk 动态代理统一生成代理 Mapper)

这里写目录标题 前言温馨提示手把手带你解析 MapperScan 源码手把手带你解析 MapperScan 源码细节剖析工厂模式Jdk 代理手撕脚手架,复刻 BeanDefinitionRegistryPostProcessor手撕 FactoryBean代理 Mapper 在 Spring 源码中的生成流程手撕 MapperProxyFactory手撕增…

浅析Linux SCSI子系统:调试方法

文章目录 SCSI日志调试功能scsi_logging_level调整SCSI日志等级 SCSI trace events使能SCSI trace events方式一:通过set_event接口方式二:通过enable 跟踪trace信息 相关参考 SCSI日志调试功能 SCSI子系统支持内核选项CONFIG_SCSI_LOGGING配置日志调试…

C++day2(笔记整理)

一、Xmind整理&#xff1a; 二、上课笔记整理&#xff1a; 1.左值引用 #include <iostream> using namespace std;int main() {int a 100;int &ra a; //定义了变量a的引用racout << &a << endl;cout << "&ra" << &…

wx原生微信小程序入门常用总结

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、定义值和修改值1、定义值2、修改值&#xff08;1&#xff09;代码&#xff08;2&#xff09;代码说明&#xff08;3&#xff09;注意点 二、点击事件三、微…

机器人TF坐标系变换与一些可视化工具的应用

TF坐标在ROS中是一个非常重要的概念&#xff0c;因为机器人在做日常操作任务的时候&#xff0c;对于其所在位置和朝向是需要时刻知道的&#xff0c;而机器人是由很多节点组成的协同任务&#xff0c;对于每个部件&#xff0c;我们需要知道它的位姿(位置和朝向)&#xff0c;这使得…

React+Typescript使用接口泛型处理props

好 刚讲完组件 那么 这次 我们来看一下 数据传递的 props 还是上文的案例 例如 我们想将 title 传给Hello组件 之前我们可以直接这样 以一个标签属性的形式传过去 而我们在子组件中 这样去使用 但现在 我们从编辑器中都可以看出 这种写法已经不行了 然后 我们将 hello 组件…

Windows 11 + Ubuntu20.04 双系统 坑里爬起来

ThinkPad x390 安装双系统&#xff0c;原有的磁盘太小&#xff0c;扩充了磁盘重新装系统&#xff0c;出现的问题&#xff0c;加以记录。 1. windows和ubuntu谁先安装&#xff0c;两个都可以&#xff0c;一般建议先安装windows&#xff0c;后安装ubuntu 2. 安装windows后&…

c++--动态规划回文串问题

1.回文子串 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给定一个字符串 s &#xff0c;请计算这个字符串中有多少个回文子字符串。 具有不同开始位置或结束位置的子串&#xff0c;即使是由相同的字符组成&#xff0c;也会被视作不同的子串。 示…

无涯教程-Perl - time函数

描述 此函数返回自纪元以来的秒数(对于大多数系统,是1970年1月1日UTC,00:00:00&#xff1b;对于Mac OS,是1904年1月1日,00:00:00)。适用于gmtime和本地时间。 语法 以下是此函数的简单语法- time返回值 此函数返回自纪元后数秒的整数。 例 以下是显示其基本用法的示例代…

如何实现24/7客户服务自动化?建设智能客服知识库

客户自助服务是指用户通过企业或者第三方建立的网络平台或者终端&#xff0c;实现相关的自定义处理。实现客户服务自动化&#xff0c;对提高客户满意度、维持客户关系至关重要。客户服务自动化可以帮助企业以更快的速度和更高的效率来满足客户的售后服务要求&#xff0c;以进一…

ssm助学贷款系统源码和论文

ssm助学贷款系统源码和论文050 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&am…

使用vscode编写插件-php语言

https://blog.csdn.net/qq_45701130/article/details/125206645 一、环境搭建 1、安装 Visual Studio Code 2、安装 Node.js 3、安装 Git 4、安装生产插件代码的工具&#xff1a;npm install -g yo generator-code 二、创建工程 yo code 选择项解释&#xff1a; 选择编写扩…

JVM性能调优

java 如何跨平台&#xff0c;如何一次编译到处执行 是由于java在不同的jvm上编译&#xff0c;jvm在软件层面屏蔽不同操作系统在底层硬件与指令上的区别。 jvm 包括 new 的对象都是放在堆中 栈&#xff0c;给线程单独使用&#xff08;线程私有&#xff09;&#xff0c;存储一个…

Java-进程调度算法

文章目录 为什么要设置进程调度算法&#xff1f;分类1. 先进先出&#xff08;FIFO&#xff09;算法优缺点FIFO代码示例 2. 短作业优先&#xff08;SJF&#xff09;算法优缺点示例代码 3. 优先级算法&#xff08;Priority scheduling&#xff09;优缺点示例代码 4. 时间片轮转算…

Midjourney API 国内申请及对接方式

在人工智能绘图领域&#xff0c;想必大家听说过 Midjourney 的大名吧&#xff01; Midjourney 以其出色的绘图能力在业界独树一帜。无需过多复杂的操作&#xff0c;只要简单输入绘图指令&#xff0c;这个神奇的工具就能在瞬间为我们呈现出对应的图像。无论是任何物体还是任何风…

Docker容器与虚拟化技术:Docker consul 实现服务注册与发现

目录 一、理论 1.Docker consul 二、实验 1.consul部署 2. consul-template部署 三、总结 一、理论 1.Docker consul &#xff08;1&#xff09;服务注册与发现 服务注册与发现是微服务架构中不可或缺的重要组件。起初服务都是单节点的&#xff0c;不保障高可用性&…

解决Linux虚拟机IP无法显示的问题

目录 问题&#xff1a; 两种解决方案&#xff0c;供大家选择使用哦。 第一种解决办法&#xff1a; 第二种解决办法&#xff1a; 1、查看ens33网卡的配置 2、修改文件 扩展&#xff1a; 问题&#xff1a; Linux命令 ip a 查看ip时&#xff0c;无法显示IP的解决办法。 两…

lnmp(docker)

1. 建立工作目录 [rootdocker ~]# mkdir /opt/nginx [rootdocker ~]# cd /opt/nginx [rootdocker nginx]# rz -E rz waiting to receive. #上传 nginx 安装包 nginx-1.12.0.tar.gz[rootdocker nginx]# rz -E rz waiting to receive. #上传 wordpress 服务包 wordpress-4.9.4-z…