SSD的anchor_box计算

本文深入解析SSD算法中Anchor Box的计算原理,详细介绍了如何基于特征层尺寸、长宽比及尺寸界限等参数生成不同比例的边界框,阐述了SSD如何通过多尺度特征检测不同大小的目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

看过SSD的tensorflow实现的小伙伴一定对anchor_box的计算很是好奇, 网上也是五花八门的解释,今天我结合源码和原理来解释一下.

default_params = SSDParams(
        img_shape=(300, 300),
        num_classes=21,
        no_annotation_label=21,
        feat_layers=['block4', 'block7', 'block8', 'block9', 'block10', 'block11'],
        feat_shapes=[(38, 38), (19, 19), (10, 10), (5, 5), (3, 3), (1, 1)],
        anchor_size_bounds=[0.15, 0.90],
        # anchor_size_bounds=[0.20, 0.90],
        anchor_sizes=[(21., 45.),
                      (45., 99.),
                      (99., 153.),
                      (153., 207.),
                      (207., 261.),
                      (261., 315.)],
        # anchor_sizes=[(30., 60.),
        #               (60., 111.),
        #               (111., 162.),
        #               (162., 213.),
        #               (213., 264.),
        #               (264., 315.)],
        anchor_ratios=[[2, .5],
                       [2, .5, 3, 1./3],
                       [2, .5, 3, 1./3],
                       [2, .5, 3, 1./3],
                       [2, .5],
                       [2, .5]],
        anchor_steps=[8, 16, 32, 64, 100, 300],
        anchor_offset=0.5,
        normalizations=[20, -1, -1, -1, -1, -1],
        prior_scaling=[0.1, 0.1, 0.2, 0.2]
        )

这个anchor_box的计算与anchor_sizes和anchor_ratios有关.
先解释一下anchor_box的由来. 我们假设当前层是block4, 那么我们的feat_shape就是(38, 38),
你可以将其理解为38*38个cell单元, 每个单元要预测出来几个anchor_box, 不同的层, 这个数理论上讲都是6个, (paper上就是这么写的). 每个box的长宽比是有ratios决定的, paper上是两个 1 , 以及4个其他的值. 但是作者的源码却很调皮的改了一下.
看一下我们的长宽比,这里面没有那两个1, 因为他们是单独设定的:

anchor_ratios=[[2, .5],
               [2, .5, 3, 1./3],
               [2, .5, 3, 1./3],
               [2, .5, 3, 1./3],
               [2, .5],
               [2, .5]],

我们看到第一层还有最后两层, 只有两种长宽比, 所以这三层就只有4种box.
在这里插入图片描述
这个图可以说介绍的相当准确定了, 网上有错的, 以这个为准 . 以block4层为例, 他每个cell单元只有4个box, 包括一大一小两个正方形, 以及两个长方形.
对于小正方形,其边长为min_size, 这个min_size是什么呢?就是前面参数中的anchor_sizes:

anchor_sizes=[(30., 60.),
   			(60., 111.),
   			(111., 162.),
   			(162., 213.),
   			(213., 264.),
   			(264., 315.)],

其中每一行为一组, 每一行对应相应的特征层, 第一行对应的就是block4, 依次类推, 对于(30, 60), 30就是min_size, 60就是max_size.
大正方形其边长为在这里插入图片描述
然后是另外两个长方形,这个时候anchor_ratios就出马了,长方形的长宽是有公式可寻的.
在这里插入图片描述
这个ratio就是anchor_ratios里的2, 5, 3, 1/3 之类的.
这样,原理上box的大小就介绍完了.但是别忘了这个尺寸是在原图上的尺寸, 我们需要这个尺寸相对于原图的比例.
看下源码的这一部分:

	# Add first anchor boxes with ratio=1.
	# sizes就是(30, 60), img_shape就是原图尺寸(300, 300)
    h[0] = sizes[0] / img_shape[0]
    w[0] = sizes[0] / img_shape[1]
    
    di = 1
    if len(sizes) > 1:
        h[1] = math.sqrt(sizes[0] * sizes[1]) / img_shape[0]
        w[1] = math.sqrt(sizes[0] * sizes[1]) / img_shape[1]
        di += 1
    # r 就是[2, 5, 3, 1/3]    
    for i, r in enumerate(ratios):
        h[i+di] = sizes[0] / img_shape[0] / math.sqrt(r)
        w[i+di] = sizes[0] / img_shape[1] * math.sqrt(r)

