目标检测 --- Anchor的生成
1.Faster rcnn
1.1.概述
- anchor本身的设置是基于各层输出分辨率上的各点,由各点回归出anchor的偏移量,预测anchor的类别;故anchor的布局需要和各层输出分辨率对应。
- 输出分辨率各点anchor的数量和尺寸是可以调整的,其设置的合理与否,决定了网络的训练难易程度和模型的精度。
- anchor大小的设置是对应到输入分辨率【即训练分辨率】大小,和原图大小和输出分辨率无关。
1.2.anchor生成步骤
a) 在rpn网络初始化的同时,完成基础anchor的构建
class RPNHead(AnchorHead):def __init__(self, in_channels,......seperable=False,**kwargs):......super(RPNHead, self).__init__(2, in_channels, **kwargs)class AnchorHead(nn.Module):def __init__(self,num_classes,.......anchor_scales=[8, 16, 32],anchor_ratios=[0.5, 1.0, 2.0],anchor_strides=[4, 8, 16, 32, 64],anchor_base_sizes=None,......super(AnchorHead, self).__init__()self.num_classes = num_classesself.anchor_scales = anchor_scalesself.anchor_ratios = anchor_ratiosself.anchor_strides = anchor_stridesself.anchor_base_sizes = list(anchor_strides) if anchor_base_sizes is None else anchor_base_sizesself.anchor_generators = []for anchor_base in self.anchor_base_sizes:self.anchor_generators.append(AnchorGenerator(anchor_base, anchor_scales, anchor_ratios))self.num_anchors = len(self.anchor_ratios) * len(self.anchor_scales)#对于fpn的网络结构,如果各层设置多个self.anchor_scales,参考方案如下:# self.anchor_generators = []# if len(self.anchor_scales)>1:# assert len(self.anchor_base_sizes) == len(self.anchor_scales)# for i, anchor_base in enumerate(self.anchor_base_sizes):# self.anchor_generators.append(# AnchorGenerator(anchor_base,self.anchor_scales[i],anchor_ratios)# )# self.num_anchors = len(self.anchor_ratios) * len(self.anchor_scales[0])# else:# for anchor_base in self.anchor_base_sizes:# self.anchor_generators.append(# AnchorGenerator(anchor_base, anchor_scales, anchor_ratios))# self.num_anchors = len(self.anchor_ratios) * len(self.anchor_scales)
相关参数解释:
#anchor基础尺寸的缩放比例,是控制anchor大小最重要的参数
self.anchor_scales = anchor_scales
#anchor的长宽比例设置
self.anchor_ratios = anchor_ratios
#anchor步长设置【和下采样倍数对应,如果不对应将导致图片部分区域没有anchor或anchor的设置超过图片边缘】
self.anchor_strides = anchor_strides
#anchor基础尺寸,可以设置多个,一般等于各层下采样倍数【anchor_stride】即可,anchor的尺寸可以通过self.anchor_scales进行设置
self.anchor_base_sizes = list(anchor_strides) if anchor_base_sizes is None else anchor_base_sizes
#根据上述参数生成所有的基础anchor【此时没考虑特征图的坐标】
self.anchor_generators = []
for anchor_base in self.anchor_base_sizes:self.anchor_generators.append(AnchorGenerator(anchor_base, anchor_scales, anchor_ratios))
#每个像素点的anchor的数量,网络输出的维度根据该参数计算得到
self.num_anchors = len(self.anchor_ratios) * len(self.anchor_scales)def _init_layers(self):self.conv_cls = nn.Conv2d(self.in_channels,self.num_anchors * self.cls_out_channels, 1)self.conv_reg = nn.Conv2d(self.in_channels, self.num_anchors * 4, 1)
参数设置举例
anchor_scales=[1, 2, 4, 8, 16, 32, 64],
anchor_ratios=[0.33, 0.5, 1.0, 2.0, 3.0],
anchor_strides=[16, ],
anchor_strides严格等于下采样倍数即可
anchor大小的设置通过anchor_scales进行设置
一些极端大小的目标检测效果不佳不一定是anchor设置的原因,可能是没有输出对应特征图的原因
AnchorGenerator
- 根据尺寸、比例生成基础的anchor
class AnchorGenerator(object):
#生成基础的anchor,与特征图无关def __init__(self, base_size, scales, ratios, scale_major=True, ctr=None):self.base_size = base_size #anchor 基础尺寸self.scales = torch.Tensor(scales) #anchor的尺寸self.ratios = torch.Tensor(ratios) #anchor的宽高比self.scale_major = scale_majorself.ctr = ctr #anchor中心点坐标self.base_anchors = self.gen_base_anchors() #生成的基础anchor【total_num,4】@propertydef num_base_anchors(self):return self.base_anchors.size(0)def gen_base_anchors(self):w = self.base_size #anchor 基础宽【16】h = self.base_size #anchor 基础高【16】if self.ctr is None:x_ctr = 0.5 * (w - 1) #anchor 中心点横坐标y_ctr = 0.5 * (h - 1) #anchor 中心点纵坐标else:x_ctr, y_ctr = self.ctrh_ratios = torch.sqrt(self.ratios)#求平方根w_ratios = 1 / h_ratios #保证 h_ratios/w_ratios = self.ratiosif self.scale_major:ws = (w * w_ratios[:, None] * self.scales[None, :]).view(-1)hs = (h * h_ratios[:, None] * self.scales[None, :]).view(-1)else:ws = (w * self.scales[:, None] * w_ratios[None, :]).view(-1)hs = (h * self.scales[:, None] * h_ratios[None, :]).view(-1)
# ws: tensor([ 27.8524, 55.7048, 111.4097, 222.8194, 445.6388, 891.2776,
# 1782.5552, 22.6274, 45.2548, 90.5097, 181.0193, 362.0387,
# 724.0773, 1448.1547, 16.0000, 32.0000, 64.0000, 128.0000,
# 256.0000, 512.0000, 1024.0000, 11.3137, 22.6274, 45.2548,
# 90.5097, 181.0193, 362.0387, 724.0773, 9.2376, 18.4752,
# 36.9504, 73.9008, 147.8017, 295.6033, 591.2067])base_anchors = torch.stack( #以(7.5,7.5)为中心点生成的anchor[x_ctr - 0.5 * (ws - 1), y_ctr - 0.5 * (hs - 1),x_ctr + 0.5 * (ws - 1), y_ctr + 0.5 * (hs - 1)],dim=-1).round()# temp = torch.tensor([[-200.0,-600.0,200.0,600.0][-750.0,-600.0,750.0,600.0]]) #可以考虑单独加其它的anchor# base_anchors = torch.cat((base_anchors,temp),0)# yapf: enablereturn base_anchors
base_anchors:[中心点坐标为7.5,7.5]
tensor([[ -6., 3., 21., 12.], [左上x,左上y,右下x,右下y][ -20., -1., 35., 16.],[ -48., -10., 63., 25.],[-103., -29., 118., 44.],[-215., -66., 230., 81.],.......[ -10., -47., 25., 62.],[ -29., -103., 44., 118.],[ -66., -214., 81., 229.],[-140., -435., 155., 450.],[-288., -879., 303., 894.]])
到这一步为止,生成的anchor与特征图大小、步长无关
中心点坐标为base_size的一半
生成的anchor尺寸与训练分辨率大小对应,并非原图大小
各基础anchor尺寸 = base_size * anchor_ratios * anchor_scales
在以上示例代码中,anchor_ratios = h / w,anchor宽高的计算简单理解如下
hs = h * torch.sqrt(anchor_ratios) * anchor_scales
ws = w * (1 / torch.sqrt(anchor_ratios)) * anchor_scales
b) .生成特征图各位置的anchor,和有效anchor的索引
- loss计算阶段完成
def loss(self,cls_scores,bbox_preds,......img_meta):featmap_sizes = [featmap.size()[-2:] for featmap in cls_scores]anchor_list, valid_flag_list = self.get_anchors(featmap_sizes, img_metas, device=device)......
def get_anchors(self, featmap_sizes, img_metas, device='cuda'):"""Get anchors according to feature map sizes.Args:featmap_sizes (list[tuple]): Multi-level feature map sizes.img_metas (list[dict]): Image meta info.device (torch.device | str): device for returned tensorsReturns:tuple: anchors of each image, valid flags of each image"""num_imgs = len(img_metas)num_levels = len(featmap_sizes)# since feature map sizes of all images are the same, we only compute# anchors for one timemulti_level_anchors = []for i in range(num_levels):#根据基础anchor、特征图大小和步长生成所有anchoranchors = self.anchor_generators[i].grid_anchors(featmap_sizes[i], self.anchor_strides[i], device=device)multi_level_anchors.append(anchors)anchor_list = [multi_level_anchors for _ in range(num_imgs)]
# for each image, we compute valid flags of multi level anchorsvalid_flag_list = []#根据特征图实际大小,生成有效anchor索引【过滤掉一些无效的anchor】for img_id, img_meta in enumerate(img_metas):multi_level_flags = []for i in range(num_levels):#num_levels=1anchor_stride = self.anchor_strides[i]feat_h, feat_w = featmap_sizes[i]h, w, _ = img_meta['pad_shape']#经过resize和pad后的图像大小,非原图尺寸valid_feat_h = min(int(np.ceil(h / anchor_stride)), feat_h)valid_feat_w = min(int(np.ceil(w / anchor_stride)), feat_w)flags = self.anchor_generators[i].valid_flags((feat_h, feat_w), (valid_feat_h, valid_feat_w),device=device)multi_level_flags.append(flags)valid_flag_list.append(multi_level_flags)return anchor_list, valid_flag_list
def grid_anchors(self, featmap_size, stride=16, device='cuda'):base_anchors = self.base_anchors.to(device)feat_h, feat_w = featmap_size #特征图尺寸#shift_x: [0,16,32,48,64...976,992,1008]数量等于特征图的宽【feat_w】;最值等于训练分辨率大小【保证每个位置都有anchor】;如果stride和下采样倍数不对应,此处生成的网格点最值与分辨率大小不对应,出现部分区域没有anchor设置或anchor超出图像区域#shift_y: [0,16,32,48,64...592,608,624]数量等于特征图的宽【feat_h】shift_x = torch.arange(0, feat_w, device=device) * stride#以相应步长为单位,生成对应到训练分辨率大小的横坐标shift_y = torch.arange(0, feat_h, device=device) * strideshift_xx, shift_yy = self._meshgrid(shift_x, shift_y) #将横纵坐标重复shifts = torch.stack([shift_xx, shift_yy, shift_xx, shift_yy], dim=-1)
#生成所#有坐标点(w*h,4)[x,y,x,y]【对应到训练分辨率】
#此处的x y即为网络训练分辨率上的像素点坐标,基础anchor坐标【可以理解为偏移量】加上各像素点坐标,得到每个像素点的anchor坐标
#tensor([[ 0, 0, 0, 0],
# [ 16, 0, 16, 0],
# [ 32, 0, 32, 0],
# ...,
# [1024, 656, 1024, 656],
# [1040, 656, 1040, 656]], device='cuda:0')shifts = shifts.type_as(base_anchors)all_anchors = base_anchors[None, :, :] + shifts[:, None, :]#生成所有的anchor [1, 35, 4] + [2232, 1, 4] = [2232,35,4] 广播机制# 基础anchor[偏移量] + 各像素点坐标[x,y,x,y]all_anchors = all_anchors.view(-1, 4)return all_anchors
注意:生成的anchor并不是对应到相应像素点的,而是对应到两个像素点的中心点【因为基础anchor的中心点并不是原点】。如像素点(0,0)对应生成的anchor中心点为(7.5,7.5),往后像素点依此类推。
目标检测 --- Anchor的生成相关推荐
- 目标检测Anchor的What/Where/When/Why/How
编译|yanwan,https://zhuanlan.zhihu.com/p/150332784 来源|https://www.wovenware.com/blog/2020/06/anchor-bo ...
- 科普:目标检测Anchor是什么?怎么科学设置?[附代码]
文章来源于AIZOO,作者元峰 在基于anchor的目标检测网络(Faster RCNN.SSD.YOLO v2&v3等)中,一个至关重要的步骤就是科学的设置anchor,可以说,Anchor ...
- 五问目标检测Anchor
点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 来自 | 知乎 作者 | yanwan 链接 | https:/ ...
- 目标检测_目标检测 | Anchor free的目标检测进阶版本
今天说的是<Soft Anchor-Point Object Detection>,其也是最近关于anchor free的目标检测的论文,作者来自于CMU,一作同样也是FSAF(2019 ...
- 目标检测 | Anchor free之CenterNet深度解析
点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 1 前言 本文接着上一讲对CornerNet的网络结构和损失函数的 ...
- anchor free 目标检测_《目标检测》系列之二:目标检测中的Anchor机制回顾
前段时间,YOLOv4&v5大火,很多人忽视了yolov5在anchor上的一些细节变化,因此,本文从Faster RCNN着手,逐步分析SSD.YOLOv4&v5的anchor机制. ...
- 高效!Anchor DETR:旷视提出一种基于Transformer的目标检测神器!
点上方计算机视觉联盟获取更多干货 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:Sophia知乎 https://zhuanlan.zhihu.com/p/412738375 985人工智能 ...
- 目标检测:Anchor【就是在图像上预设好的不同大小,不同长宽比的参照框】
anchor到底是什么呢?如果我们用一句话概括--就是在图像上预设好的不同大小,不同长宽比的参照框.(其实非常类似于上面的滑窗法所设置的窗口大小) 下图来自<动手学深度学习>中的例子,假设 ...
- 遥感图像目标检测研究综述
遥感图像目标检测 遥感图像特殊性 一.目标检测研究综述 1.介绍 2.传统目标检测 3.基于深度学习目标检测 R-CNN系列为代表的两阶段算法 YOLO.SSD为代表的一阶段算法 二.多尺度目标检测研 ...
最新文章
- 《ASP.NET MVC4 WEB编程》学习笔记------Web API 续
- python心得体会300字_有没有简单一点的 Python 小例子或小项目?
- 软件项目管理0824:招标前客户需要准备的资料
- 将C4C Service Request中的summary和其他附件同步到ERP的Billing Request去
- socket网络编程——多进程、多线程处理并发
- PL/SQL: Stop Making the Same Performance Mistakes
- 电话号码的字母组合Python解法
- Execution in the Kingdom of Nouns (名词王国中的死刑)
- 记号(notation)的学习
- [剑指Offer] 36.两个链表的第一个公共结点
- android 改变音乐格式,音乐速度变更器app-音乐速度变更器下载v9.4.4-hu安卓版-西西软件下载...
- ubuntu修改dns服务器,配置Ubuntu DNS服务器
- 设置QQ空间评论回复权限,包括日志、相册、说说、留言板的评论回复和留言权限,限制名单成员无评论回复权限
- weak_auth 小宁写了一个登陆验证页面,随手就设了一个密码。
- 360系统急救箱用在服务器上,360系统急救箱打开失败的处理操作
- 进程间通信(IPC (Inter-process communication))
- 阜和SAP FICO模块课程
- matlab水下机器人,水下机器人路径控制与仿真
- 超赞!每个设计师都应该了解的IOS编年史
- Python搭建开发环境