yolov5的正负样本的定义和匹配

2023-11-09 16:59

本文主要是介绍yolov5的正负样本的定义和匹配,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • build_target
    • 1.输入参数
    • 2.初始化准备
    • 3.设置偏移值
    • 4.初步筛选出正样本
    • 5.扩增正样本
    • 6.返回值
    • 代码
  • 总结

前言

虽然yolov5没有正式的论文发布,但是其整个检测框架已经越来越成熟了。
源码:https://github.com/ultralytics/yolov5
版本yolov5 v6.1

build_target

正负样本的分配,建立在生成target的步骤上,方便后面训练时损失的计算。

1.输入参数

def build_targets(self, p, targets):'''P:predict->[检测层数,ANCHOR个数,gridspace长,gridspace宽,类别数+5(xywh+obj)], targets:[num_target,image+class+xywh]'''# Build targets for compute_loss(), input targets(image,class,x,y,w,h)

输入参数预测输出p : [检测层数,anchor个数,gridspace长,gridspace宽,classes+5(xywh+obj)],这个p的作用只是为了提供特征层的尺寸,计算target是anchor与targets之间的事。

在这里插入图片描述
输入参数标签targets信息 : [num_target,image+classes+xywh],是归一化了的信息

在这里插入图片描述

2.初始化准备

na : anchor的数量,一般都是给3个聚类或手工设置的模板
nt :一个batch里的所有target的数量
tcls, tbox, indices, anch :用来存放结果
gain :保存输出特征层的长宽尺寸,作为匹配argets在对应特征层上的坐标大小
ai : 一个targets有3个anchors的模板索引,要根据索引取anchor匹配计算loss
targets :每个target都有3个anchors,把anchors的模板索引加到后面,组成一个[3,nt,7]

	  # Build targets for compute_loss(), input targets(image,class,x,y,w,h)na, nt = self.na, targets.shape[0]  # number of anchors, targets,na正常都为3tcls, tbox, indices, anch = [], [], [], [] # 用来存放结果的gain = torch.ones(7, device=self.device)  # normalized to gridspace(就是输出的检测特征层大小) ,保存放缩到特征图大小的因子# ai:[3,nt],每个target对应的anchor索引,方便下一句的ai = torch.arange(na, device=self.device).float().view(na, 1).repeat(1, nt)  # same as .repeat_interleave(nt),# cat([3,nt,6],[3,nt,1],dim=2)->[3,nt,7]  nt:num_targets,增加anchor索引targets = torch.cat((targets.repeat(na, 1, 1), ai[..., None]), 2)  # append anchor indices,复制3份对应3个anchor

3.设置偏移值

设置target上下左右的网格也作为正样本的考虑范围,后面是要减去偏移值
在这里插入图片描述

	  g = 0.5  # bias,偏移值off = torch.tensor(  # 坐标偏移值分别对应中心点、左、上、右、下[[0, 0],[1, 0],[0, 1],[-1, 0],[0, -1],  # j,k,l,m# [1, 1], [1, -1], [-1, 1], [-1, -1],  # jk,jm,lk,lm],device=self.device).float() * g  # offsets,g=0.5,变为偏移值为0.5

4.初步筛选出正样本

