参考自SSD算法理论
Pytorch搭建孪生神经网络
先一点点记录零碎的东西,后面积累到一定量了再总结一下

第一个预测特征层,scale为21的尺度,他会有1:1,2:1,1:2这三个比例,对于根号下2145的scale,只有1:1的比例,所以一共有4个default boxes.
第二个预测特征层,scale为45的尺度,他会有1:1,2:1,1:2,3:1,1:3这5个比例,对于根号下45
99的scale,只有1:1的比例,所以一共有6个default boxes.
其余的预测特征层是一样的道理。

在这6个特征图上,总共会生成8732个default boxes.
选取了6个feature map中的两个,feature map1对应4个default boxes ,其中1:1为中间黄色框,1:2和2:1为中间两个蓝色框,外面那个黄色框为根号下21 * 45,比例为1:1.
feature map4对应6个default boxes.其中1:1为中间黄色框,1:2和2:1为中间两个蓝色框,1:3和3:1为中间两个红色框。外面那个黄色框为根号下153*207,比例为1:1.
如果把个feature map全部绘制在图片上,那么基本可以覆盖图片上所有出现的目标了。
对于每个给定的位置,会生成k个default box,对于每个default box 会计算c个类别分数和4个坐标偏移量。那么就需要(c + 4) * k个卷积核进行卷积处理,那么对于一个m * n的feature map而言,就会生成一个(c + 4) * k * m * n个输出值。

其中,c* k个值用来预测目标类别,4 * k个值用来预测边界框回归参数。
这里的c包括背景类别,也就是会预测背景的概率的。
每个default box对应计算4个偏移量:中心坐标x,y的偏移量,w,h宽度和高度的偏移量。
训练模型时,
正样本选取的两个准则:
1、对于每个ground truth box,去匹配与它IOU值最大的那个default box
2、对于任意的default box,它只要与任意的一个ground truth的IOU值大于0.5,那么也认为它是正样本。

负样本的选取。
如果把匹配剩下的所有default box当成负样本,那么负样本的数量也太大了。这样就会造成样本数量不平衡问题。我们的措施:计算每个default box的highest confidence loss,并且按照从高到底进行排序。
为什么计算confidence loss:这个值越大,那么网络将这个负样本预测为目标的概率会更大,这是我们所不能容忍的。
于是,计算出confidence loss的值后,取一些confidence loss最大的样本作为负样本。具体取多少呢?使得总体负样本比正样本的比例为3:1即可。
这种负样本的选取方法在论文中称为Hard negative mining




SSD框架大概:
输入是一个300 * 300的图片,先通过一个VGG16的前置网络部分,通过Conv5_3layer后,还有一个pooling层,但是这个pooling层由原来的池化核大小2 * 2步距为2,变为池化核大小3 * 3步距为1.这样他是不会改变我们特征矩阵的大小的,后面又接了一系列的卷积层,见上图的下面部分。
通过上面的卷积能够得到我们的6个特征层(上图已经标注了),然后分别在这6个特征层上去预测不同尺度以及比例的目标,预测完之后再通过非极大值抑制算法,以及,滤除我们小概率的目标,就能够得到最终的预测结果。

代码的原理图:

SSD算法会在这6个特征层上进行预测。
继续补充 下面参考自Pytorch 搭建自己的SSD目标检测平台


因为经多次卷积池化后,小物体的特征容易消失,所以这里采用不同尺寸的网格(越细密的网格可以延缓小物体特征消失的现象,结合一下池化均一代表就好理解一些)
一般来讲,38 * 38和1919的网格用来检测小物体,55,33,11的网格用来检测大的物体。

对于SSD目标检测网络来讲,它的输入图片shape是https://github.com/bubbliiiing/ssd-pytorch/archive/refs/heads/master.zip300 * 300 * 3 的。所以我们输入一张图片的时候,需要对它resize一下。另外,这里用到了VGG用来特征提取,但是对VGG进行了一些改变,后面还增加了4个卷积层。通过这样一个主干特征提取网络,SSD可以对输入的300 * 300的图片进行不断的特征提取(提取了6个特征层),利用这些特征层就可以进行下一步的操作,获得框的位置了。

上面的特征层,比如第一个特征层38 * 38 ,就是把图片分割成38 * 38 的网格,然后这样对图片进行目标检测。

