【YOLOv9】使用yolov9训练自己的数据集/验证 /推理 /参数分析

完胜V8的SOTA模型Yolov9(论文阅读笔记)内容 点击即可跳转

当今的YOLO系列武林盟主YOLOV9:

YOLOv9的优秀表现:

环境:

ubuntu20.04,无GPU,使用anaconda3创建的虚拟环境yolov9。

  • 环境安装:
conda create -n yolov9 python=3.8

# 激活yolov9 env

conda activate yolov9
  • YOLOv9源码下载:
cd 到想要放置yolov9源码的路径

git clone https://github.com/WongKinYiu/yolov9.git

cd yolov9

pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

1 数据准备

可以使用开源的数据集,也可以自己准备数据集。

①标注工具

⒈labelme

安装方法:pip install labelme

使用方法:终端输入labelme

标注后生成的标记文件是json文件。

⒉labelimg

安装方法: pip install labelimg

使用方法:

cd到labelImg所在路径;

python3 labelImg.py

标注后生成的标记文件是xml文件。

②数据集整理

原始数据集格式如下图所示:

Annotations里面存放标签xml文件。

JPEGImage 里面存放原始图片。

labels文件夹里面存放的是标签txt文件。这个文件夹里的文件是通过脚本XmlToTxt.py生成的。

XmlToTxt.py的代码如下:

import xml.etree.ElementTree as ET
import os
import os
import random
# TODO 这里按照类别去修改
classes = ['fire']
# TODO 这里按照实际XML文件夹路径去修改
xml_filepath = 'dataset_fire/Annotations/'
# TODO 这里按照实际想要保存结果txt文件夹的路径去修改
labels_savepath = 'dataset_fire/labels/'
abs_path = os.getcwd()
 
def convert(size, box):
    dw = 1. / (size[0])
    dh = 1. / (size[1])
    x = (box[0] + box[1]) / 2.0 - 1
    y = (box[2] + box[3]) / 2.0 - 1
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x * dw
    w = w * dw
    y = y * dh
    h = h * dh
    return x, y, w, h
 
def convert_annotation(image_id):
    in_file = open(xml_filepath + '%s.xml' % (image_id), encoding='UTF-8')
    out_file = open(labels_savepath + '%s.txt' % (image_id), 'w')
    tree = ET.parse(in_file)
    root = tree.getroot()
    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)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
 
def run():
    total_xml = os.listdir(xml_filepath)
    num = len(total_xml)
    names = []
    for xml  in total_xml:
        names.append(xml[:-4])
    for name in names:
        convert_annotation(name)
    pass
 
if __name__ == '__main__':
    run()
    pass

然后,根据JPEGImage 文件夹labels文件夹通过脚本deal_dataset.py将数据集划分为如下结构。

deal_dataset.py的代码如下:

import os
import random
import shutil
 
# 原数据集目录
root_dir = 'dataset_fire/'
# 划分比例
train_ratio = 0.8
valid_ratio = 0.1
test_ratio = 0.1
 
# 设置随机种子
random.seed(42)
 
# TODo 这里按照实际数据集路径去修改
split_dir = 'dataset_fire_split/'
os.makedirs(os.path.join(split_dir, 'train/images'), exist_ok=True)
os.makedirs(os.path.join(split_dir, 'train/labels'), exist_ok=True)
os.makedirs(os.path.join(split_dir, 'val/images'), exist_ok=True)
os.makedirs(os.path.join(split_dir, 'val/labels'), exist_ok=True)
os.makedirs(os.path.join(split_dir, 'test/images'), exist_ok=True)
os.makedirs(os.path.join(split_dir, 'test/labels'), exist_ok=True)
 
# TODo 这里按照实际数据集路径去修改
imgpath = "JPEGImages"
labelpath = "labels"
image_files = os.listdir(os.path.join(root_dir, imgpath))
label_files = os.listdir(os.path.join(root_dir, labelpath))
 
# 随机打乱文件列表
combined_files = list(zip(image_files, label_files))
random.shuffle(combined_files)
image_files_shuffled, label_files_shuffled = zip(*combined_files)
 
# 根据比例计算划分的边界索引
train_bound = int(train_ratio * len(image_files_shuffled))
valid_bound = int((train_ratio + valid_ratio) * len(image_files_shuffled))
 
