【SSD论文解读】 模型部分

  • 一、骨干网络
    • 1、原始的骨干网络——VGG16
    • 2、SSD对VGG16的改进
    • 3、代码
  • 二、Extra Feature Layers
    • 1、使用多尺度的特征图进行检测
      • 代码
    • 2、使用卷积预测器产生预测边界框(相比于YOLO的全连接层)
      • 代码
    • 3、每个特征图生成一组固定的预测边界框
      • 代码
  • 三、SSD网络结构
    • 代码

一、骨干网络

1、原始的骨干网络——VGG16

VGGNet是继AlexNet后的一个隐含层更多的深度卷积神经网络。VGGNet结构根据层数的不同有不同的版本,常用结构是VGG16和VGG19。SSD使用的是VGG16。

VGG16有13个卷积层,5个最大池化层以及3个全连接层

  • 卷积层卷积核的大小为3×3,步长为1,通过卷积层可以实现通道数的增加
  • 池化层大小为2×2,步长为2,作用是降低特征图尺寸并能提高网络抗干扰能力
  • 3个全连接层中的前两层通道数为4096,第三层通道数为1000,代表1000个标签类别

所有隐藏层后都带有ReLU非线性激活函数。VGG16网络结构图如下图:

VGG16网络结构图

2、SSD对VGG16的改进

【论文内容】

  • 为了能够与在骨干网络之后增加特征提取层,将全连接层fc6和fc7转换为卷积层conv6和conv7,并对fc6和fc7的参数进行二次采样,并移除了fc8层
  • 将池化层pool5从2×2大小,步长为2更改为3×3大小,步长为1,并使用atrous算法来填充“漏洞”;
  • 由于SSD网络结构移除了VGG16的全连接层,因此防止过拟合的dropout层也被移除
  • 由于conv4_3与其他特征层相比具有不同的特征比例,因此使用L2归一化将特征图中每个位置的特征比例进行缩放,并在反向传播过程中学习该比例。

L1 norm、L2 norm:
L1 norm是绝对值相加,又称曼哈顿距离
L2 norm是平方和,即欧几里德距离之和
L1归一化和L2归一化范数的详解和区别


每一层详细的更改,如图:来源【SSD算法】史上最全代码解析-核心篇

3、代码

#数字代表卷积层的通道数,'M'代表普通池化层,'C'代表池化层但ceil_mode=True
cfg= {'300': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'C', 512, 512, 512, 'M',512, 512, 512],'512': [],
}
# vgg网络初始通道数为“原图像通道数”:3
i = 3def vgg(cfg, i, batch_norm=False):layers = []in_channels = ifor v in cfg:if v == 'M':layers += [nn.MaxPool2d(kernel_size=2, stride=2)]elif v == 'C':layers += [nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)]else:conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)if batch_norm:layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)]else:layers += [conv2d, nn.ReLU(inplace=True)]in_channels = vpool5 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)conv6 = nn.Conv2d(512, 1024, kernel_size=3, padding=6, dilation=6)conv7 = nn.Conv2d(1024, 1024, kernel_size=1)layers += [pool5, conv6,nn.ReLU(inplace=True), conv7, nn.ReLU(inplace=True)]return layers

输出骨干网的网络结构,如下所示:

