YOLOv5/v7/v8改进实验(三)之训练技巧篇

news2024/12/23 10:15:31

在这里插入图片描述


🚀🚀 前言 🚀🚀

YOLO系列是一种目标检测算法,具有高效的实时性能和较高的准确性。一些常用的YOLO训练技巧往往可以帮助提高模型的性能和收敛速度。而这些技巧在YOLOv5YOLOv7YOLOv8几乎通用。


🔥🔥 YOLO系列实验实战篇:

📖 YOLOv5/v7/v8改进实验(一)之数据准备篇
📖 YOLOv5/v7/v8改进实验(二)之数据增强篇
📖 YOLOv5/v7/v8改进实验(三)之训练技巧篇

更新中…


目录

  • 一、入门级操作(必学!!!)
    • 1.1 数据预处理
    • 1.2 模型选择 🔥
    • 1.3 模型基线
    • 1.4 超参数设置
      • img-size
      • batch-size
      • epochs
      • cache 🔥🔥🔥
      • workers
      • seeds 🔥🔥
    • 1.5 权重文件保存 🔥
  • 二、进阶级操作
    • 2.1 模型测试
    • 2.2 GFLOPs显示 🔥

一、入门级操作(必学!!!)

1.1 数据预处理

在训练之前,对数据进行预处理是很重要的。常见的预处理步骤包括随机裁剪、翻转、旋转等操作和归一化。详细代码请移步–YOLOv5改进实战 | YOLOv5-7.0改进实验(二)之数据增强篇

1.2 模型选择 🔥

模型越大,训练出来的结果更理想,但对硬件的要求更高,需要更多的显存去训练,且训练时间更长。

  • 对于实验来说,建议使用YOLOv5s
  • 对于移动部署,建议使用YOLOv5s/m;
  • 对于云部署,建议使用YOLOv5l/x。

是否使用预训练模型

  • 如果是大数据集,则建议从头开始训练(不使用预训练模型);
  • 如果是小数据集,则建议使用预训练模型做迁移学习
    Transferred 342/349 items from yolov5s.pt
    

当然,在训练时加载预训练模型可以加速模型的收敛和提高模型的精度,因为预训练模型已经学习到了一些通用的特征,可以帮助模型更快地学习到目标检测任务所需的特征。不过,您的模型改进是有效的,那么即使不加载预训练模型,模型也应该具有更好的性能。所以,个人还是建议不使用预训练模型,从头开始训练。只是个人建议,还是取决于具体情况和实验需求,可以根据实验结果进行选择

1.3 模型基线

训练使用默认设置,不做任何改动,得到模型性能基线。实验最开始需要完成的工作,必不可少的一个操作,因为有它你才能对比。

1.4 超参数设置

img-size

推荐使用默认的 640 ∗ 640 640*640 640640,无需做修改。如果数据集中有大量的小目标,可以适当增加数值,比如800、1000、1280等,有利于训练结果。但也会增加训练时间和显存需求模型推理img-size值需与训练img-size值一致

parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640, help='train, val image size (pixels)')

batch-size

批量大小Batchsize训练过程中需要调整的超参数之一。合适的批量大小可以充分利用GPU资源。建议使用硬件允许的最大值,需避免Batchsize值过小产生糟糕的统计结果。

parser.add_argument('--batch-size', type=int, default=32, help='total batch size for all GPUs, -1 for autobatch')

PS:做实验的话不建议将Batchsize拉满,原因如下:

  • 做对比实验需要保持Batchsize一致,但不同模型在Batchsize相同情况下往往存在所需显存不同,举个例子,YOLOv5训练时我将batchsize设置为128,这时显存刚好拉满,但是换成YOLOv7训练,如果你的batchsize设置为128,那显存必爆无疑。众所周知,YOLOv7训练所需要的显存要高得多
  • 如果你对网络进行修改,增加了很多模块,这常常会使得计算量FLOPs增加,那么就需要更多的显存来进行训练。

总结:实验需要保持Batchsize一致,不过这个值需要各位根据具体情况确定。


epochs

迭代次数是训练过程中需要调整的超参数之一。迭代次数要足够多以达到模型收敛。

parser.add_argument('--epochs', type=int, default=300, help='total training epochs')

默认300个,出现过拟合则减小该值,反之亦然。

PS:如果时从头开始训练,则可以在训练模型基线时将该值调大,然后观察训练loss大致在多少轮数收敛,那么再结合自身情况综合考虑确定轮数。


cache 🔥🔥🔥

YOLOv5的训练参数里面有一个--cache,默认不开启,开启后默认是ram,就是把解码后的图片保存在内存中。也可以是disk,就会把解码后的图片保存在硬盘上,可以加快训练