# 将图片和标签文件移动到相应的目录
for i, (image_file, label_file) in enumerate(zip(image_files_shuffled, label_files_shuffled)):
    if i < train_bound:
        shutil.move(os.path.join(root_dir, imgpath, image_file), os.path.join(split_dir, 'train/images', image_file))
        shutil.move(os.path.join(root_dir, labelpath, label_file), os.path.join(split_dir, 'train/labels', label_file))
    elif i < valid_bound:
        shutil.move(os.path.join(root_dir, imgpath, image_file), os.path.join(split_dir, 'valid/images', image_file))
        shutil.move(os.path.join(root_dir, labelpath, label_file), os.path.join(split_dir, 'valid/labels', label_file))
    else:
        shutil.move(os.path.join(root_dir, imgpath, image_file), os.path.join(split_dir, 'test/images', image_file))
        shutil.move(os.path.join(root_dir, labelpath, label_file), os.path.join(split_dir, 'test/labels', label_file))

至此,数据集准备好啦!

2 配置文件

在yolov9/data目录下新建数据的配置文件fire.yaml,内容如下:

path: data/images/dataset_fire_split  # dataset root dir
train: train/  # train images 
val: val/  # val images
test: test/ # test images
 
# Classes
names:
  0: fire

找到yolov9/models/detect/yolov9-c.yaml文件后,修改里面的内容,如下图:

3 训练

下载预训练的模型后放到yolov9项目路径下,如下图:

  1. train:主分支。
  2. train_dual:一个辅助分支 + 一个主分支。
  3. triple_branch: 1个主分支 + 2个辅助分支。

训练相关的参数解析如下:

# train
parser.add_argument('--weights', type=str, default='',
                    help='权重初始化的路径')
parser.add_argument('--cfg', type=str, default='models/detect/gelan.yaml',
                    help='模型的配置文件,可以根据自己需求配置yaml文件')
parser.add_argument('--data', type=str, default='',
                    help='数据集yaml文件地址')
parser.add_argument('--hyp', type=str, default='data/hyps/hyp.scratch-high.yaml',
                    help='超参数文件,yaml文件用于配置各种超参数')
parser.add_argument('--epochs', type=int, default=150,
                    help='训练的轮次')
parser.add_argument('--batch-size', type=int, default=4,
                    help='训练的批次大小,决定了一次向模型里输入多少张图片')
parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640,
                    help='输入模型里的图像尺寸,YOLO系列默认都是640')
parser.add_argument('--rect', action='store_true',
                    help='矩形训练或验证,是一种数据处理技术,在训练或验证过程中,输入数据会被调整为具有相同宽高比的矩形形状')
parser.add_argument('--resume', nargs='?', const=True, default=False,
                    help='如果设置为True,那么会根据最新一次没有训练完成的权重进行继续训练')
parser.add_argument('--nosave', action='store_true',
                    help='只保存之后一次训练的权重文件地址,即得到的那个权重,默认')
parser.add_argument('--noval', action='store_true',
                    help='设置时,只在最后一个周期(epoch)进行验证,而不是在每个周期都进行验证')
parser.add_argument('--noautoanchor', action='store_true',
                    help='设置时,禁用自动锚定(AutoAnchor)')
parser.add_argument('--noplots', action='store_true',
                    help='设置时,不保存任何绘图文件,就是runs下面的训练结果产物')
parser.add_argument('--evolve', type=int, nargs='?', const=300,
                    help='允许超参数的进化优化,参数是进化的代数。')
parser.add_argument('--bucket', type=str, default='',
                    help='指定一个gsutil存储桶的路径')
parser.add_argument('--cache', type=str, nargs='?', const='ram',
                    help='设置图像缓存方式,可以是内存(ram)或磁盘(disk),默认是内存')
parser.add_argument('--image-weights', action='store_true',
                    help='使用加权图像选择进行训练,简单的说就是,处理一些复杂或不平衡的数据集')
