0


【代码解读】超详细,YOLOV5之build_targets函数解读。

文章目录

build_targets作用

build_targets函数用于网络训练时计算loss所需要的目标框,即正样本。

注意

  1. 与yolov3/yolov4不同,yolv5支持跨网格预测。即每一个bbox,正对于任何一个输出层,都可能有anchor与之匹配。
  2. 该函数输出的正样本框比传入的GT数目要多。
  3. 当前解读版本为6.1

可视化结果

  • TODO

过程

  1. 首先通过bbox与当前层anchor做一遍过滤。对于任何一层计算当前bbox与当前层anchor的匹配程度,不采用IoU,而采用shape比例。如果anchor与bbox的宽高比差距大于4,则认为不匹配,保留下匹配的bbox。
  1. r = t[...,4:6]/ anchors[:,None]# wh ratio
  2. j = torch.max(r,1/ r).max(2)[0]< self.hyp['anchor_t']# compare# j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2))
  3. t = t[j]# filter
  1. 最后根据留下的bbox,在上下左右四个网格四个方向扩增采样。
  1. gxy = t[:,2:4]# grid xy
  2. gxi = gain[[2,3]]- gxy # inverse
  3. j, k =((gxy %1< g)&(gxy >1)).T
  4. l, m =((gxi %1< g)&(gxi >1)).T
  5. j = torch.stack((torch.ones_like(j), j, k, l, m))
  6. t = t.repeat((5,1,1))[j]

详细代码解读

准备

  1. defbuild_targets(self, p, targets):

P是网络预测的输出。

  1. pshape

:(batch_size,anchor_num,grid_cell,grid_cell,xywh+obj_confidence+classes_num)
在这里插入图片描述
P[0]的shape
在这里插入图片描述
P[1]的shape
在这里插入图片描述
P[2]的shape
在这里插入图片描述


targets是经过数据增强(mosaic等)后总的bbox。

  1. targetsshape

:[num_obj, 6] , that number 6 means -> (img_index, obj_index, x, y, w, h)
在这里插入图片描述
在这里插入图片描述


  1. na, nt = self.na, targets.shape[0]# number of anchors, targets

在这里插入图片描述

  1. tcls, tbox, indices, anch =[],[],[],[]

tcls:用来存储类别。
tbox:用来存储bbox
indices:用来存储第几张图片,当前层的第几个anchor,以及当前层grid的下标。

  1. gain = torch.ones(7, device=self.device)# normalized to gridspace gain

初始化为1,用来还原bbox为当前层的尺度大小。

  1. ai = torch.arange(na, device=self.device).float().view(na,1).repeat(1, nt)# same as .repeat_interleave(nt)

扩充anchor数量和当前bbox一样多。
ai是anchor的下标
在这里插入图片描述在这里插入图片描述

  1. targets = torch.cat((targets.repeat(na,1,1), ai[...,None]),2)# append anchor indices

targets的shape变为(3,101,7)。

  1. targets[0]

对应第一个anchor对应的(image_id, cls, center_x,center_y, w, h,第个anchor)
在这里插入图片描述

  1. targets[1]

对应第一个anchor对应的(image_id, cls, center_x,center_y, w, h,第个anchor)在这里插入图片描述

  1. targets[2]

对应第一个anchor对应的(image_id, cls, center_x,center_y, w, h,第个anchor)在这里插入图片描述

  1. # 预定义的偏移量
  2. g =0.5# bias
  3. 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],
  4. device=self.device).float()* g # offsets
  1. for i inrange(self.nl):# 枚举每一层
  1. anchors = self.anchors[i]# 当前层anchor

self.anchors
在这里插入图片描述

  1. self.anchors[0]

得到第一层归一化后的anchor
在这里插入图片描述
乘8得到的
在这里插入图片描述

  1. self.anchors[1]

得到第二层归一化后的anchor
在这里插入图片描述
乘16得到的
在这里插入图片描述

  1. self.anchors[2]

得到第三层归一化后的anchor
在这里插入图片描述
乘以32得到的
在这里插入图片描述

  1. gain[2:6]= torch.tensor(p[i].shape)[[3, 2, 3, 2]]# xyxy gain

生成一个当前层的方格大小。
如果i=0
在这里插入图片描述
如果i=1,
在这里插入图片描述
如果i=2
在这里插入图片描述

  1. t = targets * gain

