【深度学习】SSD网络原理

在这里插入图片描述SSD网络backbone由VGG16网络的全部卷积层,即到conv5为止,去掉之后的全连接层。如下图:
在这里插入图片描述

然后是
conv6:3x3x1024;
conv7:1x1x1024;
conv8:1x1x256,stride=1,3x3x512,stride=2,padding=1;
conv9:1x1x128,stride=1,3x3x256,stride=2,padding=1;
conv10:1x1x128,stride=1,3x3x256,stride=1,padding=0;
conv11:1x1x128,stride=1,3x3x256,stride=1,padding=0;

其中conv4,7,8,9,10,11作为多尺度特征图,再分别进行3x3xp的卷积提取检测结果。
其中p=( ratio数量x ( 类别数(21)+预测框参数个数(4) ) )
ratio数量 conv7,8,9 为6个,其他为4个,具体原因在稍后讲到。

default box

对于之前的每一个特征图,特征图上的每一个像素点cell都会生成一系列default box,每一个default box按特征图和原图的比例映射到原图,就能获得不同大小的框,来识别不同大小的目标。在这里插入图片描述
每个feature map 的大小分别为

38x38、19x19、10x10、5x5、3x3、1x1

每个特征层经过卷积之后,在channel方向,就有每个小像素点对应ratio组defaultbox的信息,每一组包括21个类别概率,4个预测框回归参数。

defaultbox大小的选取
在这里插入图片描述
Sk可以简单理解为default box面积 与 原图的比例,Smax原文取0.9,Smin原文取0.2,m是特征图的数量,backbone里的conv4不算,所以m=5,k是第k个特征图。k=1时,取Sk=0.1。
所以default box的大小(面积开根号)为

   			         300 * 0.1,300*0.2,*300[0.2+(0.7/4)*(2-1)],等等

		                    30,60,111,162,213,264

实际上很多复现,并没有按这个来~

大小确定,确定ratio,即default box的形状
conv7,8,9 有 6种形状

1:1 、1:1(大小为Sk’)、1:2、2:1、1:3、3:1
在这里插入图片描述

conv4,conv10,conv11有4种形状

1:1 、1:1(大小为Sk’)、1:2、2:1、

也就是之前3x3xp卷积的p中的不同

default box中心点的定义
在这里插入图片描述
fk为特征图的长度,其实中心点就定义在每个像素点的中间

正负样本的选取

正样本:
首先ground truth匹配每个和它iou最大的boundingbox,将这些boundingbox选为正样本。
bounding box与某个ground truth的IOU大于某个阈值(0.5)设为正样本。

负样本:
其他都为负样本

由于负样本太多,所以会对负样本进行排序,取负样本中概率为背景较大的一些,保持 负样本:正样本 接近 3:1。

损失函数

损失函数定义为位置误差(loc)与置信度误差(conf)的加权和
在这里插入图片描述
位置误差采用Smooth L1 loss
在这里插入图片描述在这里插入图片描述
l为预测的位置参数,g为真实的位置参数,d为default box的位置参数,x,y是中心坐标,w,h是box的宽和高,xij=1,第i个预测box与第j个ground truth所匹配。
我个人认为学习的是default box 和 ground truth的偏移量,并且只关心位置,不关心类别。

置信度误差
采用softmax,0表示为背景的概率
在这里插入图片描述

大概就是这样了,之后遇到什么问题再补充

2021.5.8
SSD300框架

import torch
import torch.nn as nn
from Basic_Net.VGG import VGG