parser.add_argument('--device', default='',
                    help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
parser.add_argument('--multi-scale', action='store_true',
                    help='设置时,图像大小会在训练过程中变化,上下浮动50%')
parser.add_argument('--single-cls', action='store_true',
                    help='设置时,将多类别数据作为单类别数据训练,一般都设置为False')
parser.add_argument('--optimizer', type=str, choices=['SGD', 'Adam', 'AdamW', 'LION'], default='SGD',
                    help='优化器的选择,默认为SGD优化器')
parser.add_argument('--sync-bn', action='store_true',
                    help='设置时,使用同步批处理归一化(SyncBatchNorm)')
parser.add_argument('--workers', type=int, default=0,
                    help='Linux系统可以设置工作的线程,Windows系统必须设置0否则会导致各种问题')
parser.add_argument('--project', default='runs/train',
                    help='设置项目保存路径,就是训练结果产物保存路径')
parser.add_argument('--name', default='exp',
                    help='保存的项目名称,类似于runs/train/exp/训练的产物')
parser.add_argument('--exist-ok', action='store_true',
                    help='设置时,如果项目/名称已存在则不会报错,不会自动增加编号')
parser.add_argument('--quad', action='store_true',
                    help='使用四边形数据加载器, 默认开启')
parser.add_argument('--cos-lr', action='store_true',
                    help='使用余弦学习率调度器, 默认开启')
parser.add_argument('--flat-cos-lr', action='store_true',
                    help='启用一个平坦余弦学习率调度器(Flat Cosine Learning Rate Scheduler')
parser.add_argument('--fixed-lr', action='store_true',
                    help='启用一个固定学习率调度器(Fixed Learning Rate Scheduler)')
parser.add_argument('--label-smoothing', type=float, default=0.0,
                    help='参数是用来设置标签平滑的 epsilon 值的,用来提高模型的泛化能力')
parser.add_argument('--patience', type=int, default=100,
                    help='早停机制,损失超过多少个回合变化的较小就停止训练')
parser.add_argument('--freeze', nargs='+', type=int, default=[0],
                    help='用于在神经网络训练过程中“冻结”一部分层,不对它们进行更新')
parser.add_argument('--save-period', type=int, default=-1,
                    help='每隔x个周期保存一次检查点,如果小于1则禁用')
parser.add_argument('--seed', type=int, default=0,
                    help='随机数种子,根据随机数种子来演变出来的随机数')
parser.add_argument('--local_rank', type=int, default=-1,
                    help='自动设置用于多GPU DDP训练的局部排名,通常不需要手动修改')
parser.add_argument('--min-items', type=int, default=0,
                    help='Experimental,实验功能')
parser.add_argument('--close-mosaic', type=int, default=0,
                    help='关闭mosaic数据增强的参数,比如设置0则不关闭mosaic数据增强'
                         '如果设置100则在训练后100轮关闭mosaic增强')
# Logger arguments
parser.add_argument('--entity', default=None,
                    help='设置实体,用于日志记录')
parser.add_argument('--upload_dataset', nargs='?', const=True, default=False,
                    help='设置是否上传数据集,如果指定“val”,则上传验证集')
parser.add_argument('--bbox_interval', type=int, default=-1,
                    help='设置边界框图像记录间隔')
parser.add_argument('--artifact_alias', type=str, default='latest',
                    help='设置要使用的数据集工件的版本,默认为latest')

训练示例

cd yolov9项目路径

python3 train_dual.py --weights=yolov9-c.pt --cfg=models/detect/yolov9-c.yaml --data=data/fire.yaml --epoch=50 --batch-size=4 --imgsz=640 --hyp=data/hyps/hyp.scratch-high.yaml

训练过程的产物如下所示:

模型保存在这个路径runs/train/exp/weights下,文件如图:

4 验证

验证相关的参数解析如下:

# val
parser.add_argument('--data', type=str, default='数据集的yaml文件地址',
                    help='数据集配置文件路径')
parser.add_argument('--weights', nargs='+', type=str, default='runs/train/exp12/weights/best.pt',
                    help='trained模型权重文件路径')
parser.add_argument('--batch-size', type=int, default=4,
                    help='批处理大小')
parser.add_argument('--imgsz', '--img', '--img-size', type=int, default=640,
                    help='推理时的图像大小')
parser.add_argument('--conf-thres', type=float, default=0.001,
                    help='置信度阈值')
parser.add_argument('--iou-thres', type=float, default=0.7,
                    help='非最大抑制(NMS)的交并比(IoU)阈值')
parser.add_argument('--max-det', type=int, default=300,
                    help='每张图像的最大检测数量')
parser.add_argument('--task', default='val',
                    help='任务类型,可以是train, val, test, speed或study')
parser.add_argument('--device', default='',
                    help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
parser.add_argument('--workers', type=int, default=0,
                    help='最大工作线程数,Windows系统建议0。Linux系统根据需求设置即可')
parser.add_argument('--single-cls', action='store_true',
                    help='将数据集视为单类别。')
parser.add_argument('--augment', action='store_true',
                    help='使用增强的推理。')
parser.add_argument('--verbose', action='store_true',
                    help='按类别详细报告mAP数值')
parser.add_argument('--save-txt', action='store_true',
                    help='将结果保存为文本文件')
parser.add_argument('--save-hybrid', action='store_true',
                    help='将标签和预测的混合结果保存为文本文件')
parser.add_argument('--save-conf', action='store_true',
                    help='在保存的文本标签中包含置信度。')
parser.add_argument('--save-json', action='store_true',
                    help='保存COCO-JSON格式的结果文件')
parser.add_argument('--project', default='runs/val',
                    help='结果保存的项目路径')
parser.add_argument('--name', default='exp',
                    help='保存结果的子目录名称exp')
parser.add_argument('--exist-ok', action='store_true',
                    help='如果项目名称已存在,则不递增编号。')
parser.add_argument('--half', action='store_true',
                    help='使用FP16半精度推理,半精度会降低精度,但是推理速度快')
parser.add_argument('--dnn', action='store_true',
                    help='使用OpenCV DNN进行ONNX推理')
parser.add_argument('--min-items', type=int, default=0,
                    help='Experimental,实验功能')

验证示例

cd yolov9项目路径

python3 val_dual.py --data data/fire.yaml --weights runs/train/exp/weights/best.pt --batch-size 4 --imgsz 640 --conf-thres 0.5 --iou-thres 0.8

5 预测

预测相关的参数解析如下

# predict
parser.add_argument('--weights', nargs='+', type=str, default='',
                    help='模型权重的路径')
parser.add_argument('--source', type=str, default='data/images',
                    help='预测数据的来源,可以是文件、目录、URL、glob模式、屏幕捕获或网络摄像头')
parser.add_argument('--data', type=str, default='data/coco128.yaml',
                    help='数据集配置文件的路径,默认为ROOT/data/coco128.yaml')
parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640],
                    help='推理时的图像大小')
