SSD

SSD算法优点:

①比Faster-RCNN块。
②多尺度,不同的特征图上进行预测,类似于金字塔。
③端对端,可多分类,对分辨率比较小的图片,分类也很准确。

网络结构:

由SSD网络结构可以看出,SSD使用了6个不同特征图检测不同尺度的目标。低层预测小目标,高层预测大目标。

整个网络为全卷积网络结构,骨干网使用VGG16网络。SSD将骨干网中的fc6改为33卷积层,fc7改为11卷积层,池化层pool5由原来的stride=2的22变为stride=1的33。为了不改变特征图的大小,同时获得更大的感受野,Conv6为空洞卷积,dilation=6。在骨干网之后增加了8个卷积层。

网络中共有6个卷积层(conv4_3,conv7,conv8_2,conv9_2,conv10_2,conv11_2)的特征图被用来进行检测,6个特征图分别预测不同大小和长宽比的边界框。

SSD为每个检测层都预定了不同大小的先验框(Prior boxes),Conv4_3,Conv10_2和Conv11_2分别有4种先验框,而Conv7、Conv8_2和Conv9_2分别有6种先验框,即对应于特征图上的每个像素,都会生成K(prior box种类)个prior box。prior box类似于Faster rcnn中的anchor。

网络6个检测层总共预测的边界框数目为8732(38 * 38 * 4 + 19 * 19 * 6 + 10 * 10 * 6 + 5 * 5 * 6 + 3 * 3 * 4 + 1 * 1 * 4)。

下图详细的展示了SSD的每个模块,整体上SSD网络可以分为backbone,extras,和head模块。head模块包含了detector(用于定位)和classifier(用于分类)。

image.png

Detector和Classfier对每个特征图使用不同的3 * 3卷积核进行预测,卷积核的数目由每个特征图上定义的priors box种类决定。比如Conv4_3输出的特征图,定义了4种prior box,那么Detector得到的特征图通道数为4 * 4,Classifier得到的特征图通道数为4 * 21(voc类别数,包含背景)。

Detector输出每个prior box的坐标偏移,Classifier输出每个类的类别概率得分。

网络输入大小为300 * 300,数据集使用Voc数据集(20个类别)。

网络训练

在训练过程中,首先要确定训练图片中的 ground truth与哪个先验框来进行匹配,与之匹配的先验框所对应的边界框将负责预测它。

SSD的先验框与ground truth的匹配是任两框匹配,按准确度说话,原则有2点:

①对于图片中每个ground truth,找到与其 IOU 最大的先验框,该先验框与其匹配,这样,可以保证每个ground truth 一定与某个先验框匹配。通常称与ground truth匹配的先验框为正样本,反之,若一个先验框没有与任何 ground truth 进行匹配,那么该先验框只能与背景匹配,就是负样本。一个图片中ground truth是非常少的, 而先验框却很多,如果仅按第一个原则匹配,很多先验框会是负样本,正负样本极其不平衡,所以需要第二个原则。
②对于剩余的未匹配先验框,若某个ground truth的IOU大于某个阈值(一般为0.5),那么该先验框也与这个ground truth 进行匹配。这意味着某个ground truth可能与多个先验框匹配,这是可以的。但是反过来不可以,因为一个先验框只能匹配一个ground truth。如果多个ground truth 与某个先验框IOU大于阈值,那么先验框只与 IOU 最大的那个先验框进行匹配。第二个原则一定在第一个原则之后进行。

即便每个真实框可与多个先验框同时匹配,但背景先验框的数量还是要明显大于物体先验框的数量。因此,论文中还使用了Hard negative mining的策略,按照先验框的类别置信度误差从高到低排序,只选择前top_k个先验框作为训练的背景先验框(背景先验框的采样),最终正负样本的比例约为1:3。

损失函数

SSD的损失函数为多任务损失函数,包含了定位损失和分类损失。如下图所示,N表示匹配的先验框的数目,α为权重项,平衡分类和定位损失,通过交叉验证设为1。


其他技巧

L2 Norm 层

Conv4_3为第一个用于检测的特征图,由于该特征图的norm较大,因此在Conv4_3之后增加了一个L2_Norm层,将特征图上的每个位置的特征norm缩放到20,并在反向传播过程中学习该缩放参数。以此来保证与之后的特征图不会有太大的差异。
L2 Norm与BatchNorm不同,BatchNorm是在(channel,width,height)3个维度上进行normalization,而L2 Norm只在channel维度上进行Normalization。

class L2Norm(nn.Module):
    """
    unlike batchnorm normalize in width, height and channel 3 dimension, 
    l2norm just normalize in channel dimension

    Params:
        channels: channels of input feature map
        scales: initial scale param, it will be learned by gradient descent

    """
    def __init__(self, channels, scales):
        
        super(L2Norm, self).__init__()

        self.channels = channels
        # gamma is parameter which net will learn
        self.gamma = scales or None

        self.eps = 1e-10

        # normalization in channel dimension
        self.weights = nn.Parameter(t.Tensor(self.channels))

        nn.init.constant_(self.weights, self.gamma)

    def forward(self, x):
        norm = x.pow(2).sum(dim=1, keepdim=True).sqrt() + self.eps
        x = t.div(x, norm)
        out = self.weights.view(1, -1, 1, 1).expand_as(x) * x
        return out

你可能感兴趣的:(SSD)