class SSD (nn.Module):
    def __init__(self,num_class=21):
        super(SSD, self).__init__()
        self.num_class = num_class
        self.backbone = VGG()
        # todo 把backbone的maxpool改为向上取整 ceil_mode = True
        # 去掉最后一个maxpool
        self.backbone_all = list(self.backbone.children())[0][0:-1]
        # 去掉conv5 提取特征
        self.backbone_conv4 = nn.Sequential(*list(self.backbone.children())[0][0:23])
        print(list(self.backbone.children())[0][0:23])
        self.backbone = nn.Sequential(*list(self.backbone_all))
        #
        self.conv_6_7 = nn.Sequential(
            nn.Conv2d(512,1024,kernel_size=3,padding=1),
            nn.BatchNorm2d(1024),
            nn.ReLU(True),
            nn.Conv2d(1024,1024,kernel_size=1),
            nn.BatchNorm2d(1024),
            nn.ReLU(True),
        )
        self.conv_8 = nn.Sequential(
            nn.Conv2d(1024,256,kernel_size=1),
            nn.BatchNorm2d(256),
            nn.ReLU(True),
            nn.Conv2d(256,512,kernel_size=3,stride=2,padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(True),
        )
        self.conv_9 = nn.Sequential(
            nn.Conv2d(512,128,kernel_size=1,stride=1),
            nn.BatchNorm2d(128),
            nn.ReLU(True),
            nn.Conv2d(128,256,kernel_size=3,stride=2,padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU(True),
        )
        self.conv_10 = nn.Sequential(
            nn.Conv2d(256,128,kernel_size=1,stride=1),
            nn.BatchNorm2d(128),
            nn.ReLU(True),
            nn.Conv2d(128,256,kernel_size=3,stride=1,padding=0),
            nn.BatchNorm2d(256),
            nn.ReLU(True),
        )
        self.conv_11 = nn.Sequential(
            nn.Conv2d(256,128,kernel_size=1),
            nn.BatchNorm2d(128),
            nn.ReLU(True),
            nn.Conv2d(128,256,kernel_size=3,stride=1,padding=0),
            # 1x1矩阵就不需要BN啦
            nn.ReLU(True),
        )

        # 提取特征层
        inchannel = [512,1024,512,256,256,256]
        self.conv_featrue = []
        for i,channel in enumerate(inchannel):
            if i in[1,2,3]:
                ratio = 6

            else:
                ratio = 4
            print(ratio)
            # 位置
            conv_loc = nn.Sequential(
                nn.Conv2d(channel, ratio * 4, kernel_size=3, stride=1,padding=1),
            )
            # 分类置信度
            conv_cof = nn.Sequential(
                nn.Conv2d(channel, ratio * num_class, kernel_size=3, stride=1,padding=1),
            )
            self.conv_featrue.append((conv_loc,conv_cof))

        #self.conv_featrue = nn.ModuleList(self.conv_featrue)

    def forward(self,x):
        self.feature_extra = []
        # 先把特征图1拿出来
        feature_1 = self.backbone_conv4(x)

        self.feature_extra.append(feature_1)

        x = self.backbone(x)
        
        x = self.conv_6_7(x)
        self.feature_extra.append(x)
        
        x = self.conv_8(x)
       
        self.feature_extra.append(x)
        x = self.conv_9(x)
        
        self.feature_extra.append(x)
        x = self.conv_10(x)
       
        
        self.feature_extra.append(x)
        x = self.conv_11(x)
        
        self.feature_extra.append(x)
        # batch,channel,w,h w*h 个点 每个点的channel方向是一组 不同形状的box的类别和位置偏移信息
        self.loc,self.conf = self.get_feature(self.feature_extra)
        # (batch,4,box_num)

        return self.loc,self.conf


    def get_feature(self,feature_list):
        # nn.ModuleList 使list可以调用Module的方法
        # self.feature_list = nn.ModuleList(feature_list)
        locs = []
        confs = []
        self.feature_list = feature_list
        for (x,conv) in zip(self.feature_list,self.conv_featrue):
            
            # conv_feature : tuple(loc_conv2d,confi_conv2d)
            conv_loc,conv_conf = conv
            loc = conv_loc(x)
           
            conf = conv_conf(x)
            
            # (batch,ratio_num*4,w,h) => (batch,4,box_num)
            loc = loc.reshape((loc.size(0),4,-1))
            # => (batch, 21, box_num)
            conf = conf.reshape((conf.size(0),self.num_class,-1))
            locs.append(loc)
            confs.append(conf)
            # 所有的cat在一起,cat在哪个维度,哪个维度东西变多
        loc = torch.cat(locs,2)
        conf = torch.cat(confs,2)
        return loc,conf







  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值