parser.add_argument('--conf-thres', type=float, default=0.25,
                    help='检测的置信度阈值。默认为0.25')
parser.add_argument('--iou-thres', type=float, default=0.45,
                    help='非最大抑制(NMS)的交并比(IoU)阈值。默认为0.45')
parser.add_argument('--max-det', type=int, default=1000,
                    help='每张图像的最大检测框数量。默认为1000')
parser.add_argument('--device', default='',
                    help='指定运行设备,CUDA设备(0或0,1,2,3)或CPU')
parser.add_argument('--view-img', action='store_true',
                    help='设置时,展示检测结果。')
parser.add_argument('--save-txt', action='store_true',
                    help='设置时,将检测结果保存为文本文件')
parser.add_argument('--save-csv', action='store_true',
                    help='设置时,将检测结果保存为CSV格式')
parser.add_argument('--save-conf', action='store_true',
                    help='设置时,保存置信度信息')
parser.add_argument('--save-crop', action='store_true',
                    help='设置时,保存被检测对象的裁剪图像')
parser.add_argument('--nosave', action='store_true',
                    help='设置时,不保存图像或视频结果')
parser.add_argument('--classes', nargs='+', type=int,
                    help='过滤指定的类别,例如0或 0 2 3 4')
parser.add_argument('--agnostic-nms', action='store_true',
                    help='设置时,使用与类别无关的NMS')
parser.add_argument('--augment', action='store_true',
                    help='设置时,使用增强的推理')
parser.add_argument('--visualize', action='store_true',
                    help='设置时,可视化')
parser.add_argument('--update', action='store_true',
                    help='设置时,更新所有模型')
parser.add_argument('--project', default='runs/detect',
                    help='设置结果保存的项目目录,默认为ROOT/runs/detect')
parser.add_argument('--name', default='exp',
                    help='设置保存结果的子目录名称,默认为exp')
parser.add_argument('--exist-ok', action='store_true',
                    help='设置时,允许已存在的项目/名称,不自动增加编号')
parser.add_argument('--line-thickness', default=3, type=int,
                    help='设置边界框的线条粗细')
parser.add_argument('--hide-labels', default=False, action='store_true',
                    help='设置时,隐藏标签')
parser.add_argument('--hide-conf', default=False, action='store_true',
                    help='设置时,隐藏置信度')
