经典网络骨架:Backbone 学习笔记(一)——卷积网络的基本构成

目标检测经典骨架网络

当前的物体检测算法虽然各不相同,但第一步通常是利用卷积神经网络处理输入图像,生成深层的特征图,然后再利用各种算法完成区域生成与损失计算,这部分卷积神经网络是整个检测算法的“骨架”,也被称为Backbone。
在这里插入图片描述

卷积神经网络的基本构成

在这里插入图片描述

卷积层

如图所示为一个基本二维卷积的运算过程,公式为y=ωx+b。这里的特征图(x)大小为1×5×5,即输入通道数为1,卷积核(ω)的大小为3×3,偏置(b)为1,为保证输出维度和输入特征维度一致,还需要有填充(padding),这里使用zero-padding,即用0来填充。
在这里插入图片描述
偏置是卷积操作后相加的一个常数,例如上图卷积核卷积左上角操作,1×0+0×0+1×0+0×0+1×1+0×8+1×0+0×6+1×7+1=9

  • padding用于保持卷积维度 当卷积核大小与输入图大小不能整除时保证卷积操作正常进行。最终保证输入输出维度相同。
  • 保持上述卷积核大小以及padding不变,stride变大,卷积输出的特征图维度减小。
  • 保持padding和stride不变,卷积核越小,输出特征图越大;卷积核越大,输出特征图越小。所以越小的卷积核会提取到更细节的特征信息。