parser.add_argument('--cache', type=str, nargs='?', const='ram', help='image --cache ram/disk')

如果训练图片总量不大,或者服务器内存超高,那么完全可以把解码后的图片放内存里,直接加上--cache参数搞定:

python train.py --cache

workers

在YOLOv5中,workers参数用于指定用于数据加载的工作进程数量。这些工作进程负责将数据从存储设备(如硬盘)加载到内存中,并进行预处理操作,例如图像缩放、数据增强等。默认值为8,一般不做修改,Windows下建议设置为0

parser.add_argument('--workers', type=int, default=8, help='max dataloader workers (per RANK in DDP mode)')

增加workers参数可以并行化数据加载和预处理过程,从而加快数据的处理速度,提高训练速度。每个工作进程都可以独立地加载和处理数据,减少了数据加载和预处理的等待时间。因此,在选择workers参数时,需要根据系统的硬件配置和资源限制进行权衡。


seeds 🔥🔥

随机种子(seeds)设置用于控制随机性,从而使训练过程更加可重复和可控。模型训练过程通常包含随机性,例如数据增强、权重初始化和优化器等。这些随机因素会影响模型的训练结果,使得每次训练的结果可能不同。如果需要比较不同模型或参数设置的性能,或者需要在多次训练中保持结果的一致性,就需要使用随机种子来控制随机性。
PS:随机种子的设置,能确保每次运行时的随机数生成是可重复的。不过设置种子只能保证模型在相同的种子值下生成相同的随机数序列,但不能保证模型的训练结果完全相同。(少量数据集下训练结果是完全相同的)

  • YOLOv5可以通过设置--seed参数来指定随机种子。例如,--seed 2表示使用随机种子2进行训练。建议在实验中使用随机种子来控制随机性,并根据实验结果进行调整。
    python train.py --seed 2
    
  • YOLOv7设置随机种子,可移步YOLOv7改进实战(1) | YOLOv7训练随机种子设置
  • YOLOv8则通过设置seed参数即可。
from ultralytics import YOLO

# Load a model
model = YOLO(r"ultralytics\cfg\models\v8\yolov8s.yaml")  # build a new model from scratch

# Use the model
model.train(seed=2)  # train the model

1.5 权重文件保存 🔥

YOLOv5官方保存pt权重文件代码在train.py

# Save last, best and delete
torch.save(ckpt, last)
if best_fitness == fi:
    torch.save(ckpt, best)
if opt.save_period > 0 and epoch % opt.save_period == 0:
    torch.save(ckpt, w / f'epoch{epoch}.pt')

训练完成后在相应的weights文件夹下只会有一个best.ptlast.pt文件。可发现关键在于fi这个变量,它是PRmAP@0.5mAP@0.5:0.95的加权和,具体计算公式如下:

def fitness(x):
    # Model fitness as a weighted combination of metrics
    w = [0.0, 0.0, 0.1, 0.9]  # weights for [P, R, mAP@0.5, mAP@0.5:0.95]
    return (x[:, :4] * w).sum(1)

每次best.pt的保存都会覆盖上一次的best.pt权重文件,当然我们训练的时候并不知晓best.pt在测试集的效果,那么如果将这些fi值相等的权重全部保存下来,我们甚至有机会能在众多权重中进行挑选表现最优以及最合适自己的权重,,岂不美哉!不然我们把宝全部压在那一个best.pt上,风险太大,弄不好就是从头再来。

所以我们可以对上述代码进行修改,其实很简单,只是需要注意一个小细节添加上strip_optimizer函数,不然你的磁盘可能会很快爆满:

# Save last, best and delete
torch.save(ckpt, last)
if best_fitness == fi:
    torch.save(ckpt, best)
# 保存pt文件
if (best_fitness == fi and epoch >= 200):
    torch.save(ckpt, w / f'best{epoch}.pt')
    strip_optimizer(w / f'best{epoch}.pt')
if opt.save_period > 0 and epoch % opt.save_period == 0:
    torch.save(ckpt, w / f'epoch{epoch}.pt')

YOLOv7作者已经设置好无需修改

YOLOv8需要在ultralytics/engine/trainer.py(在这里不得不说一句,v8的代码是真难找啊!!!!)进行相应的修改:

# Save last, best and delete
torch.save(ckpt, self.last, pickle_module=pickle)
if self.best_fitness == self.fitness:
    torch.save(ckpt, self.best, pickle_module=pickle)
# 保存权重文件
if self.best_fitness == self.fitness and self.epoch >= 200:
    torch.save(ckpt, self.wdir / f'best{self.epoch}.pt', pickle_module=pickle)
    strip_optimizer(self.wdir / f'best{self.epoch}.pt')