parser.add_argument('--half', action='store_true',
                    help='设置时,使用FP16半精度推理(精度会下降),推理速度快')
parser.add_argument('--dnn', action='store_true',
                    help='设置时,使用OpenCV DNN模块进行ONNX推理')
parser.add_argument('--vid-stride', type=int, default=1,
                    help='设置视频帧率步长,默认值为1')

预测示例

python detect_dual.py --source 'data/images/test.jpg' --img 640  --weights 'runs/train/exp/weights/best.pt' --name yolov9_c_640_detect

检测的结果如下图所示:

6 报错处理

【报错】

AttributeError: 'FreeTypeFont' object has no attribute 'getsize'

【解决方法】

pip install Pillow==9.5 -i https://pypi.tuna.tsinghua.edu.cn/simple

其他

RepNCSPELAN4结构

class RepNCSPELAN4(nn.Module):
    # csp-elan
    def __init__(self, c1, c2, c5=1):  # c5 = repeat
        super().__init__()
        c3 = int(c2 / 2)
        c4 = int(c3 / 2)
        self.c = c3 // 2
        self.cv1 = Conv(c1, c3, 1, 1)
        self.cv2 = nn.Sequential(RepNCSP(c3 // 2, c4, c5), Conv(c4, c4, 3, 1))
        self.cv3 = nn.Sequential(RepNCSP(c4, c4, c5), Conv(c4, c4, 3, 1))
        self.cv4 = Conv(c3 + (2 * c4), c2, 1, 1)
 
    def forward(self, x):
        y = list(self.cv1(x).chunk(2, 1))
        y.extend((m(y[-1])) for m in [self.cv2, self.cv3])
        return self.cv4(torch.cat(y, 1))
 
    def forward_split(self, x):
        y = list(self.cv1(x).split((self.c, self.c), 1))
        y.extend(m(y[-1]) for m in [self.cv2, self.cv3])
        return self.cv4(torch.cat(y, 1))

SPPELAN结构

class SP(nn.Module):
    def __init__(self, k=3, s=1):
        super(SP, self).__init__()
        self.m = nn.MaxPool2d(kernel_size=k, stride=s, padding=k // 2)
 
    def forward(self, x):
        return self.m(x)
 
 
class SPPELAN(nn.Module):
    # spp-elan
    def __init__(self, c1, c2, c3):  # ch_in, ch_out, number, shortcut, groups, expansion
        super().__init__()
        self.c = c3
        self.cv1 = Conv(c1, c3, 1, 1)
        self.cv2 = SP(5)
        self.cv3 = SP(5)
        self.cv4 = SP(5)
        self.cv5 = Conv(4*c3, c2, 1, 1)
 
    def forward(self, x):
        y = [self.cv1(x)]
        y.extend(m(y[-1]) for m in [self.cv2, self.cv3, self.cv4])
        return self.cv5(torch.cat(y, 1))

YOLOv9的yaml文件

# YOLOv9

# parameters
nc: 80  # number of classes
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple
#activation: nn.LeakyReLU(0.1)
activation: nn.ReLU()

# anchors
anchors: 3

# YOLOv9 backbone
backbone:
  [
   [-1, 1, Silence, []],  
   
   # conv down
   [-1, 1, Conv, [64, 3, 2]],  # 1-P1/2

   # conv down
   [-1, 1, Conv, [128, 3, 2]],  # 2-P2/4

   # elan-1 block
   [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]],  # 3

   # conv down
   [-1, 1, Conv, [256, 3, 2]],  # 4-P3/8

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]],  # 5

   # conv down
   [-1, 1, Conv, [512, 3, 2]],  # 6-P4/16

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 7

   # conv down
   [-1, 1, Conv, [512, 3, 2]],  # 8-P5/32

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 9
  ]

