Datawhale AI 夏令营-CV 方向-Task 2

一、baseline上分思路

1.数据集划分

1.1原划分代码py

import os
import cv2
import pandas as pd
import glob

def setup_directories():
    base_dir = "yolo-dataset"
    subdirs = ["train", "val"]
    for subdir in subdirs:
        dir_path = os.path.join(base_dir, subdir)
        if not os.path.exists(dir_path):
            os.makedirs(dir_path)
    return base_dir

def create_dataset_config(base_dir):
    dir_path = os.path.abspath(base_dir) + "/"
    config_path = os.path.join(base_dir, "yolo.yaml")
    with open(config_path, "w", encoding="utf-8") as file:
        file.write(
            f"""
path: {dir_path}
train: train/
val: val/

names:
    0: 非机动车违停
    1: 机动车违停
    2: 垃圾桶满溢
    3: 违法经营
"""
        )

def process_videos(annotations, videos, category_labels, output_dir, is_train=True):
    for anno_path, video_path in zip(annotations, videos):
        print(f"Processing video: {video_path}")
        anno_df = pd.read_json(anno_path)
        cap = cv2.VideoCapture(video_path)
        fps = cap.get(cv2.CAP_PROP_FPS)
        total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
        duration = total_frames / fps
        frame_step = get_frame_step(duration)

        frame_idx = 0
        while True:
            ret, frame = cap.read()
            if not ret:
                break

            if frame_idx % frame_step == 0:
                process_frame(
                    frame,
                    anno_df,
                    frame_idx,
                    category_labels,
                    output_dir,
                    video_path,
                    anno_path,
                )
            frame_idx += 1
        cap.release()

def get_frame_step(duration):
    if duration <= 5:
        return 2
    elif 5 < duration <= 10:
        return 5
    elif 10 < duration <= 20:
        return 10
    else:
        return 50

def process_frame(
    frame, anno_df, frame_idx, category_labels, output_dir, video_path, anno_path
):
    img_height, img_width = frame.shape[:2]
    frame_anno = anno_df[anno_df["frame_id"] == frame_idx]
    img_filename = os.path.join(
        output_dir, f"{os.path.basename(anno_path)[:-5]}_{frame_idx}.jpg"
    )
    cv2.imwrite(img_filename, frame)
    if len(frame_anno) != 0:
        create_annotation_file(
            frame_anno,
            img_width,
            img_height,
            category_labels,
            output_dir,
            anno_path,
            frame_idx,
        )

def create_annotation_file(
    frame_anno, img_width, img_height, category_labels, output_dir, anno_path, frame_idx
):
    anno_filename = os.path.join(
        output_dir, f"{os.path.basename(anno_path)[:-5]}_{frame_idx}.txt"
    )
    with open(anno_filename, "w") as file:
        for category, bbox in zip(
            frame_anno["category"].values, frame_anno["bbox"].values
        ):
            category_idx = category_labels.index(category)
            x_min, y_min, x_max, y_max = bbox
            x_center = (x_min + x_max) / 2 / img_width
            y_center = (y_min + y_max) / 2 / img_height
            width = (x_max - x_min) / img_width
            height = (y_max - y_min) / img_height
            file.write(f"{category_idx} {x_center} {y_center} {width} {height}\n")

if __name__ == "__main__":
    base_dir = setup_directories()
    create_dataset_config(base_dir)
    category_labels = ["非机动车违停", "机动车违停", "垃圾桶满溢", "违法经营"]

    train_annos = glob.glob("训练集(有标注第一批)/标注/*.json")
    train_videos = glob.glob("训练集(有标注第一批)/视频/*.mp4")
    train_annos.sort()
    train_videos.sort()
    process_videos(
        train_annos[:40],
        train_videos[:40],
        category_labels,
        os.path.join(base_dir, "train"),
        is_train=True,
    )

    val_annos = train_annos[-13:]
    val_videos = train_videos[-13:]
    process_videos(
        val_annos,
        val_videos,
        category_labels,
        os.path.join(base_dir, "val"),
        is_train=False,
    )