二、进阶级操作

2.1 模型测试

如果你按照1.5节的操作进行操作,那么你训练完后,weights文件夹中必将有不少的best_xxx.pt权重文件,训练完接着就是需要在测试集上进行模型性能测试,当然你可以一个一个指定执行,但是很耗时,这时候可以选择使用sh脚本进行自动化执行,新建一个test.sh脚本文件,脚本如下:

#!/bin/bash

# 指定目标文件夹的路径
target_folder=$1
task=$2
data="/root/dataset/data.yaml" # 需要修改为自己数据集的yaml配置文件
log_dir="log"

parent_folder=$(dirname "$target_folder" | awk -F'/' '{print $NF}')
echo "Found folder: $parent_folder"

mkdir -p "$log_dir/$parent_folder"
log_file="$log_dir/$parent_folder/$task.log"

rm -f "$log_file"
file_list=$(find "$target_folder" -type f -name "*.pt")

exec > "$log_file" 2>&1
for file in $file_list; do
    file_name=$(basename "$file" .pt)
    echo "========================================"
    echo "Found file: $file_name"
    echo "========================================"
    python test.py --weights "$file" --data "$data" --task $task
done
sh test.sh runs/train/exp/weights test

执行完会在根目录下生成log文件夹,里面对应的log日志文件。

2.2 GFLOPs显示 🔥

不少小伙伴给YOLO做改进时,运行models/yolo.py会遇到这样的情况:

YOLOv5s-ghostv2-backbone summary: 406 layers, 5156430 parameters, 5156430 gradients

GFLOPs指标无法显示,YOLOv5/v7可以在utils/torch_utils.pymodel_info函数进行修改,YOLOv8可以在ultralytics/utils/torch_utils.py中的get_flops函数中修改

try:  # FLOPs
    p = next(model.parameters())
    stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32  # max stride
    im = torch.empty((1, p.shape[1], stride, stride), device=p.device)  # input image in BCHW format
    flops = thop.profile(deepcopy(model), inputs=(im, ), verbose=False)[0] / 1E9 * 2  # stride GFLOPs
    imgsz = imgsz if isinstance(imgsz, list) else [imgsz, imgsz]  # expand if int/float
    fs = f', {flops * imgsz[0] / stride * imgsz[1] / stride:.1f} GFLOPs'  # 640x640 GFLOPs
except Exception as e:
	# print(e)
    im = torch.rand(1, 3, 640, 640).to(p.device)
    flops, parms = thop.profile(model, inputs=(im,), verbose=False)
    # print(f'Params: {parms}, GFLOPs: {flops * 2 / 1e9}')
    # fs=''
    fs = f', {flops * 2 / 1E9:.1f} GFLOPs'

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CUDA编程入门系列(十一)CUDA程序优化技巧