# YOLOv9 head
head:
  [
   # elan-spp block
   [-1, 1, SPPELAN, [512, 256]],  # 10

   # up-concat merge
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 7], 1, Concat, [1]],  # cat backbone P4

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 13

   # up-concat merge
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 5], 1, Concat, [1]],  # cat backbone P3

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [256, 256, 128, 1]],  # 16 (P3/8-small)

   # conv-down merge
   [-1, 1, Conv, [256, 3, 2]],
   [[-1, 13], 1, Concat, [1]],  # cat head P4

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 19 (P4/16-medium)

   # conv-down merge
   [-1, 1, Conv, [512, 3, 2]],
   [[-1, 10], 1, Concat, [1]],  # cat head P5

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 22 (P5/32-large)
   
   # routing
   [5, 1, CBLinear, [[256]]], # 23
   [7, 1, CBLinear, [[256, 512]]], # 24
   [9, 1, CBLinear, [[256, 512, 512]]], # 25
   
   # conv down
   [0, 1, Conv, [64, 3, 2]],  # 26-P1/2

   # conv down
   [-1, 1, Conv, [128, 3, 2]],  # 27-P2/4

   # elan-1 block
   [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]],  # 28

   # conv down fuse
   [-1, 1, Conv, [256, 3, 2]],  # 29-P3/8
   [[23, 24, 25, -1], 1, CBFuse, [[0, 0, 0]]], # 30  

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]],  # 31

   # conv down fuse
   [-1, 1, Conv, [512, 3, 2]],  # 32-P4/16
   [[24, 25, -1], 1, CBFuse, [[1, 1]]], # 33 

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 34

   # conv down fuse
   [-1, 1, Conv, [512, 3, 2]],  # 35-P5/32
   [[25, -1], 1, CBFuse, [[2]]], # 36

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 37

   # detect
   [[31, 34, 37, 16, 19, 22], 1, DualDDetect, [nc]],  # DualDDetect(A3, A4, A5, P3, P4, P5)
  ]

GELAN允许支持多种类型的计算块,这使得它可以更好地适应各种不同的计算需求和硬件约束。

YOLOv9-GELAN版本yaml文件

# YOLOv9

# parameters
nc: 80  # number of classes
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple
#activation: nn.LeakyReLU(0.1)
#activation: nn.ReLU()

# anchors
anchors: 3

# gelan backbone
backbone:
  [
   # conv down
   [-1, 1, Conv, [64, 3, 2]],  # 0-P1/2

   # conv down
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4

   # elan-1 block
   [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]],  # 2

   # avg-conv down
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]],  # 4

   # avg-conv down
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 6

   # avg-conv down
   [-1, 1, Conv, [512, 3, 2]],  # 7-P5/32

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 8
  ]

# gelan head
head:
  [
   # elan-spp block
   [-1, 1, SPPELAN, [512, 256]],  # 9

   # up-concat merge
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 6], 1, Concat, [1]],  # cat backbone P4

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 12

   # up-concat merge
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 4], 1, Concat, [1]],  # cat backbone P3

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [256, 256, 128, 1]],  # 15 (P3/8-small)

   # avg-conv-down merge
   [-1, 1, Conv, [256, 3, 2]],
   [[-1, 12], 1, Concat, [1]],  # cat head P4

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 18 (P4/16-medium)

   # avg-conv-down merge
   [-1, 1, Conv, [512, 3, 2]],
   [[-1, 9], 1, Concat, [1]],  # cat head P5

   # elan-2 block
   [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]],  # 21 (P5/32-large)

   # detect
   [[15, 18, 21], 1, DDetect, [nc]],  # Detect(P3, P4, P5)
  ]

训练

1 Single GPU training

# train yolov9 models

python train_dual.py --workers 8 --device 0 --batch 16 --data data/coco.yaml --img 640 --cfg models/detect/yolov9-c.yaml --weights '' --name yolov9-c --hyp hyp.scratch-high.yaml --min-items 0 --epochs 500 --close-mosaic 15
# train gelan models

python train.py --workers 8 --device 0 --batch 32 --data data/coco.yaml --img 640 --cfg models/detect/gelan-c.yaml --weights '' --name gelan-c --hyp hyp.scratch-high.yaml --min-items 0 --epochs 500 --close-mosaic 15

2 Multiple GPU training

# train yolov9 models

python -m torch.distributed.launch --nproc_per_node 8 --master_port 9527 train_dual.py --workers 8 --device 0,1,2,3,4,5,6,7 --sync-bn --batch 128 --data data/coco.yaml --img 640 --cfg models/detect/yolov9-c.yaml --weights '' --name yolov9-c --hyp hyp.scratch-high.yaml --min-items 0 --epochs 500 --close-mosaic 15
# train gelan models

python -m torch.distributed.launch --nproc_per_node 4 --master_port 9527 train.py --workers 8 --device 0,1,2,3 --sync-bn --batch 128 --data data/coco.yaml --img 640 --cfg models/detect/gelan-c.yaml --weights '' --name gelan-c --hyp hyp.scratch-high.yaml --min-items 0 --epochs 500 --close-mosaic 15