为啥要分割成那么多的网格呢?因为以每个网格为中心,会生成许多的先验框(那么就是每个网格都对应几个先验框,整张图来看就是密密麻麻的先验框),后面对这些先验框进行调整选择,最后真正选中的只有几个。
上数第三张图中(懒得标序号了,就这么叫吧),def:boxes后面对应的数字就是每个网格所对应的先验框的个数,所以第一个特征层每个网格对应4个先验框,那么第一个特征层对应38 * 38 * 4个先验框,其它特征层也是同理,最后六个特征层加起来,总共是8732个先验框。那么我们就相当于调整了8732个先验框,然后判断这调整的8732个先验框里面有没有我们需要的物体,如果有的话我们就把它标出来。当然我们得到的框有一些是重合的,那么我们就需要对这些框的得分和重合情况进行判断,利用非极大抑制的方法,找到我们需要的框,并且标出它们所属的种类。这就是SSD算法的检测过程。

这里用到了VGG作为backbone,下面的代码进行到了到这里,得到了19 * 19 * 1024的特征层:

代码:

import torch.nn as nnbase = [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'C', 512, 512, 512, 'M',512, 512, 512]'''
该代码用于获得VGG主干特征提取网络的输出。
输入变量i代表的是输入图片的通道数,通常为3。一般来讲,输入图像为(300, 300, 3),随着base的循环,特征层变化如下:
300,300,3 -> 300,300,64 -> 300,300,64 -> 150,150,64 -> 150,150,128 -> 150,150,128 -> 75,75,128 -> 75,75,256 -> 75,75,256 -> 75,75,256
-> 38,38,256 -> 38,38,512 -> 38,38,512 -> 38,38,512 -> 19,19,512 ->  19,19,512 ->  19,19,512 -> 19,19,512
到base结束,我们获得了一个19,19,512的特征层之后进行pool5、conv6、conv7。
'''
def vgg(i):layers = []in_channels = ifor v in base: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)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

i是通道数,一般等于3,M和C是加入最大池化层,C模式下,ceil_mode = True 是指池化的时候,把不足的边给保留下来,单独另算,这样会增加池化后的特征层尺度:

数字是经过卷积后的通道数。

上图,红色框代表最大池化层,白色框代表卷积层。

而从第三个特征层到最后特征层的实现,是由ssd.py中的下面的代码完成的:

def add_extras(i, backbone_name):layers = []in_channels = iif backbone_name=='vgg':# Block 6# 19,19,1024 -> 10,10,512layers += [nn.Conv2d(in_channels, 256, kernel_size=1, stride=1)]layers += [nn.Conv2d(256, 512, kernel_size=3, stride=2, padding=1)]# Block 7# 10,10,512 -> 5,5,256layers += [nn.Conv2d(512, 128, kernel_size=1, stride=1)]layers += [nn.Conv2d(128, 256, kernel_size=3, stride=2, padding=1)]# Block 8# 5,5,256 -> 3,3,256layers += [nn.Conv2d(256, 128, kernel_size=1, stride=1)]layers += [nn.Conv2d(128, 256, kernel_size=3, stride=1)]# Block 9# 3,3,256 -> 1,1,256layers += [nn.Conv2d(256, 128, kernel_size=1, stride=1)]layers += [nn.Conv2d(128, 256, kernel_size=3, stride=1)]

这里之所以判断是不是VGG,是因为代码中除了提供VGG作为主干特征提取网络外,还添加了mobilenetv2作为ssd的主干特征提取网络,作为轻量级ssd的实现,可通过设置train.py和ssd.py中的backbone进行主干变换。

而num_priors指的是该特征层每一个特征点所拥有的先验框数量。上述提到的六个特征层,每个特征层的每个特征点对应的先验框数量分别为4、6、6、6、4、4。
回归预测的通道数:num_priors * 4代表每个先验框的调整参数
分类预测的通道数:num_priors * num_classes代表对每个先验框预测的种类(种类包括背景,数量+1)
如果预测某个类的概率很高,那么这个先验框的内部很可能包含物体。

