SSD论文总结

SSD论文总结

目录

一、one-stage 检测器和two-stage检测器

SSD属于one-stage的物体检测器

1) ont-stage 检测器
  • 主要以YOLO和SSD为代表,这种one-stage的检测主要是对图片不同位置进行采样预测,利用卷积层输出的相对于原图相对位置的特征,直接预测对象类别和对象位置信息。
  • 如YOLO,最后输出相对于原图的7x7的网格,也就是对图中的49个位置进行均匀采样预测,如使用anchor技术,对同一位置进行不同长宽比例的预测。而SSD则对多个分辨率的fmaps进行密集的均匀采样预测。
  • 我们可以发现,这种均匀采样存在一定缺陷:导致正负例的比例不均衡,均匀采样中大部分对应着背景图。这会导致模型精度不高。论文Focal Loss就是一种从损失方面针对这种问题进行优化的方法。而OHEM技术也对这种正负不均衡问题的一种优化技术。
2) two-stage 检测器

主要以R-CNN系列算法,主要是通过启发式方法Selective search或者RPN产生较为准确的候选框,然后再对这些候选框进行分类与回归。有利用多级方式,则预测精度更加准确。因而RefineDet 论文就是利用两个SSD级联,一个相当于RPN对anchor修正,第二个SSD对第一个的修正anchor后的输出进行预测,取得更好的结果。

二、SSD与YOLOv1

  • SSD用CNN来直接进行检测,而YOLOv1使用全连接进行检测;
  • SSD将背景background当做一个类别来预测(对于20类的VOC,则实际预测21类),而YOLO只对对象类别进行预测(实际预测为20类)
  • SSD利用了多层不同分辨率的特征图进行预测输出,而且对大尺度的图进行小物体检测,小尺度的图进行大物体检测;从而更有利于多scale的物体的检测
  • SSD采用了Faster rcnn中的anchor技术,利用不同长宽比先验框进行对象检测;而YOLOv1没有用anchors技术。
  • SSD的这几个改进,一定程度上克服了YOLOv1**难以检测小目标定位不准**等不足。

三、网络结构中的一些tricks

1)SSD的结构示意图

SSD示意图
可以看出,后面几层用于对象预测(类别和位置的预测)

2) L2Norm的使用

该技术来自于ParseNet,conv4_3作为第一个输出预测的特征图,其大小为38x38,该层比较靠前,norm较大,因而使用L2Norm对特征图进行归一化,保证其与后面高语义层的差异不是很大。
- 注意L2Norm与BatchNorm(BN)的区别,BN是在batch_size,width,height三个维度上进行归一化,;而L2Norm仅仅在channel每个像素的维度上进行归一化,归一化后一般设置一个可训练的放缩变量gamma。

pytorch代码
class L2Norm2d(nn.Module):
    '''L2Norm layer across all channels'''
    def __init__(self,scale):  # scale是参数初始化的值,代码中设置为20
        super(L2Norm2d, self).__init__()
        self.scale = Parameter(torch.Tensor([scale]))  # self.scale是可学习的
    '''
    因为conv4_3层比较靠前,而且norm较大所以加一个L2Norm使其与后面层差别不大
    不同于BN,这是在通道维度上进行Norm (spatial normalization)
    '''
    def forward(self,x,dim=1):
        '''out = scale * x / sqrt(\sum x_i^2)'''
        return self.scale[0] * x * x.pow(2).sum(dim).unsqueeze(1).clamp(min=1e-12).rsqrt().expand_as(x)
3) dilation的使用

这个技术来自于DeepLab-LargeFOV,这个下采样操作是代替原来网络的pool5层,这样能速度会慢与使用这种操作的20%。
下图为不同dilation rate的设置
(a)是普通的 3\times3 卷积,其视野就是 3×3 3 × 3 ,(b)是扩张率为1,此时视野变成 7×7 7 × 7 ,(c)扩张率为3时,视野扩大为 15×15 15 × 15 ,但是视野的特征更稀疏了。Conv6采用 3×3 3 × 3 大小但dilation rate=6的扩展卷积。
ditaltion conv
该图片来自于https://www.zhihu.com/people/xiaohuzc/posts?page=1 博文

4) 不同大小的fmaps对应的anchor_sizes设计