优化原则:最大化并行执行 探索并行化: 优化线程块的规模 我们在设计CUDA程序的时候,要对线程块的个数进行考虑。因为GPU中流处理器SM的数量是相对固定的,所以我们应该尽量的将多个block放到同一个SM当中(至少保证每个…

三、信号与槽

1. 信号槽的定义 信号函数和槽函数是Qt在C的基础上新增的功能,功能是实现对象之间的通信。 实现信号槽需要有两个先决条件: 通信的对象必须是从QObject派生出来的 QObject是Qt所有类的基类。 类中要有Q_OBJECT宏 2. 信号槽的使用 2.1 函数原型 最常…

免费SSL证书:JoySSL让您的网站更安全

在今天的数字化时代,保护网站和用户信息的安全至关重要。SSL(Secure Sockets Layer)证书通过加密网站与用户之间的通信,确保数据传输的安全性。让您拥有一个SSL加密的网站是至关重要的,但您可能会担心高昂的费用。不过…

秦丝科技“羽”深大计软学院同行,共庆深圳大学成立40周年

2023年10月21日, 由深圳大学工会主办 , 深圳大学体育学院 、深圳大学后勤部、丽湖校区管委会等单位协办的深圳大学2023年教职工羽毛球联赛-第一场正式举办; 由深圳市秦丝科技有限公司联合头部商户共同赞助的计算机与软件学院取得首场胜利&…

花生好车基于 KubeSphere 的微服务架构实践

公司简介 花生好车成立于 2015 年 6 月,致力于打造下沉市场汽车出行解决方案第一品牌。通过自建直营渠道,瞄准下沉市场,现形成以直租、批售、回租、新能源汽车零售,四大业务为核心驱动力的汽车新零售平台,目前拥有门店…

java基础--transient关键字减少序列化

前置内容 1.序列化 今天在看ArrayList源码的时候看到了这个,我之前应该是看过的,但是忘记了。现在在总结一下。 transient 用在类的属性上,不能修饰其他的。 作用:在序列化的时候transient修饰的属性不能被序列化 用途 在一些…

力扣:盛最多水的容器

题目 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明:你不能倾斜容器。 …

【公众号开发】图像文字识别 · 模板消息推送 · 素材管理 · 带参数二维码的生成与事件的处理

【公众号开发】(4) 文章目录 【公众号开发】(4)1. 图像文字识别功能1.1 百度AI图像文字识别接口申请1.2 查看文档学习如何调用百度AI1.3 程序开发1.3.1 导入依赖:1.3.2 公众号发来post请求格式1.3.3 对image类型的消息…

【JavaEE】synchronized原理 -- 多线程篇(6)

synchronized原理 1. synchronized具体采用了哪些加锁策略?2. synchronized内部实现策略(内部原理)2.1 偏向锁2.2 轻量级锁与重量级锁 3. synchronized 的其它优化策略3.1 锁消除3.2 锁的粒度 4. 总结 1. synchronized具体采用了哪些加锁策略? synchronized既是悲观锁, 也是…

Power BI 傻瓜入门 4. Power BI:亮点

本章内容包含: 在Power BI Desktop上学习诀窍摄入数据使用模型试用Power BI服务 就像评估一个由多种成分组成的蛋糕一样,Power BI要求其用户熟悉商业智能(BI)解决方案中的功能。几乎所有与Power BI交互的用户都是从桌面版开始的…

Locust负载测试工具实操

本中介绍如何使用Locust为开发的服务/网站执行负载测试。 Locust 是一个开源负载测试工具,可以通过 Python 代码构造来定义用户行为,避免混乱的 UI 和臃肿的 XML 配置。 步骤 设置Locust。 在简单的 HTTP 服务上模拟基本负载测试。 准备条件 Python…

2021年03月 Python(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python编程(1~6级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 下列代码的输出结果是?( ) x 0x10print(x)A:2 B:8 C&#xff…

NeurIPS 23 Spotlight丨3D-LLM:将3D世界注入大语言模型

来源:投稿 作者:橡皮 编辑:学姐 论文链接:https://arxiv.org/pdf/2307.12981.pdf 开源代码:https://vis-www.cs.umass.edu/3dllm/ 摘要: 大型语言模型 (LLM) 和视觉语言模型 (VLM) 已被证明在多项任务上…

FPGA的256点FFT调用Quartus IP核实现VHDL傅里叶变换

名称:256点FFT调用Quartus IP核实现傅里叶变换 软件:Quartus 语言:VHDL 代码功能:使用VHDL实现256点FFT,调用Quartus IP核实现傅里叶变换 演示视频:http://www.hdlcode.com/index.php?mhome&cView…

Mysql基础与高级汇总

SQL语言分类 DDL:定义 DML:操作 DCL:控制(用于定义访问权限和安全级别) DQL:查询 Sql方言 ->sql:结构化查询语言 mysql:limit oracle:rownum sqlserver:top 但是存储过程:每一种数据库软件一样SQL语法要求: SQL语句可以单行或多行书写&…

msvcp110.dll无法继续执行代码怎么办?msvcp110.dll丢失的解决方法

msvcp110.dll 丢失通常意味着你的计算机上缺少一个名为 msvcp110.dll 的动态链接库文件。这个文件是 Microsoft Visual C 2010 Redistributable Package 的一个组件,它包含了一些运行时库文件。当你的计算机缺少这个文件时,可能会出现一些问题&#xff0…

有哪些靠谱的获客渠道? 大家都在说精准大数据获客,你了解过没?

如何获取准确、实际的客户信息是众多企业在获客阶段最头疼的问题,想要精准获客就需要了解客户的真实需求,若企业无法满足又无法预估到客户意向,那么将会浪费双方的时间,费力不讨好,企业获客难题是这么多年最难以解决的…

接口自动化测试难点:数据库验证解决方案

接口自动化中的数据库验证:确保数据的一致性和准确性 接口自动化测试是现代软件开发中不可或缺的一环,而数据库验证则是确保接口返回数据与数据库中的数据一致性的重要步骤。本文将介绍接口自动化中的数据库验证的原理、步骤以及示例代码,帮…

关于Mysql中的索引与事务

索引 定义 索引:为了提高查找效率而使用的一种数据结构把数据组织起来,可以把索引理解在书的目录或字典的检索表(拼音检索) 索引是一种特殊的文件,可以包含着对数据表里的所有记录的引用指针,对表中的一…