最后, 既然我们高明白了anchor_size, 这个参数直接决定了当前特征层的box 的大小, 可以看出越靠近输入层, box越小, 越靠近输出层, box越大, 所以 SSD的底层用于检测小目标, 高层用于检测大目标.

### SSD Anchor-Free 目标检测实现方法 SSD(Single Shot MultiBox Detector)是一种经典的 one-stage 目标检测算法,最初设计为 anchor-based 的框架。然而,为了提升灵活性并减少对预定义 anchor 的依赖,可以将其扩展至 anchor-free 形式。 #### 1. **核心思想** 在传统的 SSD 中,anchor 是预先设定好的一组矩形框,用于匹配真实目标边界框,并预测其偏移量和类别概率。而在 anchor-free 版本中,则不再依赖这些预定义的 anchors,而是直接在网络输出的空间位置上预测目标的中心点及其宽度和高度[^4]。这种转换使得模型能够更加灵活地适应各种尺寸和比例的目标。 #### 2. **网络结构调整** 要将 SSD 转变为 anchor-free 模型,需做出如下改动: - **取消 Anchors**: 去掉原有的 multi-scale feature maps 上设置的不同 aspect ratios 和 scales 的 default boxes (anchors),改为仅关注每个像素点作为潜在对象中心的可能性。 - **增加额外分支**: - 对于每一个可能的对象中心位置, 新增两个任务——即除了分类之外还需要估计该处是否有物体存在以及如果有的话具体有多大. 以下是简化版伪代码表示如何修改原生ssd架构: ```python class AnchorFreeSSD(nn.Module): def __init__(self,...): super(AnchorFreeSSD,self).__init__() self.backbone = BackboneNetwork() # e.g., VGG or ResNet num_classes = ... out_channels = ... self.class_pred_conv = nn.Conv2d(out_channels,num_classes,kernel_size=3,padding=1) self.reg_pred_conv = nn.Conv2d(out_channels,4,kernel_size=3,padding=1) def forward(self,x): features = self.backbone(x) cls_preds,bbox_preds=[],[] for feat in features: cls_score=self.class_pred_conv(feat).permute(0,2,3,1).contiguous().view(N,-1,C) bbox_reg=self.reg_pred_conv(feat).permute(0,2,3,1).contiguous().view(N,-1,4) cls_preds.append(cls_score) bbox_preds.append(bbox_reg) return torch.cat(cls_preds,dim=1),torch.cat(bbox_preds,dim=1) ``` 此部分展示了如何去构建一个基础版本的无定单次探测器(SSD)[^1]. #### 3. **损失函数的设计** 由于没有了默认框(anchor box),因此需要重新定义适合新情况下的loss function。一般采用以下几种组合形式之一或者它们之间的变体: - Focal Loss: 针对抗不平衡问题特别有效的一种改进型交叉熵损失函数,尤其适用于极端正负样本比率的情况 [^5]. - Smooth L1 Loss: 应用于回归子项计算预测坐标与实际坐标的差异度量. 最终整体Loss Function可表述如下: \[ \text{Total Loss} = \lambda_{cls}\cdot\text{Classification Loss}+\lambda_{reg}\cdot\text{Regression Loss}, \] 其中参数λ_cls和λ_reg用来平衡两类误差的重要性程度[^2]. #### 4. **训练策略优化建议** 考虑到去掉了先验知识带来的便利条件之后可能会面临更多挑战比如收敛困难等问题,这里给出几点改进建议供参考考虑: - 数据增强(Data Augmentation): 更加充分多样化的输入变换有助于改善泛化性能; - 学习率调度(Learning Rate Schedule): 动态调整lr曲线可以帮助平稳度过初期不稳定阶段直至稳定状态达成最优解路径探索过程完成为止; - Hard Negative Mining(HNM): 自动筛选最难分错案例参与反向传播更新操作从而加快整个流程效率同时保证质量不受影响; 以上措施均能在一定程度范围内缓解因改变原有机制而导致的新难题出现几率增大现象的发生频率降低效果明显可见成效显著值得尝试应用实践验证价值非凡不可忽视忽略不得务必重视高度重视才行啊亲们!!! --- ###
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值