Sequential((0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(1): ReLU(inplace)(2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU(inplace)(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(6): ReLU(inplace)(7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(8): ReLU(inplace)(9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(11): ReLU(inplace)(12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(13): ReLU(inplace)(14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(15): ReLU(inplace)(16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=True)(17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(18): ReLU(inplace)(19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(20): ReLU(inplace)(21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(22): ReLU(inplace)(23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(25): ReLU(inplace)(26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(27): ReLU(inplace)(28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(29): ReLU(inplace)(30): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)(31): Conv2d(512, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(6, 6), dilation=(6, 6))(32): ReLU(inplace)(33): Conv2d(1024, 1024, kernel_size=(1, 1), stride=(1, 1))(34): ReLU(inplace)
)

二、Extra Feature Layers

相比于YOLO和Faster-RCNN,SSD网络结构也提出了一些新的策略

  • 使用多尺度的特征图进行检测
  • 使用卷积预测器产生预测边界框
  • 每个特征图生成一组固定的预测边界框

1、使用多尺度的特征图进行检测

【论文内容】

SSD算法在截断后的VGG16之后,增加了大小逐层减小的卷积层进行特征提取,然后在不同大小的特征图上进行检测,从而允许在多个尺度上进行检测。

因为不同大小的特征图感受野不同,因此可以检测不同大小的物体:

  • 较大的特征图,感受野较小,适合检测相对较小的物体。如下图中,8×8的特征图中蓝色框更适合检测猫
  • 较小的特征图,感受野较大,适合检测相对较大的物体。如下图中,4×4的特征图中红色框更适合检测狗。

图片的真实值(左),8×8特征图(中),4×4特征图(右)

代码
#数字表示卷积层的通道数,'S'表示采用stride=2, padding=1的池化层
extras = {'300': [256, 'S', 512, 128, 'S', 256, 128, 256, 128, 256],'512': [],
}
# Extra Feature Layers 的输入通道数,为vgg网络的输出通道数,即conv7的输出通道数:1024
i = 1024def add_extras(cfg, i, batch_norm=False):# Extra layers added to VGG for feature scalinglayers = []in_channels = iflag = Falsefor k, v in enumerate(cfg):if in_channels != 'S':if v == 'S':layers += [nn.Conv2d(in_channels, cfg[k + 1],kernel_size=(1, 3)[flag], stride=2, padding=1)]else:layers += [nn.Conv2d(in_channels, v, kernel_size=(1, 3)[flag])]flag = not flagin_channels = vreturn layers

输出:

Sequential((0): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1))(1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))(2): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1))(3): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))(4): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1))(5): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1))(6): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1))(7): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1))
)

2、使用卷积预测器产生预测边界框(相比于YOLO的全连接层)

【论文内容】

YOLO中使用全连接层来进行分类和回归,而SSD将其改为了卷积层。SSD并不是对所有的卷积层都使用 “卷积预测器”,而是选择了其中的6层(conv4_3、conv7、conv8_2、conv9_2、conv10_2、conv11_2)进行特征提取。

对于 m×n×pm×n×pm×n×p 的特征图,用 2个 3×3×p3×3×p3×3×p 的卷积核分别进行卷积:

  • 一个输出分类用的置信度损失(confidence loss),每个默认边界框生成21个类别置信度损失
    代码中主要使用 Pascal VOC 数据集进行训练、验证、测试。有20种分类;另外还有1种分类,为背景;所以总的类别数为21。
  • 一个输出回归用的定位损失(localization loss),每个默认边界框生成4个坐标值(x,y,w,h)(x,y,w,h)(x,y,w,h)。
代码
# 函数调用:
multibox(vgg(base[str(size)], 3),add_extras(extras[str(size)], 1024),mbox[str(size)], num_classes)# 卷积层 conv4_3、conv7、conv8_2、conv9_2、conv10_2、conv11_2 每层每个 cell 生成 default boxes 的个数依次为:
mbox = {'300': [4, 6, 6, 6, 4, 4],  # number of boxes per feature map location'512': [],
}# SSD300,原图像大小为 300×300
size=300
num_classes=21def multibox(vgg, extra_layers, cfg, num_classes):loc_layers = []conf_layers = []# 骨干网vgg16共有34个元素(每个conv层后面都有一个relu)# 所以第21、-2个元素分别为:可以参考“一、骨干网络 3、代码”的输出# (21): Conv2d(512, 512, kernel_ size=(3, 3),stride=(1, 1),padding=(1, 1))# (-2)即(33): Conv2d(1024, 1024,kernel_ size=(1, 1), stride=(1, 1))vgg_source = [21, -2]for k, v in enumerate(vgg_source):loc_layers += [nn.Conv2d(vgg[v].out_channels,cfg[k] * 4, kernel_size=3, padding=1)]conf_layers += [nn.Conv2d(vgg[v].out_channels,cfg[k] * num_classes, kernel_size=3, padding=1)]for k, v in enumerate(extra_layers[1::2], 2):loc_layers += [nn.Conv2d(v.out_channels, cfg[k]* 4, kernel_size=3, padding=1)]conf_layers += [nn.Conv2d(v.out_channels, cfg[k]* num_classes, kernel_size=3, padding=1)]return vgg, extra_layers, (loc_layers, conf_layers)

3、每个特征图生成一组固定的预测边界框

【论文内容】


