yolov5的anchors的编解码原理

  • yolov5的anchors及bbox的编解码原理
    • 1.anchor的生成
      • 1)base anchor的生成
      • 2)base anchor的平移和复制
    • 2.bbox的编解码过程

yolov5的anchors及bbox的编解码原理

1.anchor的生成

anchor的生成分为两个步骤:

首先会生成位于feature map左上角的base anchor,众所周知yolov3有9组anchor(图2),3个不同尺度大小的输出,而3个输出各对应三组anchor;生成base anchor之后会根据不同feature map的stride对base anchor进行平移复制。

图1 anchor的生成的代码实现

图2 9组anchor h*w

1)base anchor的生成

现假设输入图片为448640,那么最后输出的三个featuremap大小从小到大依次为:1420、2840、5680,对应的stride从小到大依次为:32,16,8。**以1420的feature map为例**,stride=32,对应9组anchor中的第一组:[(116, 90), (156, 198), (373, 326)]。那么图1中的代码就干两件事儿,生成base anchor:

图3 base anchor中心点位于左上角网格的中心位置

2)base anchor的平移和复制

平移复制base anchor,stride=32(feature map为14*20,那么相对于原图一个网格边长就是32):

图4 只画了116*90的anchor的平移示意,在14*20的feature map上最终共有14*20*3=840个anchor

最终,在14×20的feature map上有14×20×3=840个anchor,在28×40的feature map上有28×40×3=3360个anchor,在5680的feature map上有5680*3=13440个anchor,共计17640个anchor。

anchor生成完毕之后,再做一些操作之后就是decoder了,decode完毕之后就是NMS

2.bbox的编解码过程

编解码代码:

@BBOX_CODERS.register_module()
class YOLOV5BBoxCoder(BaseBBoxCoder):"""YOLO BBox coder.Following `YOLO <https://arxiv.org/abs/1506.02640>`_, this coder divideimage into grids, and encode bbox (x1, y1, x2, y2) into (cx, cy, dw, dh).cx, cy in [0., 1.], denotes relative center position w.r.t the center ofbboxes. dw, dh are the same as :obj:`DeltaXYWHBBoxCoder`.Args:eps (float): Min value of cx, cy when encoding."""def __init__(self, eps=1e-6):super(BaseBBoxCoder, self).__init__()self.eps = epsdef encode(self, bboxes, gt_bboxes, stride):"""YOLOv5 and YOLOx of YOLO series don't have encode"""raise NotImplementedError("YOLOv5 doesn't have encoder!")# targetdef delta_bbox(self, bboxes, pred_bboxes):"""Get delta_bboxes from anchors and pred_bboxes.Args:bboxes: anchors.(x1,y1,x2,y2)pred_bboxes: output bboxes of YOLOv5.(x,y,w,h)"""# anchors' width and heightw, h = bboxes[..., 2] - bboxes[..., 0], bboxes[..., 3] - bboxes[..., 1]# center of x & y of pred_bboxx_center_pred = (pred_bboxes[..., 0].sigmoid() - 0.5) * 2y_center_pred = (pred_bboxes[..., 1].sigmoid() - 0.5) * 2# w & h of pred_bboxw_pred = (pred_bboxes[..., 2].sigmoid() * 2) ** 2 * wh_pred = (pred_bboxes[..., 3].sigmoid() * 2) ** 2 * hdelta_bboxes = torch.stack((x_center_pred - w_pred / 2, y_center_pred - h_pred / 2,x_center_pred + w_pred / 2, y_center_pred + h_pred / 2),dim=-1)return delta_bboxesdef decode(self, bboxes, pred_bboxes, stride):"""Apply transformation `pred_bboxes` to `boxes`.Args:boxes (torch.Tensor): Basic boxes, e.g. anchors.pred_bboxes (torch.Tensor): Encoded boxes with shapestride (torch.Tensor | int): Strides of bboxes.Returns:torch.Tensor: Decoded boxes."""assert pred_bboxes.size(0) == bboxes.size(0)assert pred_bboxes.size(-1) == bboxes.size(-1) == 4x_center = (bboxes[..., 0] + bboxes[..., 2]) * 0.5y_center = (bboxes[..., 1] + bboxes[..., 3]) * 0.5w = bboxes[..., 2] - bboxes[..., 0]h = bboxes[..., 3] - bboxes[..., 1]# Get outputs x, y# 由于mmdetection的anchor已经偏移了0.5,故*2的操作要放在外面x_center_pred = (pred_bboxes[..., 0] - 0.5) * 2 * stride + x_centery_center_pred = (pred_bboxes[..., 1] - 0.5) * 2 * stride + y_center# yolov5中正常情况应该是# x_center_pred = (pred_bboxes[..., 0] * 2. - 0.5 + grid[:, 0]) * stride  # xy# y_center_pred = (pred_bboxes[..., 1] * 2. - 0.5 + grid[:, 1]) * stride  # xy# wh也需要sigmoid,然后乘以4来还原w_pred = (pred_bboxes[..., 2].sigmoid() * 2) ** 2 * wh_pred = (pred_bboxes[..., 3].sigmoid() * 2) ** 2 * hdecoded_bboxes = torch.stack((x_center_pred - w_pred / 2, y_center_pred - h_pred / 2,x_center_pred + w_pred / 2, y_center_pred + h_pred / 2),dim=-1)return decoded_bboxes