不同于yolov3和yolov4利用类似MaxIoUAssigner分配的原则去对正负样本进行定义和分配。yolov5通过将聚类或者手工设置的anchor,通过计算它们与target的宽高之比的最大值是否小于一个阈值来进行正负样本的划分。小于(包含在内)为正样本,大于为负样本。图参考:https://blog.csdn.net/qq_37541097/article/details/123594351
在这里插入图片描述

	for i in range(self.nl): # 遍历每个检测层anchors = self.anchors[i]   # 获取第i个模板的anchor# gain = [1, 1, 特征图w, 特征图_h, 特征图w, 特征图_h]gain[2:6] = torch.tensor(p[i].shape)[[3, 2, 3, 2]]  # xyxy gain,放缩因子# Match targets to anchorst = targets * gain  # targets为归一化的,乘以当前层尺度还原为当前层的尺度if nt:  # 如果分层检测的特征层上有目标# Matchesr = t[..., 4:6] / anchors[:, None]  # wh ratio# self.hyp['anchor_t']=4,根据偏移值计算公式,bw=pw(2σ(tw))^2,比值范围最好为(0,4)j = torch.max(r, 1 / r).max(2)[0] < self.hyp['anchor_t']  # compare,.max(2)[0]返回宽的比值和高的比值两者中较大的一个值# yolov5之前的方法,通过iou阈值来分配正负样本# j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t']  # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2))# j中,符合比列要求的为true,否则为falset = t[j]  # filter,[3,nt,7][3,nt]->[num_P,7],初步选择好了哪些anchors对应正样本

5.扩增正样本

为了解决正样本较少的问题,同时因为中心偏移值范围限制在(-0.5,1.5)之间,所以可以通过将周围符合条件的网格也作为正样本点。一个target除了本身匹配的一个正样本,还可以通过减去偏移值,将target最多移动到邻近的两个网格以网格左上角为标准去进行回归偏移值计算。这样,一个target最多可以匹配三个正样本。
在这里插入图片描述

      # Offsetsgxy = t[:, 2:4]  # grid xy, # 正样本的xy中心坐标gxi = gain[[2, 3]] - gxy  # inverse  #  特征图的长宽-targets的中心j, k = ((gxy % 1 < g) & (gxy > 1)).T  # <0.5,取网格中偏向于左,上的target为truel, m = ((gxi % 1 < g) & (gxi > 1)).T    # 取网格中偏向于右,下的target为truej = torch.stack((torch.ones_like(j), j, k, l, m))  # 中心加左,上,右,下,五个# [num_P,7]->[5,num_P,7][5,num_P]->[num_P+,7],取出所有对应为true的target信息# 有重复的,但是后面会减去相应的偏移值,来定义更多的正样本,进而扩充正样本数量t = t.repeat((5, 1, 1))[j]   # 复制五份,取出对应位置的target信息# [1,num_P,2]+[5,1,2]->[5,num_P,2],初始化坐标值,表示后面正样本经过每个偏移方向后的坐标# [5,num_P,2][5,num_P]->[num_P+,7],符合上面所说的每个正样本取邻近网格作为正样本偏移值的计算offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j]else:t = targets[0]offsets = 0# Definebc, gxy, gwh, a = t.chunk(4, 1)  # (image, class), grid xy, grid wh, anchorsa, (b, c) = a.long().view(-1), bc.long().T  # anchors, image, class# 正样本中心坐标减去每个方向的偏移值,对应一个正样本变成三个正样本,.long()表示以网格左上角坐标计算偏移值gij = (gxy - offsets).long()    gi, gj = gij.T  # grid indices,把坐标分离开

6.返回值

indices:batch里图像的索引,anchor的索引,以及预测输出特征层坐标的索引。这个后面计算loss的时候要从相应位置取出anchor与targets计算的偏移值与预测值计算loss
tbox:保存anchor与targets计算的偏移值,以对应特征网格左上角为标准,中心xy范围(0~1),wh是相应的特征图尺度
anch:正样本对应的anchor模板
tcls:类别

# Appendindices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1)))  # image, anchor, grid indices# gxy - gij:表示的是对于网格左上角的偏移值,gwh:targets的宽高,没做什么处理tbox.append(torch.cat((gxy - gij, gwh), 1))  # box,偏移值anch.append(anchors[a])  # anchorstcls.append(c)  # classreturn tcls, tbox, indices, anch