SSD 对多尺度特征图中的 每个 cellcellcell 产生固定数量的 default bounding boxes:

  • 每个特征图生成 default boxes 的个数:m×n×km×n×km×n×k,总数量为8732个
  • 每个 default box 的输出个数:有 21个分类+4个坐标21个分类 + 4个坐标21个分类+4个坐标 ,共25个输出

其中,m×nm×nm×n:特征图大小;kkk :每个特征图产生 default box 的个数,取值如下表所示:(“三、SSD网络结构” 中的结构图,每一条 conv 层与 detections 的连线上标明了 kkk 的取值。如:Classifier : Conv: 3x3x(4x(Classes+4)))
还请路过的小伙伴指教,Classifier : Conv: 3x3x(4x(Classes+4)))中的 3x3 是什么?

每个特征图产生 default bounding boxes 的具体数量如下表所示:

k×m×nk×m×nk×m×n
conv4_3 4×38×38
conv7_2 6×19×19
conv8_2 6×10×10
conv9_2 4×5×5
conv10_2 4×3×3
conv11_2 4×1×1
代码

这部分的代码分两部分实现:

  1. 每个特征图生成 default boxes 的个数:由于这部分涉及到论文中【训练】部分,因此在下一篇文章中介绍具体实现。
  2. 每个 default box 的输出个数:在 ssd.py/multibox()函数中实现
loc_layers += [nn.Conv2d(vgg[v].out_channels, cfg[k] * 4, kernel_size=3, padding=1)]
conf_layers += [nn.Conv2d(vgg[v].out_channels, cfg[k] * num_classes, kernel_size=3, padding=1)]

三、SSD网络结构

输入:300×300×3300×300×3300×300×3
网络结构:如上图
输出:满足条件的目标检测框、目标的label、分数,具体格式为:[image_ id, label, confidence, xmin, ymin, xmax, ymax]


模型详细层结构:
红色方框:骨干网络、Extra Feature Layers层
黄色条形:SSD对VGG16的修改
粉色条形:生成 default box 的层

代码
    def forward(self, x):"""Applies network layers and ops on input image(s) x.Args:x: input image or batch of images. Shape: [batch,3,300,300].Return:Depending on phase:test:Variable(tensor) of output class label predictions,confidence score, and corresponding location predictions foreach object detected. Shape: [batch,topk,7]train:list of concat outputs from:1: confidence layers, Shape: [batch*num_priors,num_classes]2: localization layers, Shape: [batch,num_priors*4]3: priorbox layers, Shape: [2,num_priors*4]"""sources = list()loc = list()conf = list()# apply vgg up to conv4_3 relufor k in range(23):x = self.vgg[k](x)s = self.L2Norm(x)sources.append(s)# apply vgg up to fc7for k in range(23, len(self.vgg)):x = self.vgg[k](x)sources.append(x)# apply extra layers and cache source layer outputsfor k, v in enumerate(self.extras):x = F.relu(v(x), inplace=True)if k % 2 == 1:sources.append(x)# apply multibox head to source layersfor (x, l, c) in zip(sources, self.loc, self.conf):loc.append(l(x).permute(0, 2, 3, 1).contiguous())conf.append(c(x).permute(0, 2, 3, 1).contiguous())loc = torch.cat([o.view(o.size(0), -1) for o in loc], 1)conf = torch.cat([o.view(o.size(0), -1) for o in conf], 1)if self.phase == "test":output = self.detect(loc.view(loc.size(0), -1, 4),                   # loc predsself.softmax(conf.view(conf.size(0), -1,self.num_classes)),                # conf predsself.priors.type(type(x.data))                  # default boxes)else:output = (loc.view(loc.size(0), -1, 4),conf.view(conf.size(0), -1, self.num_classes),self.priors)return output