目标检测---SSD相关推荐

  1. 动手学深度学习——目标检测 SSD R-CNN Fast R-CNN Faster R-CNN Mask R-CNN

    来源:13.4. 锚框 - 动手学深度学习 2.0.0-beta1 documentation 目标检测:锚框算法原理与实现.SSD.R-CNN_神洛华的博客 目录 目标检测简介 目标检测模型 ​编辑 ...

  2. 目标检测 SSD: Single Shot MultiBox Detector - SSD在MMDetection中的实现

    目标检测 SSD: Single Shot MultiBox Detector - SSD在MMDetection中的实现 flyfish 目标检测 SSD: Single Shot MultiBox ...

  3. 说说早期目标检测-----------ssd那些事

    说说早期目标检测---------ssd那些事 前言 论文地址 github ssd的优点 学习前言 a[::-1] ssd---anchor SSD代码讲解 1.预测部分 获得预测结果 预测框解码 ...

  4. 目标检测SSD学习笔记

    目标检测SSD学习笔记 SSD: Single Shot MultiBox Detector Abstract. 我们提出了一种使用单一深度神经网络来检测图像中的对象的方法.我们的方法,命名为SSD, ...

  5. 再读目标检测--ssd深度解析

    [目标检测 – R-CNN,Fast R-CNN,Faster R-CNN] https://www.cnblogs.com/yanghailin/p/14767995.html [目标检测-SSD] ...

  6. 重温目标检测--SSD

    SSD: Single Shot MultiBox Detector ECCV2016 https://github.com/weiliu89/caffe/tree/ssd 针对目标检测问题,本文侧重 ...

  7. 目标检测--SSD: Single Shot MultiBox Detector

    SSD: Single Shot MultiBox Detector ECCV2016 https://github.com/weiliu89/caffe/tree/ssd 针对目标检测问题,本文取消 ...

  8. SSD浅层网络_目标检测SSD

    一.目标检测之SSD SSD: Single Shot MultiBox Detector 论文链接:https://arxiv.org/abs/1512.02325 论文翻译:https://blo ...

  9. 目标检测-SSD算法详细总结

    文章与视频资源多平台更新 微信公众号|知乎|B站|头条:AI研习图书馆 深度学习.大数据.IT编程知识与资源分享,欢迎关注,共同进步~ 一. 引言 文章:SSD: Single Shot MultiB ...

  10. 目标检测—SSD系列算法原理介绍

    一.SSD系列算法原理介绍 1.1 SSD算法介绍: ➢Single Shot MultiBox Detector (one-stage方法)                  ●Wei Liu在EC ...

最新文章

  1. Winform开发中常见界面的DevExpress处理操作
  2. 基于xampp搭建的个人博客。
  3. hdu1006 Tick and TIck
  4. android 有值代码,Android:如何在代码中获取“listPreferredItemHeight”属性的值?
  5. idea新建类包图标_IntelliJ IDEA 常见文件类型的图标介绍
  6. ListView缓存机制踩过的坑
  7. TDSQL迁移,myloader:39626报错问题的排查与解决
  8. Navicat打开保存的查询
  9. android计算汇率代码,android studio 开发实例 连接网络获取汇率
  10. 区块链 女巫攻击是什么 Sybil Attack 为什么POW可以抵御女巫攻击 一文看懂
  11. linux负载均衡总结性说明(四层负载/七层负载)
  12. OpenSCAD通过循环快速复制几何对象
  13. 如何使用Teamtoken工具软件做员工股权激励
  14. pop3 c语言,VisualC#编写实现POP3的程序
  15. c#对Aspose.Word替换书签内容的简单封装
  16. def是c语言特殊标识符吗,typedef和def究竟有什么区别?
  17. Graphene-SGX 总结
  18. 关系数据库规范化理论
  19. android 高德地图定位缓慢,Android高德地图定位逻辑优化
  20. C# 学习笔记 1.初识

热门文章

  1. 20200620每日一句
  2. 传智播客扫地僧C/C++学习笔记冒泡排序
  3. 181116每日一句
  4. unity通过脚本获取一个物体的所有子物体孙子物体.....并从里面找到有动画的物体
  5. Atitit. Toast alert loading js控件   atiToast v2新特性
  6. Atitit.常见的4gl 第四代编程语言  与 dsl
  7. atitit.基于虚拟机的启动器设计 --java 启动器 java生成exe
  8. Paip.Php Java 异步编程。推模型与拉模型。响应式(Reactive)”编程FutureData总结... 1
  9. 关于FLEX中找不到目标对象或通道未定义错误
  10. 贝莱德砸10亿美元买下指数定制公司,释放什么信号?