代码

 def build_targets(self, p, targets):'''P:predict->[检测层数,ANCHOR个数,gridspace长,gridspace宽,类别数+5(xywh+obj)], target:[num_target,image_index+class+xywh]'''# Build targets for compute_loss(), input targets(image,class,x,y,w,h)na, nt = self.na, targets.shape[0]  # number of anchors, targets,na正常都为3tcls, tbox, indices, anch = [], [], [], [] # 用来存放结果的gain = torch.ones(7, device=self.device)  # normalized to gridspace(就是输出的检测特征层大小) ,保存放缩到特征图大小的因子# ai:[3,nt],每个target对应的anchor索引,方便下一句的ai = torch.arange(na, device=self.device).float().view(na, 1).repeat(1, nt)  # same as .repeat_interleave(nt),# cat([3,nt,6],[3,nt,1],dim=2)->[3,nt,7]  nt:num_targets,增加anchor索引targets = torch.cat((targets.repeat(na, 1, 1), ai[..., None]), 2)  # append anchor indices,复制3份对应3个anchor# [num_anchor,num_target,image_idx+class+xywh+anchor_idx]g = 0.5  # bias,偏移值off = torch.tensor(  # 坐标偏移值分别对应中心点、左、上、右、下[[0, 0],[1, 0],[0, 1],[-1, 0],[0, -1],  # j,k,l,m# [1, 1], [1, -1], [-1, 1], [-1, -1],  # jk,jm,lk,lm],device=self.device).float() * g  # offsets,g=0.5,变为偏移值为0.5for i in range(self.nl): # 遍历每个检测层anchors = self.anchors[i]   # 获取第i个模板的anchor# gain = [1, 1, 特征图w, 特征图_h, 特征图w, 特征图_h]gain[2:6] = torch.tensor(p[i].shape)[[3, 2, 3, 2]]  # xyxy gain,放缩因子# Match targets to anchorst = targets * gain  # targets为归一化的,乘以当前层尺度还原为当前层的尺度if nt:  # 如果分层检测的特征层上有目标# Matchesr = t[..., 4:6] / anchors[:, None]  # wh ratio# self.hyp['anchor_t']=4,根据偏移值计算公式,bw=pw(2σ(tw))^2,比值范围最好为(0,4)j = torch.max(r, 1 / r).max(2)[0] < self.hyp['anchor_t']  # compare,.max(2)[0]返回宽的比值和高的比值两者中较大的一个值# yolov5之前的方法,通过iou阈值来分配正负样本# j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t']  # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2))# j中,符合比列要求的为true,否则为falset = t[j]  # filter,[3,nt,7][3,nt]->[num_P,7],初步选择好了哪些anchors对应正样本# Offsetsgxy = t[:, 2:4]  # grid xy, # 正样本的xy中心坐标gxi = gain[[2, 3]] - gxy  # inverse  #  特征图的长宽-targets的中心j, k = ((gxy % 1 < g) & (gxy > 1)).T  # <0.5,取网格中偏向于左,上的target为truel, m = ((gxi % 1 < g) & (gxi > 1)).T    # 取网格中偏向于右,下的target为truej = torch.stack((torch.ones_like(j), j, k, l, m))  # 中心加左,上,右,下,五个# [num_P,7]->[5,num_P,7][5,num_P]->[num_P+,7],取出所有对应为true的target信息# 有重复的,但是后面会减去相应的偏移值,来定义更多的正样本,进而扩充正样本数量t = t.repeat((5, 1, 1))[j]   # 复制五份,取出对应位置的target信息# [1,num_P,2]+[5,1,2]->[5,num_P,2],初始化坐标值,表示后面正样本经过每个偏移方向后的坐标# [5,num_P,2][5,num_P]->[num_P+,7],符合上面所说的每个正样本取邻近网格作为正样本偏移值的计算offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j]else:t = targets[0]offsets = 0# Definebc, gxy, gwh, a = t.chunk(4, 1)  # (image, class), grid xy, grid wh, anchorsa, (b, c) = a.long().view(-1), bc.long().T  # anchors, image, class# 正样本中心坐标减去每个方向的偏移值,对应一个正样本变成三个正样本,.long()表示以网格左上角坐标gij = (gxy - offsets).long()    gi, gj = gij.T  # grid indices,把坐标分离开# Appendindices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1)))  # image, anchor, grid indices# gxy - gij:表示的是对于网格左上角的偏移值,gwh:targets的宽高,没做什么处理tbox.append(torch.cat((gxy - gij, gwh), 1))  # box,偏移值anch.append(anchors[a])  # anchorstcls.append(c)  # classreturn tcls, tbox, indices, anch