目录设置:

  • setup_directories() 函数创建了一个名为 `“yolo-dataset” 的基础目录,并在其中创建 “train” 和 “val” 两个子目录。这是为了后续处理训练和验证数据做准备。

配置文件创建:

  • create_dataset_config() 函数在 “yolo-dataset” 目录下创建了一个 “yolo.yaml” 文件,记录了数据集的路径以及4个类别(“非机动车违停”, “机动车违停”, “垃圾桶满溢”, “违法经营”)的定义。这个文件可以作为 YOLO 模型训练的配置文件使用。

视频和标注数据处理:

  • process_videos() 函数接收视频文件路径、标注文件路径以及类别标签,逐个处理每个视频:
    • 读取视频并计算帧率和总帧数。
    • 根据视频长度设置不同的帧步长,以控制处理的帧数。
    • 对于每个需要处理的帧,调用 process_frame() 函数:
      • 保存当前帧为图像文件。
      • 根据标注数据,为当前帧生成 YOLO 格式的标注文件,包括类别索引、中心坐标、宽高比等信息。

数据划分:

  • 在主程序中,将可用的训练集视频和标注数据分为训练集(前40个)和验证集(后13个),分别调用 process_videos() 函数进行处理。
  • 训练集图像和标注文件保存在 “train” 子目录下,验证集保存在 “val” 子目录下。

1.2修改划分代码py

修改思路:

  • 先将所有的标注文件读取到一个列表中,然后再随机划分为训练集和验证集。
  • 在创建训练集和验证集目录时,先创建一个大的 “annotations” 文件夹,将所有的标注文件保存在这里。
  • 然后根据训练集和验证集的划分,将图像文件保存到 “train” 和 “val” 目录下。

修改后的代码:

import os
import cv2
import pandas as pd
import glob
import random

def setup_directories(base_dir):
    subdirs = ["train", "val", "annotations"]
    for subdir in subdirs:
        dir_path = os.path.join(base_dir, subdir)
        if not os.path.exists(dir_path):
            os.makedirs(dir_path)
    return base_dir

def create_dataset_config(base_dir):
    dir_path = os.path.abspath(base_dir) + "/"
    config_path = os.path.join(base_dir, "yolo.yaml")
    with open(config_path, "w", encoding="utf-8") as file:
        file.write(
            f"""
path: {dir_path}
train: train/
val: val/

names:
    0: 非机动车违停
    1: 机动车违停
    2: 垃圾桶满溢
    3: 违法经营
"""
        )

def process_videos(annotations, videos, category_labels, output_dir, is_train=True):
    for anno_path, video_path in zip(annotations, videos):
        print(f"Processing video: {video_path}")
        anno_df = pd.read_json(anno_path)
        cap = cv2.VideoCapture(video_path)
        fps = cap.get(cv2.CAP_PROP_FPS)
        total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
        duration = total_frames / fps
        frame_step = get_frame_step(duration)

        frame_idx = 0
        while True:
            ret, frame = cap.read()
            if not ret:
                break

            if frame_idx % frame_step == 0:
                process_frame(
                    frame,
                    anno_df,
                    frame_idx,
                    category_labels,
                    output_dir,
                    video_path,
                    anno_path,
                )
            frame_idx += 1
        cap.release()

def get_frame_step(duration):
    if duration <= 5:
        return 2
    elif 5 < duration <= 10:
        return 5
    elif 10 < duration <= 20:
        return 10
    else:
        return 50

def process_frame(
    frame, anno_df, frame_idx, category_labels, output_dir, video_path, anno_path
):
    img_height, img_width = frame.shape[:2]
    frame_anno = anno_df[anno_df["frame_id"] == frame_idx]
    img_filename = os.path.join(
        output_dir, f"{os.path.basename(anno_path)[:-5]}_{frame_idx}.jpg"
    )
    cv2.imwrite(img_filename, frame)
    if len(frame_anno) != 0:
        create_annotation_file(
            frame_anno,
            img_width,
            img_height,
            category_labels,
            os.path.join(base_dir, "annotations"),
            anno_path,
            frame_idx,
        )

def create_annotation_file(
    frame_anno, img_width, img_height, category_labels, output_dir, anno_path, frame_idx
):
    anno_filename = os.path.join(
        output_dir, f"{os.path.basename(anno_path)[:-5]}_{frame_idx}.txt"
    )
    with open(anno_filename, "w") as file:
        for category, bbox in zip(
            frame_anno["category"].values, frame_anno["bbox"].values
        ):
            category_idx = category_labels.index(category)
            x_min, y_min, x_max, y_max = bbox
            x_center = (x_min + x_max) / 2 / img_width
            y_center = (y_min + y_max) / 2 / img_height
            width = (x_max - x_min) / img_width
            height = (y_max - y_min) / img_height
            file.write(f"{category_idx} {x_center} {y_center} {width} {height}\n")

if __name__ == "__main__":
    base_dir = setup_directories("yolo-dataset")
    create_dataset_config(base_dir)
    category_labels = ["非机动车违停", "机动车违停", "垃圾桶满溢", "违法经营"]

    all_annos = glob.glob("训练集(有标注第一批)/标注/*.json")
    all_videos = glob.glob("训练集(有标注第一批)/视频/*.mp4")
    all_annos.sort()
    all_videos.sort()

    # 随机划分训练集和验证集
    train_size = int(len(all_annos) * 0.8)
    train_indices = random.sample(range(len(all_annos)), train_size)
    train_annos = [all_annos[i] for i in train_indices]
    train_videos = [all_videos[i] for i in train_indices]
    val_annos = [all_annos[i] for i in range(len(all_annos)) if i not in train_indices]
    val_videos = [all_videos[i] for i in range(len(all_videos)) if i not in train_indices]

    # 处理训练集
    process_videos(
        train_annos,
        train_videos,
        category_labels,
        os.path.join(base_dir, "train"),
        is_train=True,
    )

    # 处理验证集
    process_videos(
        val_annos,
        val_videos,
        category_labels,
        os.path.join(base_dir, "val"),
        is_train=False,
    )

主要改动如下:

  1. setup_directories() 函数中,增加了 “annotations” 子目录的创建。
  2. create_annotation_file() 函数中,将标注文件保存到 “annotations” 子目录下,而不是分别保存到训练集和验证集目录中。
  3. 在主程序中,首先将所有的标注文件路径和视频文件路径保存到 all_annos 和 all_videos 列表中。
  4. 然后使用 random.sample() 函数,随机划分训练集和验证集,得到 train_annos、train_videos、val_annos 和 val_videos 列表。
  5. 最后分别调用 process_videos() 函数处理训练集和验证集,将图像文件保存到 “train” 和 “val” 目录下。
    这样修改后,代码就可以先将所有的标注文件保存到 “annotations” 目录,然后再按照 8:2 的比例随机划分为训练集和验证集,并将图像文件保存到对应的目录中。

1.3继续修改划分代码py

让图像文件和对应的标注文件保存在同一个文件夹内

import os
import cv2
import pandas as pd
import glob
import random

def setup_directories(base_dir):
    subdirs = ["train", "val"]
    for subdir in subdirs:
        dir_path = os.path.join(base_dir, subdir)
        if not os.path.exists(dir_path):
            os.makedirs(dir_path)
    return base_dir

def create_dataset_config(base_dir):
    dir_path = os.path.abspath(base_dir) + "/"
    config_path = os.path.join(base_dir, "yolo.yaml")
    with open(config_path, "w", encoding="utf-8") as file:
        file.write(
            f"""
path: {dir_path}
train: train/
val: val/

names:
    0: 非机动车违停
    1: 机动车违停
    2: 垃圾桶满溢
    3: 违法经营
"""
        )

def process_videos(annotations, videos, category_labels, output_dir, is_train=True):
    for anno_path, video_path in zip(annotations, videos):
        print(f"Processing video: {video_path}")
        anno_df = pd.read_json(anno_path)
        cap = cv2.VideoCapture(video_path)
        fps = cap.get(cv2.CAP_PROP_FPS)
        total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
        duration = total_frames / fps
        frame_step = get_frame_step(duration)

        frame_idx = 0
        while True:
            ret, frame = cap.read()
            if not ret:
                break

            if frame_idx % frame_step == 0:
                process_frame(
                    frame,
                    anno_df,
                    frame_idx,
                    category_labels,
                    output_dir,
                    os.path.basename(anno_path)[:-5],
                )
            frame_idx += 1
        cap.release()

def get_frame_step(duration):
    if duration <= 5:
        return 2
    elif 5 < duration <= 10:
        return 5
    elif 10 < duration <= 20:
        return 10
    else:
        return 50

def process_frame(
    frame, anno_df, frame_idx, category_labels, output_dir, anno_base_name
):
    img_height, img_width = frame.shape[:2]
    frame_anno = anno_df[anno_df["frame_id"] == frame_idx]
    img_filename = os.path.join(
        output_dir, f"{anno_base_name}_{frame_idx}.jpg"
    )
    anno_filename = os.path.join(
        output_dir, f"{anno_base_name}_{frame_idx}.txt"
    )
    cv2.imwrite(img_filename, frame)
    if len(frame_anno) != 0:
        create_annotation_file(
            frame_anno,
            img_width,
            img_height,
            category_labels,
            anno_filename,
        )

def create_annotation_file(
    frame_anno, img_width, img_height, category_labels, anno_filename
):
    with open(anno_filename, "w") as file:
        for category, bbox in zip(
            frame_anno["category"].values, frame_anno["bbox"].values
        ):
            category_idx = category_labels.index(category)
            x_min, y_min, x_max, y_max = bbox
            x_center = (x_min + x_max) / 2 / img_width
            y_center = (y_min + y_max) / 2 / img_height
            width = (x_max - x_min) / img_width
            height = (y_max - y_min) / img_height
            file.write(f"{category_idx} {x_center} {y_center} {width} {height}\n")

if __name__ == "__main__":
    base_dir = setup_directories("yolo-dataset")
    create_dataset_config(base_dir)
    category_labels = ["非机动车违停", "机动车违停", "垃圾桶满溢", "违法经营"]

    all_annos = glob.glob("训练集(有标注第一批)/标注/*.json")
    all_videos = glob.glob("训练集(有标注第一批)/视频/*.mp4")
    all_annos.sort()
    all_videos.sort()

    # 随机划分训练集和验证集
    train_size = int(len(all_annos) * 0.8)
    train_indices = random.sample(range(len(all_annos)), train_size)
    train_annos = [all_annos[i] for i in train_indices]
    train_videos = [all_videos[i] for i in train_indices]
    val_annos = [all_annos[i] for i in range(len(all_annos)) if i not in train_indices]
    val_videos = [all_videos[i] for i in range(len(all_videos)) if i not in train_indices]

    # 处理训练集
    process_videos(
        train_annos,
        train_videos,
        category_labels,
        os.path.join(base_dir, "train"),
        is_train=True,
    )

    # 处理验证集
    process_videos(
        val_annos,
        val_videos,
        category_labels,
        os.path.join(base_dir, "val"),
        is_train=False,
    )

主要改动如下:

  1. process_frame() 函数中,图像文件和标注文件的保存路径不再分开,而是使用同一个基础名称(anno_base_name),只改变扩展名。
  2. create_annotation_file() 函数中,标注文件的保存路径由调用函数传入,不再固定在 “annotations” 目录下。
  3. 其他部分的逻辑保持不变。

这样修改后,图像文件和对应的标注文件就会保存在同一个文件夹内了。训练集和验证集的图像和标注文件分别保存在 “train” 和 “val” 目录下。

1.4上分

使用上面重新划分的数据集,YOLOv8n模型训练400epoch
代码修改:
在这里插入图片描述
结果如下:
在这里插入图片描述模型训练了195个epoch,总共计划训练400个epoch。但由于没有在最后100个epoch中看到改进,触发了早停机制(EarlyStopping),因此训练提前停止。
预测提交:
在这里插入图片描述

2.更换预训练权重

在这里插入图片描述在原始 notebook 中修改,下载预训练模型部分,以及代码中加载模型部分。

!wget http://mirror.coggle.club/yolo/yolov8n-v8.2.0.pt -O yolov8n.pt

!wget http://mirror.coggle.club/yolo/yolov8s-v8.2.0.pt -O yolov8s.pt
!wget http://mirror.coggle.club/yolo/yolov8m-v8.2.0.pt -O yolov8m.pt
!wget http://mirror.coggle.club/yolo/yolov8l-v8.2.0.pt -O yolov8l.pt
!wget http://mirror.coggle.club/yolo/yolov8x-v8.2.0.pt -O yolov8x.pt

并在训练代码中进行修改:
在这里插入图片描述
报错提醒:
OutOfMemoryError: CUDA out of memory. Tried to allocate 20.00 MiB. GPU 0 has a total capacity of 23.65 GiB of which 1.81 MiB is free. Including non-PyTorch memory, this process has 23.62 GiB memory in use. Of the allocated memory 23.07 GiB is allocated by PyTorch, and 74.20 MiB is reserved by PyTorch but unallocated. If reserved but unallocated memory is large try setting
GPU内存不足,无法容纳当前运行的模型或数据。
可以减小批量大小,调整PyTorch的内存分配策略,减小图像尺寸

在这里插入图片描述
结果提交:
在这里插入图片描述
模型训练了 196 个 epoch,总共计划训练 400 个 epoch。但由于没有在最后 100 个 epoch 中看到改进,触发了早停机制(EarlyStopping),因此训练提前停止。
预测提交:

二、YOLO学习

1.YOLO 模型介绍

1.1物体检测概述

物体检测的目标:

  • 在图像或视频帧中识别和定位感兴趣的物体
  • 不仅识别对象类别,还要确定它们在图像中的具体位置(边界框)
    在这里插入图片描述关键步骤:
  1. 输入:图像或视频帧
  2. 特征提取:使用深度学习模型(如CNN)提取图像特征
  3. 候选区域生成:(某些算法中)生成可能包含目标物体的候选区域
  4. 区域分类和边界框回归:判断候选区域是否包含特定类别物体,预测边界框
  5. 非极大值抑制(NMS):选择最佳边界框,去除重叠框

1.2物体检测算法分类

One-Stage模型

  • 代表:YOLO, SSD
  • 特点:单次网络评估直接预测所有物体的类别和位置
  • 优点:速度快,适合实时应用
  • 缺点:精度可能不如Two-Stage模型

Two-Stage模型

  • 代表:Faster R-CNN
  • 特点:先生成候选区域,再对区域进行分类和边界框调整
  • 优点:精度高
  • 缺点:速度较慢

在这里插入图片描述

在实际应用中,选择哪种模型取决于特定场景的需求。如果对速度有较高要求,如视频流处理或实时监控,One-Stage模型可能更合适。如果对精度有更高要求,如在需要高精度识别的科研或专业领域,Two-Stage模型可能更加适用 。

1.3YOLO模型介绍

YOLO(You Only Look Once):

  • 一种流行的实时目标检测算法
  • 首次提出:2015年,由Joseph Redmon等人

核心思想:

  • 将目标检测视为单一回归问题
  • 直接从图像像素映射到边界框坐标和类别概率

特点:

  1. 单个网络评估同时预测多个边界框和类别概率
  2. 使用CNN提取图像特征,预测边界框和类别概率
  3. 为每个边界框预测置信度,反映包含目标的概率和预测类别

在这里插入图片描述

1.4YOLO版本演进

YOLO(You Only Look Once)是一种革命性的目标检测算法,以其快速和高效的性能而闻名。自2015年YOLOv1的首次推出以来,YOLO系列已经经历了多次迭代,每一次迭代都在速度、准确性和计算效率方面做出了显著的贡献。

版本号年份主要贡献与特点
YOLOv12015实时端到端物体检测,将检测视为回归问题,单次网络评估预测位置和类别。
YOLOv22016引入批量归一化,高分辨率分类器,全卷积网络,能检测超过9000个类别。
YOLOv32018使用更深的Darknet-53网络,引入特征金字塔网络提高多尺度目标检测能力。
YOLOv42020结合CSPNet、PANet、SAM等技术,提高特征提取和检测效率。
YOLOv52020使用Pytorch框架,不同大小模型版本适应不同环境,易用性和性能显著改进。
YOLOv62021多种不同尺寸模型适应工业应用,继续在YOLO系列基础上改进。
YOLOv72022架构变化和一系列免费包提高准确率,保持实时性。
YOLOv82023新功能和改进,包括新的骨干网络、Anchor-Free检测头和新损失函数,提升性能和灵活性。
YOLOv92023引入可编程梯度信息(PGI)和基于梯度路径规划的通用高效层聚合网络(GELAN)架构。
YOLOv102024通过消除非最大抑制(NMS-Free)和优化各种模型组件,实现了最先进的性能。

在这里插入图片描述

YOLOv1至YOLOv3主要由Joseph Redmon及其合作者提出,而后续版本则由不同的研究者和团队负责开发。YOLOv4之后的版本,尤其是YOLOv5和YOLOv8,由Ultralytics公司开发和维护。YOLOv5和YOLOv8也是现在比较流行的版本。

2.YOLO数据集格式

2.1数据集内容

  1. 图像文件夹(images):存放所有训练、验证、测试用的图片。支持jpg、png等常见图片格式。
  2. 标注文件夹(labels):存放与图片对应的标注文件,采用YOLO格式,每个图片对应一个同名的txt文件。
  3. 数据集配置文件(data.yaml):描述数据集的元信息,如类别数、类别名称、训练集/验证集/测试集的文件路径等。
  4. 具体的标注格式:每个txt标注文件中,一行代表一个目标,格式为:
<class_id> <center_x> <center_y> <width> <height>

在这里插入图片描述 其中:

  • class_id:目标类别的索引,从0开始
  • center_x, center_y:目标中心点坐标,取值范围[0,1],分别表示在图片宽度和高度上的比例
  • width, height:目标的宽度和高度,取值范围[0,1],分别表示在图片宽度和高度上的比例

假设图像的高和宽分别为hw,边界框(bbox)的坐标为:

  • 左上角坐标:(x1, y1)
  • 右下角坐标:(x2, y2)

则可以计算边界框的中心坐标(x_c, y_c):

x_c = x1 + (x2 - x1) / 2 = (x1 + x2) / 2
y_c = y1 + (y2 - y1) / 2 = (y1 + y2) / 2

假设YOLO格式的5个数据分别为:label, x_, y_, w_, h_,则它们与边界框坐标有以下对应关系:

x_ = (x1 + x2) / (2 * w) 
y_ = (y1 + y2) / (2 * h)
w_ = (x2 - x1) / w
h_ = (y2 - y1) / h

反之,从YOLO格式的数据可以转换回边界框坐标:

x1 = w * x_ - 0.5 * w * w_
x2 = w * x_ + 0.5 * w * w_
y1 = h * y_ - 0.5 * h * h_
y2 = h * y_ + 0.5 * h * h_

以上公式总结了图像坐标系和YOLO格式数据之间的相互转换关系:

  • (x_c, y_c): 边界框中心点坐标
  • (x1, y1): 边界框左上角坐标
  • (x2, y2): 边界框右下角坐标
  • (x_, y_, w_, h_): YOLO格式的相对坐标和尺寸
  • (w, h): 图像的宽度和高度

2.2数据集目录

完整的目录结构示例:

dataset/
├── images/
│   ├── train/
│   │   ├── 000001.jpg
│   │   └── 000002.jpg
│   ├── val/
│   └── test/
├── labels/
│   ├── train/
│   │   ├── 000001.txt
│   │   └── 000002.txt
│   ├── val/
│   └── test/  
└── data.yaml

2.3数据集配置文件

其中data.yaml内容示例:

path: ../dataset/  # dataset root dir
train: images/train/ 
val: images/val/
test: images/test/

nc: 2 
names: ['person', 'car']

在YOLO的训练过程中,这样的配置文件允许用户轻松地指定数据集的位置和类别信息,从而无需硬编码在训练脚本中。具体来说,这段配置的含义如下:
- path: 指定了数据集的根目录路径,即所有数据子文件夹的上级目录。这里的路径是相对于当前配置文件的路径或者相对于执行训练脚本的工作目录。
- train: 定义了训练集图像的相对路径。在训练模型时,程序会在指定的路径下查找图像文件。
- val: 定义了验证集图像的相对路径。验证集用于在训练过程中评估模型性能,避免过拟合。
- nc: 表示类别的数量,这里设置为2,意味着数据集中有两类物体需要被识别。
- names: 是一个列表,包含了每个类别的名称。这里有两个类别,名称分别是"0"和"1"。这些名称在训练和测试过程中用于引用特定的类别。

2.4总结

总结一下要点:

  1. 图片和标注文件要一一对应,放在images和labels两个文件夹下面
  2. 标注采用YOLO格式的txt文件,每行代表一个目标
  3. 目标位置和大小都采用相对值[0,1],分别表示在图片尺寸上的比例
  4. 要提供data.yaml配置文件,描述类别数量、名称和各个数据集的路径

3.YOLO训练日志

在这里插入图片描述

3.1训练过程文件夹 (如exp/detect/train):

  • 模型权重文件(.pt或.pth): 训练过程中定期保存的模型权重,可用于后续测试或继续训练。
  • 日志文件(.log): 记录整个训练过程的输出信息,如损失值、精度、速度等关键指标。
  • 配置文件(.yaml或.cfg): 训练所使用的配置设置副本,包含数据路径、类别名称、模型结构等。
  • 性能图表: 一些可视化训练过程的图表,如损失曲线、精度曲线等。
  • 测试结果: 如果训练包含测试阶段,这里可能保存一些测试的可视化检测结果图或性能指标。

3.2关键性能指标图:

PR_curve.png

  • F1_curve.png: F1分数曲线图,综合考虑精确率和召回率的平衡。
  • PR_curve.png: 精确率-召回率曲线图,展示不同召回率水平下的精确率变化。
  • P_curve.png: 精确率曲线图,即准确预测为正类别的样本占所有预测为正类别样本的比例。
  • R_curve.png: 召回率曲线图,即准确预测为正类别的样本占所有真实正类别样本的比例。

3.3关键文件:

  • results.csv: 训练或测试过程的结果数据表格。
  • results.png: 训练结果汇总的图表或图像。
  • train_batch0.jpg: 训练过程中各批次样本的图像及标注可视化。
  • val_batch0_labels.jpg,val_batch0_pred.jpg: 验证集各批次的真实标签和预测结果可视化。
  • weights/: 保存训练过程中的模型权重文件。

3.4日志指标缩写含义:

在这里插入图片描述

缩写作用描述
epoch表示模型在整个训练数据集上进行了一次前向和后向传播的完整周期。
train/box_loss衡量模型预测的边界框与真实边界框之间差异的损失值。
train/cls_loss衡量模型预测的类别与真实类别之间差异的损失值。
train/dfl_loss衡量模型对难分类样本的关注程度,减少易分类样本的影响。
metrics/precision(B)在训练过程中,预测为正类别中实际为正类别的比例。
metrics/recall(B)在训练过程中,所有实际正类别中被模型正确预测为正类别的比例。
metrics/mAP50(B)在50%的IoU阈值下计算,衡量模型的整体性能。
metrics/mAP50-95(B)在0.5到0.95的IoU阈值范围内计算,提供更全面的模型性能评估。
val/box_loss模型在未见过的验证集上的边界框损失,用于监控模型的泛化能力。
val/cls_loss模型在验证集上的分类损失,用于监控模型的泛化能力。
val/dfl_loss模型在验证集上的难易样本平衡损失。

通过分析验证集损失值与性能指标的变化趋势,可以评估模型是否过拟合。若验证集性能提升后又下降,说明过拟合发生。日志中的图表和指标有助于洞察模型训练状态,选择最佳模型,并调优训练过程。

三、其他上分思路

1.数据集增强

from ultralytics import YOLO

# 加载模型
model = YOLO('yolov8n.pt')  # 加载预训练模型

# 定义数据增强策略
hyp = {
    'hsv_h': 0.015,  # HSV-Hue增强
    'hsv_s': 0.7,    # HSV-Saturation增强
    'hsv_v': 0.4,    # HSV-Value增强
    'degrees': 0.0,  # 旋转角度
    'translate': 0.1,# 平移
    'scale': 0.5,    # 缩放
    'shear': 0.0,    # 剪切
    'flipud': 0.0,   # 上下翻转概率
    'fliplr': 0.5,   # 左右翻转概率
    'mosaic': 0.5,   # # 图像合成概率
    'copy_paste': 0.5  # 复制粘贴增强概率
    'mixup': 0.0,    # mixup增强概率
}

# 训练模型
results = model.train(
    data='path/to/data.yaml',
    epochs=100,
    imgsz=640,
    batch=16,
    name='yolov8n_custom',
    hyp=hyp
)

2.模型选择与微调

考虑使用更大的YOLOv8模型,可以先从YOLOv8m开始训练,在验证集上评估精度和速度,再根据需要调整模型的大小。比如,如果精度不够,可以尝试YOLOv8l;如果速度不满足要求,可以尝试YOLOv8s。
尝试不同的预训练权重。
调整学习率、批次大小等超参数等。

  • 17
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值