SSD中conv4_3, Conv7,Conv8_2,Conv9_2,Conv10_2,Conv11_2共6个卷积层用作预测输出,它们的大小分别是38,19,19,5,3,1。针对不同大小的fmaps,使用不同数目的先验框以及不同大小比例的先验框;除去conv4_3, 其他5层的anchor_size的计算公式如下:
sk=smin+smaxsminm1(k1),k[1,m] s k = s m i n + s m a x − s m i n m − 1 ( k − 1 ) , k ∈ [ 1 , m ]

  • 其中 m=5, smin=2,smax=0.9 s m i n = 2 , s m a x = 0.9 , 然后每层的anchor_size乘以对应层的锚长宽比anchor_ratio,即可得到每层的anchor数目。anchor_ratio = {1,2,3,1/2,1/3};
  • 注意一些细节,每层anchor的计算并不统一;其中ratio的数目设置为[4,6,6,6,4,4],4表示只有两种比例,而6表示使用所有的长宽比;也就是只对Conv7,Conv8_2,Conv9_2使用所有的长宽比,其他的层只使用两个比例。最终所有层的anchor_sizes={30,60,111,162,213,264,315}, 对于conv4_3, sk=smin/2 s k = s m i n / 2 ,由于计算ratio=1时,需要k+1的 sk s k ,所以conv11_2的后一个 sk=300×105/100=315 s k = 300 × 105 / 100 = 315
  • 另外,对于ratio=1的情况,对应两种anchor, { sk,sk s k , s k }和{ sksk+1,sksk+1 s k s k + 1 , s k s k + 1 }。
  • 所以SSD300一共预测
    38×38×4+19×19×6+10×10×6+5×5×6+3×3×4+1×1×4=8732 38 × 38 × 4 + 19 × 19 × 6 + 10 × 10 × 6 + 5 × 5 × 6 + 3 × 3 × 4 + 1 × 1 × 4 = 8732

四、训练过程中一些tricks

1) hard example mining

由于SSD均匀采样,所以产生的正负例极其不平衡;此外,每个groundtruth至少与一个先验框anchor匹配,注意一个GT可以与多个先验框匹配,且匹配为正例的阈值为iou=0.5。但是这样正例相对于负例可能还是很少,所以为了尽量平衡,则采用OHEM技术,对负样本抽样时,按照预测出类别的执行度误差,从大到小排列,取误差大的topN个负样本作为负例。保证正负样本比例为1:3。具体代码如下

    def hard_negative_mining(self, cls_loss, pos):
        '''
        :param cls_loss: (N*num_anc,) 经过cross_entropy_loss计算损失
        :param pos: (N,num_anc,) 只有0,1值,
        :return: neg indices, (N,num_anc)
        '''
        N,num_anc = pos.size()

        cls_loss[pos.view(-1)] = 0  # set pos = 0将正例损失赋为0,不考虑正例
        cls_loss = cls_loss.view(N,-1) # (N,num_anc)

        # 注意这个地方有个编程技巧,能用索引的方式,求出topN的位置
        # 先逆序,然后在对索引值进行正序,得到的二级索引值在小于N的位置就是topN
        _, idx = cls_loss.sort(1,descending=True)  # sort by neg
        _, rank = idx.sort(1)  # (N,num_anc)

        num_pos = pos.long().sum(1)  # (N,1)
        num_neg = torch.clamp(3*num_pos,max=num_anc-1)  #(N,1) 正例样本的3倍不得超过总anc数

        # print('neg size:',num_neg.size(),rank.size())
        neg = rank < num_neg.unsqueeze(1).expand_as(rank) # (N,num_anc_8732)

        return neg # 只有0,1值
2) 数据增强

论文中的实验表明,数据增强对预测精度有很大的提升
主要采用水平旋转操作,随机采集块区域(获取小目标训练样本),还有随机裁剪加颜色扭曲(代码中未实现)。

3)损失计算

L(x,c,l,g)=1N(Lconf(x,c)+αLloc(x,l,g) L ( x , c , l , g ) = 1 N ( L c o n f ( x , c ) + α L l o c ( x , l , g )
其中N为正样本个数

  • 位置损失计算: Lloc(x,l,g)=NiPosmcx,cy,w,hxkijsmoothL1(lmigmj) L l o c ( x , l , g ) = ∑ i ∈ P o s N ∑ m ∈ c x , c y , w , h x i j k s m o o t h L 1 ( l i m − g j m ) 这是采用Fast RCNN的位置计算方法;此处的trick有,训练时对cx,cy,w,h进行缩放,添加一个scales因子,加速训练。
  • 类别损失计算:
    Lconf(x,c)=NiPosxpijlog(Cpi)iNeglog(Coi)whereCpi=exp(cpi)pexp(cpi) L c o n f ( x , c ) = − ∑ i ∈ P o s N x i j p l o g ( C i p ) − ∑ i ∈ N e g l o g ( C i o ) w h e r e C i p = e x p ( c i p ) ∑ p e x p ( c i p )
  • 权重系数 α α 通过交叉验证设置为1.

五、总结

1)有些收获
  • 在进行框预测时,要将box的值映射到(0,1)之间,这样在对不同的fmaps,进行逆转时,比较方便。
  • 多尺度特征图,或者特征融合方式,更有利于识别出大小不一的物体
  • 先验框的设置有利于物体检测,可以探究一下为什么,关于四个位置信息的计算方式(Fast RCNN方式)能否有更好的通用的方式。
2) 思想启发
  • 根据SSD中的思想,能否根据物体大小(划分为一定梯度),然后不同大小物体选取的fmaps来源不同。

六 待补充

1)SSD 512的设计细节
2)SSD的一系列变形网络设计

参考文献

1.知乎博客: https://www.zhihu.com/people/xiaohuzc/posts?page=1
2. github SSD源码: https://github.com/kuangliu/pytorch-ssd
3. Wei Liu, et al. “SSD: Single Shot MultiBox Detector.” ECCV2016.


  • 8
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值