总结

yolov5使用自己的数据集相关代码
yolov5网络结构代码解读

这篇关于yolov5的正负样本的定义和匹配的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/377427

相关文章

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

hdu 3065 AC自动机 匹配串编号以及出现次数

题意: 仍旧是天朝语题。 Input 第一行,一个整数N(1<=N<=1000),表示病毒特征码的个数。 接下来N行,每行表示一个病毒特征码,特征码字符串长度在1—50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。 在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。

二分最大匹配总结

HDU 2444  黑白染色 ,二分图判定 const int maxn = 208 ;vector<int> g[maxn] ;int n ;bool vis[maxn] ;int match[maxn] ;;int color[maxn] ;int setcolor(int u , int c){color[u] = c ;for(vector<int>::iter

基于 YOLOv5 的积水检测系统:打造高效智能的智慧城市应用

在城市发展中,积水问题日益严重,特别是在大雨过后,积水往往会影响交通甚至威胁人们的安全。通过现代计算机视觉技术,我们能够智能化地检测和识别积水区域,减少潜在危险。本文将介绍如何使用 YOLOv5 和 PyQt5 搭建一个积水检测系统,结合深度学习和直观的图形界面,为用户提供高效的解决方案。 源码地址: PyQt5+YoloV5 实现积水检测系统 预览: 项目背景

POJ 3057 最大二分匹配+bfs + 二分

SampleInput35 5XXDXXX...XD...XX...DXXXXX5 12XXXXXXXXXXXXX..........DX.XXXXXXXXXXX..........XXXXXXXXXXXXX5 5XDXXXX.X.DXX.XXD.X.XXXXDXSampleOutput321impossible

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

OmniGlue论文详解(特征匹配)

OmniGlue论文详解(特征匹配) 摘要1. 引言2. 相关工作2.1. 广义局部特征匹配2.2. 稀疏可学习匹配2.3. 半稠密可学习匹配2.4. 与其他图像表示匹配 3. OmniGlue3.1. 模型概述3.2. OmniGlue 细节3.2.1. 特征提取3.2.2. 利用DINOv2构建图形。3.2.3. 信息传播与新的指导3.2.4. 匹配层和损失函数3.2.5. 与Super

二分图的最大匹配——《啊哈!算法》

二分图 如果一个图的所有顶点可以被分为X和Y两个集合,并且所有边的两个顶点恰好一个属于X,另外一个属于Y,即每个集合内的顶点没有边相连,那么此图就是二分图。 二分图在任务调度、工作安排等方面有较多的应用。 判断二分图:首先将任意一个顶点着红色,然后将其相邻的顶点着蓝色,如果按照这样的着色方法可以将全部顶点着色的话,并且相邻的顶点着色不同,那么该图就是二分图。 java

web群集--nginx配置文件location匹配符的优先级顺序详解及验证

文章目录 前言优先级顺序优先级顺序(详解)1. 精确匹配(Exact Match)2. 正则表达式匹配(Regex Match)3. 前缀匹配(Prefix Match) 匹配规则的综合应用验证优先级 前言 location的作用 在 NGINX 中,location 指令用于定义如何处理特定的请求 URI。由于网站往往需要不同的处理方式来适应各种请求,NGINX 提供了多种匹

浙大数据结构:树的定义与操作

四种遍历 #include<iostream>#include<queue>using namespace std;typedef struct treenode *BinTree;typedef BinTree position;typedef int ElementType;struct treenode{ElementType data;BinTree left;BinTre