bbox框的编解码原理
其实整个过程可以理解成anchor在起什么作用,下面就简单的说明一下。我们知道yolo直接去预测出目标的位置坐标是不现实的,所以yolo的作者就提出去预测gt和anchor的偏移量。
示意图说明:

图5 图中蓝色框表示Anchor,绿色框表示人工标注,红色框则表示网络的预测结果(未经过训练)

上图中我们要先得到Anchor中心点所在网格的左上角坐标a=(6,2),再得到人工标注的中心点坐标g=(6.3,3.3),我们取到点g相对于点a的偏移量,记作p=(0.3,1.3),以p点坐标为中心,宽高与人工标注相同,得到target框如下:

图6 左上角天蓝色框为target,即网络需要预测的东西 注意上图中的**天蓝色框target**就是网络需要预测的东西!好了,现在涉及到编码encode了,原来yolov5中的encode代码如下:

pxy = pxy.sigmoid() * 2 - 0.5 # pxy即网络输出的框的xy坐标
pwh = (pwh.sigmoid() * 2) ** 2 * anchor[i] # anchor[i]即对应anchor的宽高
# 可以看出来,上述变化将xy坐标约束到区间[-0.5,1.5],将wh约束到[0,4]*anhcor_wh

将encode应用到上图中的网络输出pred_bbox和anchor,设pred_bbox中心点为r=(3.3,5.2),w=1.9,h=2.2,经过上述两行代码,r=(3.3,5.2)变成(1.428, 1.489),w=1.9变成1.89,h=2.2变成2.43,将得到的新框记作delta,如下:

至此,encode就完成了,一开始我们的网络没有经过训练,框都是乱跑的,经过编码之后约束到一个区间。算法会将上图中的delta框和target送入损失函数中,让网络去学习、去更新参数,使得delta框与target框趋于重合。我们假设网络学习效果非常好,现在的delta框已经与target框几乎重合:

注意了!理一下逻辑。这个时候,我们网络的输出pred_bboxes经过encode之后得到的框(记作res)几乎就是target框,还记得之前的Anchor中心点所在网格的左上角坐标a=(6,2)吗,加到res上不就是人工标注嘛!!

至此就结束了。这边可能有一点绕,因为我觉得下面的逻辑更加合适:

参考:
MMDetection移植yolov5——(二)前向推理

