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的正负样本的定义和匹配相关推荐
- 正负样本的定义、划分以及用于loss的计算的过程
文章目录 正负样本定义 难分.易分样本定义 正负样本不平衡-引自[Focal Loss](https://blog.csdn.net/qq_38253797/article/details/11629 ...
- 目标检测中如何定义正负样本,和正负样本在学习过程中loss计算起的作用
如何定义正负样本,和正负样本在学习过程中loss计算起的作用 正负样本定义 分类和回归head如何学习和利用划分后的正负样本(loss如何计算) 正负样本在分类中loss计算的处理 正样本在bbox ...
- 纯量产经验 | 谈谈目标检测中正负样本的问题
作者 | Mr.Jian 编辑 | 汽车人 原文链接:https://zhuanlan.zhihu.com/p/563196861 点击下方卡片,关注"自动驾驶之心"公众号 A ...
- Yolov3-v5正负样本匹配机制
本文来自公众号"AI大道理". 什么是正负样本? 正负样本是在训练过程中计算损失用的,而在预测过程和验证过程是没有这个概念的. 正样本并不是手动标注的GT. 正负样本都是针对于 ...
- YOLOv7 | 模型结构与正负样本分配解析
如有错误,恳请指出. Yolov7的原作者就是Yolov4的原作者.看论文的时候看到比较乱,这里可能会比较杂乱的记录一下我觉得有点启发的东西.对于yolov7的代码,我也没有仔细的看,只是大概的看了下 ...
- 【CV】PAA论文解读:在物体检测中利用概率分布来将anchor分配为正负样本
本文转自|AI公园 导读 又一篇anchor匹配策略的文章,不过确实是简单有效,在ATSS上只需要很小的修改就可以提升性能.GFL2在框的预测上用上了概率分布,这里又在anchor匹配上用上了概率分布 ...
- 目标检测算法横向比较,包括backbone、特征融合、loss、proposal/anchor/heatmap、NMS、正负样本设置等
目标检测算法发展移步:目标检测算法 本文从算法改进的方向,进行横向比较,包括backbone,特征融合.loss.proposal/anchor/heatmap.NMS.正负样本设置等 Referen ...
- 正负样本的分配atss
1.FCOS 论文链接:https://arxiv.org/abs/1904.01355 代码链接:https://github.com/tianzhi0549/FCOS/ 作为Anchor-free ...
- yolov7正负样本分配详解
来源:知乎-骚骚骚 地址:https://zhuanlan.zhihu.com/p/543160484 整体上在正负样本分配中,yolov7的策略算是yolov5和YOLOX的结合. 首先大概回顾一下 ...
- 【YOLOv5】正样本分配详解
1.前言 YoloV5中loss由正样本和负样本两部分loss组成,负样本对应着图像的背景,如果负样本远多于正样本,则负样本会淹没正样本的损失,从而降低网络收敛的效率与检测精度.这就是目标检测中常见的 ...
最新文章
- 【Codeforces】808D Array Division(前后两部分和相等)
- 转:AMS之dumpsys篇
- PDH-SDH光端机指示灯具体含义介绍
- 宝塔命令号操作全-最实用的莫过于修改密码啦
- 表格存储TableStore全新升级,打造统一的在线数据存储平台!
- 【azkaban】学习azkaban的笔记以及心得
- Soft NMS算法笔记
- 150分试卷c语言,连续5道C语言题目一共送150分啊,题目2.一个农场有头母牛,现 爱问知识人...
- Leetcode 1013. 总持续时间可被 60 整除的歌曲
- linux 集成 3g 模块 串口 option,华为等 3G、4G模块拨号上网过程分析
- 安装axure插件以便打开原型文件
- instead和instead of
- GAN的评价指标IS和FID
- springboot 整合mybatis,pagehelper。测试类。
- 【神操作】网络分线器短路导致公司网络瘫痪
- java的视频案例教学 值得下载
- 前端程序员成长的记录及被某IT外包公司套路的经历
- 基于WT588F02B语音芯片的智能语音感应洗手液器设计方案
- OTA更新利用CRC保证程序的完整性
- 嵌入式应用角度学习BLE栈
热门文章
- Burp Suite Pro Loader Keygen
- AutoHotKey实现字母组合键代替上下左右
- 照片后期处理软件DxO FilmPack 6 mac中文说明
- MCGS触摸屏未授权访问任意代码执行以及拒绝服务攻击
- 网络安全合规-个人信息安全影响评估-PIA
- 软PLC控制系统架构
- [HDLBits做题]Combinational Logic --- Basic Gates
- 爬虫某个app首页推荐栏目
- as好还是php好,优缺点分析索尼as50和as100v对比有区别没有?哪个好?求助专业爆料评测...
- 2021年电工(中级)报名考试及电工(中级)实操考试视频