将targets的大小映射到当前层,第六列是当前层的第几个anchor,第0列是位于哪张图片,第1列代表的是类别,2-5列是目标在当前层x,y,w,h。
下采样八倍的层
在这里插入图片描述

第一遍筛选

  1. if nt:# 如果存在目标
  1. r = t[..., 4:6] / anchors[:, None]

r是指bbox与当前层三个anchor的高宽的比值。
在这里插入图片描述
r[0]
在这里插入图片描述
r[1]
在这里插入图片描述
r[2]
在这里插入图片描述

  1. j = torch.max(r, 1 / r).max(2)[0]< self.hyp['anchor_t']# compare
  1. torch.max(r, 1 / r).max(2)[0]

为什么是

  1. [0]

不是

  1. [1]

.[0]代表的是value,[1]代表的index。

在这里插入图片描述

  1. torch.max(r, 1 / r).max(2)[1]

在这里插入图片描述

  1. torch.max(r, 1 / r).max(1)[0]

按行获取最大值。
在这里插入图片描述

  1. torch.max(r, 1 / r).max(1)[1]

按行获取最大值,返回索引。
在这里插入图片描述

  1. t = t[j]# filter

经过过滤后,全部汇总到来了一起。按照第六列anchor的顺序排列。
在这里插入图片描述

扩增正样本


接下来是扩增正样本

  1. gxy = t[:,2:4]# grid xy # 获取x,y
  2. gxi = gain[[2,3]]- gxy # inverse

假设最后的特征图大小是8x8,有a-h8个目标边框如下。
在这里插入图片描述
下图中深灰色的表示满足条件的。
在这里插入图片描述

  1. j, k =((gxy %1< g)&(gxy >1)).T
  2. l, m =((gxi %1< g)&(gxi >1)).T
  1. gxy % 1 < g

  1. gxi % 1 < g

包含两个方向,x和y方向。
在这里插入图片描述

  1. ((gxy %1< g)&(gxy >1))#条件合并得到下图

在这里插入图片描述

  1. (gxi %1< g)&(gxi >1)# 条件合并得到下图

在这里插入图片描述

  1. j = torch.stack((torch.ones_like(j), j, k, l, m))
  2. t = t.repeat((5,1,1))[j]# yolov5不仅用目标中心点所在的网格预测该目标,还采用了距目标中心点的最近两个网格# 所以有五种情况,网格本身,上下左右|----------------------------------------------------------------------|| 这里将t复制5个,然后使用j来过滤 || 第一个t是保留经过第一步过滤留下的gtbox,因为上一步里面增加了一个全为true的维度|| 第二个t保留了靠近方格左边的gtbox || 第三个t保留了靠近方格上方的gtbox || 第四个t保留了靠近方格右边的gtbox || 第五个t保留了靠近方格下边的gtbox ||----------------------------------------------------------------------|
  3. offsets =(torch.zeros_like(gxy)[None] + off[:, None])[j]# 生成偏移矩阵

j的第一行全为1,意思是指经过第一步保留下的bbox所在的grid_cell为1.
在这里插入图片描述

  1. else:
  2. t = targets[0]
  3. offsets =0
  1. # Define
  2. bc, gxy, gwh, a = t.chunk(4,1)# (image, class), grid xy, grid wh, anchors
  3. a,(b, c)= a.long().view(-1), bc.long().T # anchors, image, class
  4. gij =(gxy - offsets).long()#减去偏置,得到更多的正样本所在的网格。
  5. gi, gj = gij.T # grid indices

下面的四张图展示了

  1. gij = (gxy - offsets).long()

做了啥。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
最终得到的结果如下
在这里插入图片描述

  1. # Append,将对应的结果存储下来。
  2. indices.append((b, a, gj.clamp_(0, gain[3]-1), gi.clamp_(0, gain[2]-1)))# image, anchor, grid indices
  3. tbox.append(torch.cat((gxy - gij, gwh),1))# box
  4. anch.append(anchors[a])# anchors
  5. tcls.append(c)# class
  1. tbox.append(torch.cat((gxy - gij, gwh), 1)) # box

这句话做的如下:
在这里插入图片描述

Reference

  1. 感谢这位UP主的详细解释,本文的正样本采样细节参考了此UP主的PPT。yolo v5 解读,训练,复现

本文转载自: https://blog.csdn.net/wxd1233/article/details/126148680
版权归原作者 gorgeous(๑>؂<๑) 所有, 如有侵权,请联系我们删除。

“【代码解读】超详细,YOLOV5之build_targets函数解读。”的评论:

还没有评论