验证Evaluation

# evaluate yolov9 models

python val_dual.py --data data/coco.yaml --img 640 --batch 32 --conf 0.001 --iou 0.7 --device 0 --weights './yolov9-c.pt' --save-json --name yolov9_c_640_val
# evaluate gelan models

 python val.py --data data/coco.yaml --img 640 --batch 32 --conf 0.001 --iou 0.7 --device 0 --weights './gelan-c.pt' --save-json --name gelan_c_640_val

tensorboard 的使用

tensorboard的使用方法示例如下:

cd 解析文件的上一级目录
tensorboard --logdir=exp

具体情况见下图:

然后,打开链接:http://localhost:6006/

【报错】💔💔💔

TypeError: MessageToJson() got an unexpected keyword argument 'including_default_value_fields'

同时没有显示图像。

【分析】💜💜💜

tensorboard的版本过高,降低即可。

【解决方法】💚💚💚

pip install tensorboard==2.12.0

问题解决啦!!!🌺🌺🌺

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

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

相关文章

JavaSE图书管理系统

JavaSE图书管理系统 思路一.Main方法二.User包1.User类2.NormaUser类3.AdminUser类三.book包1.BookList类2.Book类四.operation包1.IOPeration接口2.AddOperation类新增图书3.BorrowOperation类借阅图书4.DelOperation类删除图书5.FindOperation类查找图书6.ReturnOperation类归…

Centos7配置IP地址

1、找到网卡名字 使用root用户登陆&#xff0c;输入命令 ifconfig 2、打开配置文件 输入命令&#xff0c;打开配置文件 vi /etc/sysconfig/network-scripts/ifcfg-ens33 3、添加IP地址 3.1修改BOOTPROTO 将“BOOTPROTOdhcp” 改为 “BOOTPROTOstatic” 3.2添加IP地址 在配…

【JavaEE多线程】从单例模式到线程池的深入探索

目录 多线程案例单例模式阻塞队列定时器线程池总结-保证线程安全的思路对比线程和进程 多线程案例 单例模式 单例模式是一种设计模式 设计模式&#xff0c;就是程序员的棋谱&#xff0c;这里介绍了很多典型场景&#xff0c;以及典型场景的处理方式&#xff0c;按照设计模式写…

火车头采集一键发布到Zblog

火车头采集发布到Zblog系统&#xff0c;主要操作步骤如下&#xff1a; 目录 1、Zblog火车头Web发布模块 2、内容发布参数映射&#xff0c;火车头发布到Zblog 3、简数一键发布到Zblog方法 1、Zblog火车头Web发布模块 自行编写Zblog火车头Web发布模块&#xff0c;一般要使用f…

Linux--进程间的通信--进程池

进程间的通信–匿名管道 进程池的概念 进程池是一种将多个进程组织起来以执行特定任务的机制。它由多个预先创建好的资源进程和一个管理进程组成。这些资源进程被管理进程负责分配和调度&#xff0c;用于处理任务。 当有新的任务提交时&#xff0c;管理进程会从进程池中取出一…

2024北京门窗展|2024北京门窗展会|2024北京门窗展览会

CWE中国&#xff08;北京&#xff09;国际系统门窗及幕墙博览会 CWE China&#xff08;Beijing&#xff09;International System Doors Windows and Curtain Walls Expo 2024年8月29-31日 北京&#xff0c;中国国际展览中心顺义馆 展会概况&#xff1a; 2024年CWE中国&…

【Unity】ScriptableObject 在游戏中的使用实例

ScriptableObject 在游戏中的使用实例 ScriptableObject 使用指南Unity 存储游戏数据的几种方法Unity ScriptableObject实例创建一个物品管理的ScriptableObject创建一个管理所有 ScriptableObject 的数据库&#xff08;ItemDBSO&#xff09; ScriptableObject 使用指南 Scrip…

回溯算法练习day.2

216.组合总和III 链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相…

基于STM32的RFID智能门锁系统

本文针对RFID技术&#xff0c;着重研究了基于单片机的智能门锁系统设计。首先&#xff0c;通过链接4*4按键模块与主控STM32&#xff0c;实现了多种模式&#xff0c;包括刷卡开锁、卡号权限管理、密码开锁、修改密码、显示实时时间等功能。其次&#xff0c;采用RC522模块与主控S…