>>> from torch import nn
# 使用torch.nn中的Conv2d()搭建卷积层
>>> conv = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, stride=1,
padding=1, dilation=1, groups=1, bias=True)
# 查看卷积核的基本信息,本质上是一个Module
>>> conv
Conv2d(1, 1, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
# 通过.weight与.bias查看卷积核的权重与偏置
>>> conv.weight.shape
torch.Size([1, 1, 3, 3])
>>> conv.bias.shape
torch.Size([1])
# 输入特征图,需要注意特征必须是四维,第一维作为batch数,即使是1也要保留
>>> input = torch.ones(1, 1, 5, 5)
>>> output=conv(input)
# 当前配置的卷积核可以使输入和输出的大小一致
>>> input.shape
torch.Size([1, 1, 5, 5])
>>> output.shape
torch.Size([1, 1, 5, 5])
import torch
a = torch.ones(1,1,5,5)
# batch chanel H W  batch不能省略
print(a)

>>tensor([[[[1., 1., 1., 1., 1.],
          [1., 1., 1., 1., 1.],
          [1., 1., 1., 1., 1.],
          [1., 1., 1., 1., 1.],
          [1., 1., 1., 1., 1.]]]])

激活函数层

Sigmoid函数

在这里插入图片描述
在这里插入图片描述

Sigmoid函数可以用来做二分类(0,1),但其计算量较大,并且容易出现梯度消失现象。从曲线图中可以看出,在Sigmoid函数两侧的特征导数接近于0,这将导致在梯度反传时损失的误差难以传递到前面的网络层(因为根据链式求导,梯度接近于0)。

所以神经网络中常用的激活函数不是Sigmoid,下面引出常用的激活函数Relu函数。

Relu函数

在这里插入图片描述
在这里插入图片描述

ReLU函数及其梯度曲线如图3.5所示。可以看出,在小于0的部分,值与梯度皆为0,而在大于0的部分中导数保持为1,避免了Sigmoid函数中梯度接近于0导致的梯度消失问题。

虽然解决了梯度消失问题,但是缺点也很明显,就是在负区间的输出全是0。因此引除了

Leaky ReLU函数

在这里插入图片描述
在这里插入图片描述
将负区间的输出赋一个小权重。但是实验表明Relu还是最好用的。

Softmax函数

面对多物体分类问题,虽然可以使用Sigmoid函数来构造多个二分类器,但比较麻烦,多物体类别较为常用的分类器是Softmax函数。

在具体的分类任务中,Softmax函数的输入往往是多个类别的得分,输出则是每一个类别对应的概率,所有类别的概率取值都在0~1之间,且和为1。

Softmax函数的表达如式所示,其中,Vi 表示第i个类别的得分,C代表分类的类别总数,输出Si 为第i个类别的概率。
在这里插入图片描述

  • 可以看出得分越高的输入输出的概率越高,最终概率最高的分为此类。
>>> import torch.nn.functional as F
>>> score = torch.randn(1,4)
>>> score
tensor([[ 1.3858, -0.4449, -1.7636, 0.9768]])
# 利用torch.nn.functional.softmax()函数,第二个参数表示按照第几个维度进行
# Softmax计算
>>> F.softmax(score, 1)
tensor([[ 0.5355, 0.0858, 0.0230, 0.3557]])

池化层

在卷积网络中,通常会在卷积层之间增加池化(Pooling)层,以降低特征图的参数量,提升计算速度,增加感受野,是一种降采样操作。池化是一种较强的先验,可以使模型更关注全局特征而非局部出现的位置,这种降维的过程可以保留一些重要的特征信息,提升容错能力,并且还能在一定程度上起到防止过拟合的作用。
在这里插入图片描述

>>> import torch
>>> from torch import nn
# 池化主要需要两个参数,第一个参数代表池化区域大小,第二个参数表示步长
>>> max_pooling = nn.MaxPool2d(2, stride=2)
>>> aver_pooling = nn.AvgPool2d(2, stride=2)
>>> input = torch.randn(1,1,4,4)
>>> input
tensor([[[[ 1.4873, -0.2228, -0.3972, -0.1336],
[ 0.6129, 0.4522, -0.3175, -1.2225],
[-1.0811, 2.3458, -0.4562, -1.9391],
[-0.3609, -2.0500, -1.2374, -0.2012]]]])
# 调用最大值池化与平均值池化,可以看到size从[1, 1, 4, 4]变为了[1, 1, 2, 2]
>>> max_pooling(input)
tensor([[[[ 1.4873, -0.1336],
[ 2.3458, -0.2012]]]])
>>> aver_pooling(input)
tensor([[[[ 0.5824, -0.5177],
[-0.2866, -0.9585]]]])

Dropout层

参数过多,训练样本比较少时,模型容易过拟合。**过拟合具体表现为训练集上预测准确率高,而在测试集上准确率大幅度下降。**因此Dropout算法有效缓解过拟合现象的发生,起到正则化的作用。

在训练时,每个神经元以概率p保留,即以1-p的概率停止工作,每次前向传播保留下来的神经元都不同,这样可以使得模型不太依赖于某些局部特征,泛化性能更强。在测试时,为了保证相同的输出期望值,每个参数还要乘以p。
在这里插入图片描述

>>> import torch
>>> from torch import nn
# PyTorch将元素置0来实现Dropout层,第一个参数为置0概率,第二个为是否原地操作
>>> dropout = nn.Dropout(0.5, inplace=False)
>>> input = torch.randn(2, 64, 7, 7)
>>> output = dropout(input)

Dropout被广泛应用到全连接层中,一般保留概率设置为0.5,而在较为稀疏的卷积网络中则一般使用下一节将要介绍的BN层来正则化模型,使得训练更稳定。

BN层

随着网络层数加深,网络难以训练收敛与调参。是因为,浅层网络参数的微小变化经过多层线性变换和激活函数后会被放大,卷积网络变得“稀疏“了,导致深层网络需要不断调整,难以收敛。

Relu在激活函数角度改善了梯度问题,BN则是在改变数据分布的角度避免了参数陷入饱和区。

BN层首先对每一个batch的输入特征进行白化操作,即去均值方差
过程。假设一个batch的输入数据为x:B={x1,…,xm},首先求该batch数据的均值与方差。
在这里插入图片描述
在这里插入图片描述

  • m代表batch数,μB代表总批次数据处理的均值,σ^2B为批处理数据方差。然后进行去均值方差操作。
    在这里插入图片描述

白化操作可以使输入的特征分布具有相同的均值与方差,固定了每 一层的输入分布,从而加速网络的收敛。这样做避免了梯度饱和,但又导致浅层的参数信息被屏蔽,所以BN层在白化操作后又增加了一个线性变换操作,让数据尽可能地恢复本身的表达能力。
BN–Batchnorm
(这里没太明白)

在这里插入图片描述
BN层的弊端和适用范围:

  1. 由于是在batch的维度进行归一化,BN层要求较大的batch才能有效地工作。利于目标检测任务占内存较高,限制batch大小,使得BN层归一化功能并不好。
  2. 数据的batch大小在训练与测试时往往不一样。在训练时一般采用滑动来计算平均值与方差,在测试时直接拿训练集的平均值与方差来使用。这种方式会导致测试集依赖于训练集,然而有时训练集与测试集的数据分布并不一致。
  3. GN(Group Normalization)巧妙的避开了Batch来归一化。将特征图的不同通道进行分组归一化。避免了训练集和测试集由于batch不一致归一化效果不好的现象。

全连接层

在这里插入图片描述
卷积网络的主要作用是从局部到整体地提取图像的特征,而全连接层则用来将卷积抽象出的特征图进一步映射到特定维度的标签空间,以求取损失或者输出预测结果。

>>> import torch
>>> from torch import nn
# 第一维表示一共有4个样本
>>> input = torch.randn(4, 1024)
>>> linear = nn.Linear(1024, 4096)
>>> output = linear(input)
>>> input.shape
torch.Size([4, 1024])
>>> output.shape
torch.Size([4, 4096])

全连接层的缺点明显,就是参数量巨大,大量的参数会导致网络模型应用部署困难,并且其中存在着大量的参数冗余,也容易发生过拟合的现象。在很多场景中,我们可以使用全局平均池化层(Global Average Pooling,GAP)来取代全连接层。
GAP可以起到降维的作用,减少了参数量,去除了全连接层,可以任意尺度输入。

感受野

感受野(Receptive Field)是指特征图上的某个点能看到的输入图像的区域,即特征图上的点是由输入图像中感受野大小区域的计算得到的。

  • 每一层积核为3×3,步长为1,可以看到第一层对应的感受野3×3,第二层是5×5,第三层则是7×7。
    在这里插入图片描述
  • 卷积层和池化层都会影响感受野,而激活函数层通常对于感受野没有影响。
  • 实际的有效感受野 (Effective Receptive Field)往往小于理论感受野。
  • 从图中也可以看出,虽然第三层的感受野是7×7,但是输入层中边缘点的使用次数明显 比中间点要少,因此做出的贡献不同。

空洞卷积

最初用来解决图像分割问题。图像分割问题需要通过池化层来增大感受野,这样同时也缩小了特征图尺寸,再进行上采样操作还原特征图尺寸使得精度丢失,所以空洞卷积就诞生了。空洞卷积可以增大感受野的同时保证特征图尺寸不变代替池化和上采样操作
在这里插入图片描述

  • a) 普通卷积:在卷积核紧密排列在特征图上滑动计算。
  • b) 空洞数为2的空洞卷积:可以看到,在特征图上每2行或者2列选取元素与卷积核卷积。
  • c) 代表了空洞数为3的空洞卷积

同样的一个3×3卷积,却可以起到5×5、7×7等卷积的效果。可以看出,空洞卷积在不增加参数量的前提下,增大了感受野。

  • 卷积核越大卷出来特征图越小,感受野越大,空洞卷积中间空洞不进行卷积,保留了特征图尺寸,也增大了感受野。
  • 假设空洞卷积的卷积核大小为k,空洞数为d,则其等效卷积核大小k’计算如下式所示。

在这里插入图片描述
空洞卷积的优点显而易见,在不引入额外参数的前提下可以任意扩大感受野,同时保持特征图的分辨率不变。这一点在分割与检测任务中十分有用,感受野的扩大可以检测大物体,而特征图分辨率不变使得物 体定位更加精准。

  • 空洞卷积增加了感受野,这样对大物体检测有利,但是对于小物体检测有弊,因此空洞卷积面临尺度问题。
  • 远距离的信息没有相关性:空洞卷积采取了稀疏的采样方式,导致远距离卷积得到的结果之间缺乏相关性,进而影响分类的结果。损失信息的连续性。
  • 23
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值