【SSD论文解读】 模型部分:骨干网络 VGG16 + 特征提取层 Extra Feature Layers相关推荐

  1. 【SSD论文解读】 论文中用到的数据集:Pascal VOC、MS COCO、ImageNet

    [SSD论文解读] 论文中用到的数据集 一.数据集介绍 1.Pascal VOC 2.MS COCO 3.ILSVRC 二.数据集处理函数 1.专门的datasets类 2.论文中的数据集处理函数 三 ...

  2. 阿里AAAI2018论文解读:轻量网络训练框架、GAN中文命名实体识别、英俄翻译等...

    1. 火箭发射:一种有效的轻量网络训练框架<Rocket Launching: A Universal and Efficient Framework for Training Well-per ...

  3. 目标检测算法SSD论文解读

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明. 原文链接:https://blog.csdn.net/jy001227801/article/ ...

  4. 如何替换模型的骨干网络(backbone)

    1.替换骨干网络的原则 为什么一些模型能够把其内部的模块进行替换?理由很简单,就是把里面的模块看作一个黑盒子,黑盒子有着输入和输出,那么作为网络中的一个部分,前面有着输入过来,后面也需要输出到其他模块 ...

  5. NIPS 2018论文解读 | 基于条件对抗网络的领域自适应方法

    在碎片化阅读充斥眼球的时代,越来越少的人会去关注每篇论文背后的探索和思考. 在这个栏目里,你会快速 get 每篇精选论文的亮点和痛点,时刻紧跟 AI 前沿成果. 点击本文底部的「阅读原文」即刻加入社区 ...

  6. 论文解读:深度监督网络(Deeply-Supervised Nets)

    所谓深监督(Deep Supervision),就是在深度神经网络的某些中间隐藏层加了一个辅助的分类器作为一种网络分支来对主干网络进行监督的技巧,用来解决深度神经网络训练梯度消失和收敛速度过慢等问题. ...

  7. 高德KDD2020论文解读|混合时空图卷积网络:更精准的时空预测模型

    导读 时空预测在天气预报.运输规划等领域有着重要的应用价值.交通预测作为一种典型的时空预测问题,具有较高的挑战性.以往的研究中主要利用通行时间这类交通状态特征作为模型输入,很难预测整体的交通状况,本文 ...

  8. 【论文解读】深度学习网络架构新视角:通过相关图表达理解神经网络(何恺明团队新作)...

    文章来源于极市平台,作者Happy 标题&作者团队 导语:恺明大神出品,必属精品.Facebook的研究员从一个新奇的角度对神经网络的表示与设计进行探索,提出了一种新颖的相关图表示方式.它有助 ...

  9. 【mmdetection源码解读(一)】骨干网络--ResNet

    以下仅为个人理解,若有不正之处还请指出,欢迎交流! 本文解读的源码为mmdet/models/backbones中的resnet.py 首先附上ResNet原文地址Deep Residual Lear ...

最新文章

  1. Topcoder SRM 657DIV2
  2. pandas删除数据行中的重复数据行、基于dataframe所有列删除重复行、基于特定数据列或者列的作何删除重复行、删除重复行并保留重复行中的最后一行、pandas删除所有重复行(不进行数据保留)
  3. 整理大型网站架构必知必会的几个服务器知识
  4. __attribute__ 总结
  5. 深蓝学院《从零开始手写VIO》作业七
  6. html实现div打印,如何在html div的中间打印/附加从按钮单击的值?
  7. koa --- 使用Sequelize连接mysql
  8. Android中用OpenGL ES Tracer分析绘制过程
  9. oracle定时向mysql取数据_Oracle中通过Job实现定时同步两个数据表之间的数据
  10. 图论(二):图的割点(cut vertex)与连通度(connectivity)
  11. 明基5560 win7 64驱动_这个Win7系统,稳定又纯净!
  12. python基于django的校园公寓宿舍报修管理系统设计与实现
  13. 互联网日报 | 农夫山泉正式登陆港交所;飞猪推出旅游业首个百亿补贴;苹果秋季发布会正式官宣...
  14. 光纤与PON基础概念整理
  15. 红米手机4A超简单刷入开发版获取ROOT超级权限的教程
  16. opencv 旋转和平移的矩阵
  17. [从头读历史] 第265节 诗经 周南
  18. 二重积分的C语言实现
  19. R语言使用factor函数处理名义变量(nominal、无序/标称分类变量)、使用ordered函数处理序数变量(ordinal、有序分类/标称变量)
  20. 知乎上已获千赞,已拿offer入职

热门文章

  1. C++重载函数使用(使用重载函数分别完成求2个整数、3个整数、4个整数的最大值。)
  2. linux .sig文件,使用.sig签名验证文件
  3. JAVA学习总结十二
  4. 一年一度秋风劲——年度总结
  5. 【Java---数据结构】二叉搜索树
  6. iOS NSAttributedStr
  7. 我对移相器的理解(1):单bit的移相结构
  8. Linux下查看图片——安装imgcat
  9. 无线渗透--‘钓鱼’wifi
  10. windows+python+bleak+BLE低功耗蓝牙通讯连接