yolov5的anchors及bbox的编解码原理相关推荐

  1. 哈夫曼编解码原理与实现【转载】

    1. 哈夫曼编解码原理 霍夫曼编码(Huffman Coding)是一种编码方法,霍夫曼编码是可变字长编码(VLC)的一种. 霍夫曼编码使用变长编码表对源符号(如文件中的一个字母)进行编码,其中变长编 ...

  2. Base64编解码原理并用Java手工实现Base64编解码

    Base64编解码原理 目前Base64已经成为网络上常见的传输8比特字节代码的编码方式之一.在做支付系统时,系统之间的报文交互都需要使用Base64对明文进行转码,然后进行签名或加密,之后再次Bas ...

  3. 一文读懂视频编解码原理

    引子 谈到视频的编解码,我们会自然地想到H.264.HEVC/H.265这些权威的视频编解码标准:谈到标准,有人觉得这个是有专门机构去研究的,我们关心应用就好:即使有兴趣读了标准和相关技术,面对更多的 ...

  4. MPEG4编解码原理

    ### Date: 2017/3/19 ### Author: SoaringLee ###Content: MPEG4 ASP编解码原理 一.MPEG4的编码原理 1 编码原理MPEG-4编码器主要 ...

  5. adpcm编解码原理及其代码实现

    目录 1. 源代码 adpcm.h adpcm.c 2. adpcm编解码原理 1.adpcm编码原理 2.adpcm解码原理 注释说明 3. ADPCM数据存放形式 1. adpcm 数据块介绍 2 ...

  6. WAV系列之二:ADPCM编解码原理及代码实现

    参考自:<adpcm编解码原理及其代码实现> <ADPCM编码与解码学习笔记> <音频编码:ADPCM> 文章目录 1.PCM 1.1.采样 1.2.量化编码 2. ...

  7. 一文读懂视频编解码原理[通俗易懂]

    一文读懂视频编解码原理[通俗易懂] 引子 谈到视频的编解码,我们会自然地想到H.264.HEVC/H.265这些权威的视频编解码标准:谈到标准,有人觉得这个是有专门机构去研究的,我们关心应用就好:即使 ...

  8. C++安全方向:(二)2.1 base16编解码原理讲解

    1.概述: 二进制转字符串 2.应用场景 (1)邮件编码 (2)xml或者json存储二进制内容 (3)网页传递数据URL (4)数据库中以文本形式存放二进制 (5)可打印的比特币钱包地址,base5 ...

  9. SSD ECC中的LDPC编解码原理

    转自:http://blog.csdn.net/zhuzongpeng/article/details/78899198 目前SSD中ECC纠错代码主要两种BCH和LDPC.不过,随着SSD对ECC纠 ...

最新文章

  1. 入门Go语言神器!超全学习资源+笔记,新手从零学习全过程资源汇总
  2. Redis批量操作详解及性能分析
  3. Redis队列php多线程请求
  4. 微软Tech Summit 2017,等你来打Call
  5. PS教程第十二课:会打开 会关闭我会了
  6. Eigen--.block(i,j,p,q)
  7. Java中调用文件中所有bat脚本
  8. EIGRP and the OSPF redistribute
  9. python自动打开网页_python 自动打开浏览器
  10. unitywebplayer 32/64 5.3版本
  11. 计算机考研408高分复习规划-如何复习408才能得高分
  12. ArcGis如何创建/连接企业级地理数据库
  13. 四核网络机顶盒芯片局势分析(开放市场):rk3128将会成为四核主流
  14. 最难学的十大编程语言,C++排第二,它竟是第一名!不服
  15. UWP VS创建UWP应用项目
  16. golang中net/http包用法
  17. 支付宝app支付产品不通过app集成sdk发起支付(附源码)
  18. 罗技无线键盘linux,罗技发布旗下第一款无线机械游戏键盘 G613
  19. JavaScript笔记(狂神说)
  20. 网络命令一览表(绝对实用)

热门文章

  1. android inactive InputConnection
  2. Hiveserver2源码剖析---如何实现代理用户
  3. AI之NLP:2020年6月21日北京智源大会演讲分享之15:15-15:40黄萱菁教授《自然语言处理中的表示学习》
  4. 散列函数(哈希函数,Hash Function)
  5. 常用CASE工具介绍 (csnd.net)
  6. linux redis密码修改,Linux redis 安装并且修改密码
  7. 敏涵控股集团:大爱敏涵共创敏涵梦
  8. python英译汉库模块_Python 进阶之路-翻译模块
  9. Excel使用教程技巧
  10. ResNet网络详解