【C语言基础】:预处理详解(二)

文章目录 一、宏和函数的对比二、#和##运算符2.1 #运算符2.2 ##运算符 三、#undef四、命令行定义五、条件编译六、头文件的包含1. 头文件包含的方式2. 嵌套文件包含 上期回顾&#xff1a; 【C语言基础】&#xff1a;预处理详解(一) 一、宏和函数的对比 宏通常被应有于执行简单…

Vue3---基础10(路由)

写一个最基本的路由导航 下载、创建、使用路由 下载路由 npm i vue-router 创建路由 先在 src 内去创建一个 router 文件夹 在文件夹内创建一个 index 文件 index.ts 内代码 // 创建一个路由器&#xff0c;并暴露出去 // 引入createRouter import { createRouter, createWeb…

CSS使用自己的字体

在项目的根目录下的static文件夹中放置字体文件。在项目中使用这个字体&#xff0c;需要2个步骤。 一. 你需要在全局样式文件中引入它。 假设你的全局样式文件是App.vue或者App.vue中引入的App.scss文件&#xff0c;你可以像这样引入字体文件&#xff1a; font-face {font-fa…

深度学习体系结构——CNN, RNN, GAN, Transformers, Encoder-Decoder Architectures算法原理与应用

1. 卷积神经网络 卷积神经网络&#xff08;CNN&#xff09;是一种特别适用于处理具有网格结构的数据&#xff0c;如图像和视频的人工神经网络。可以将其视作一个由多层过滤器构成的系统&#xff0c;这些过滤器能够处理图像并从中提取出有助于进行预测的有意义特征。 设想你手…

MySQL中的存储过程详解(上篇)

使用语言 MySQL 使用工具 Navicat Premium 16 代码能力快速提升小方法&#xff0c;看完代码自己敲一遍&#xff0c;十分有用 拖动表名到查询文件中就可以直接把名字拉进来中括号&#xff0c;就代表可写可不写 目录 1.认识存储过程 1.1 存储过程的作用 1.2 存储过程简介…

C#基础|数据类型、变量

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 01 数据类型 数据类型是为了方便存储数据的&#xff0c;为了将数据按照不同的分类存储&#xff0c;所以引入数据类型。这个在PLC中已经很熟悉了。 数据类型的作用&#xff1a;就是为了更好地管理内存&#xff0c;为…

顺序表 (头删 尾删 清空)

//头删 | 1 #include "head.h" | 1 #ifndef ww87 void head_del(p lp) | 2 int main(int argc, const char *argv[]) …

[C++][算法基础]求最小生成树(Kruskal)

给定一个 n 个点 m 条边的无向图&#xff0c;图中可能存在重边和自环&#xff0c;边权可能为负数。 求最小生成树的树边权重之和&#xff0c;如果最小生成树不存在则输出 impossible。 给定一张边带权的无向图 G(V,E)&#xff0c;其中 V 表示图中点的集合&#xff0c;E 表示图…

民航电子数据库:[E14024]事务内变更操作次数超过最大许可值10000,可通过系统参数max_trans_modify适当调整限制

目录 一、场景二、异常情况三、原因四、排查五、解决 一、场景 1、对接民航电子数据 2、执行delete语句时报错 二、异常情况 三、原因 通过报错信息就可以看出&#xff0c;是系统参数max_trans_modify配置导致 当删除的数据量 > max_trans_modify时&#xff0c;删除就会…

Visual studio项目默认“Header Files”、“Source Files”等过滤器消失后展开的方法。

使用Visual Studio进行项目开发创建默认工程的解决方案资源管理器里查看项目文件&#xff0c;所有的文件是按照其所属的类型自动归类&#xff0c;例如&#xff1a;.h头文件自动划归到Header Files文件夹&#xff0c;.cpp文件自动划归到Source Files文件夹下&#xff0c;如下图所…

关于AG32 MCU的一些奇思妙想

1、AG32VF103的网口是100M还是10M&#xff1f; RE: 都是100M的。 2、用FPGA能不能再仿出一个网口&#xff1f;有些产品用到两个网口。 理论上可以&#xff0c;但是要考虑&#xff0c;一个是cpld实现难度&#xff0c;一个是需要的逻辑单元。因为mac逻辑多&#xff0c;内置的2KL…