Densely Connected Convolutional Networks 密集连接卷积网络

什么是DenseNet?

DenseNet是由清华大学的Zhuang Liu、康奈尔大学的Gao Huang和Kilian Q.Weinberger,以及Facebook研究员Laurens van der Maaten在CVPR 2017所作,并且还获得了2017CVPR最佳论文!下面我们就来看看DenseNet是何方神圣吧。

我们知道,当靠近输入的层和靠近输出的层之间的连接越短,卷积神经网络就可以做得更深,精度更高且可以更加有效的训练。而DenseNet在此基础上将每一层与之前所有层相连接。传统的L层卷积神经网络有L个连接——位于每一层和其后一层之间—,而我们的神经网络有L*(L+1)/2个直接链接。对于每一层,其输入的特征是之前所有的层,而它自己的特征图作为之后所有层的输入。

下图展示了具体的密集连接方式:

DenseNet有以下几个引人注目的优点:缓解梯度消失问题,加强特征传播,鼓励特征复用,极大的减少了参数量。DenseNets需要更少的计算来实现高性能

ResNet

训练深层的神经网络,会遇到梯度消失和梯度爆炸(vanishing/exploding gradients)的问题,影响了网络的收敛,但是这很大程度已经被标准初始化(normalized initialization)和BN(Batch Normalization)所处理

当深层网络能够开始收敛,会引起网络退化(degradation problem)问题,即随着网络深度增加,准确率会饱和,甚至下降。这种退化不是由过拟合引起的,因为在适当的深度模型中增加更多的层反而会导致更高的训练误差
ResNet就通过引入深度残差连接来解决网络退化的问题,建立前面层与后面层之间的短链接(shortcuts),从而解决深度CNN模型难训练的问题

具体表达式如下:
在这里插入图片描述
在ResNet中前面层与后面层建立的短链接(shortcuts)方式是add相加操作,因此要求输入与输出的shape完全一样!这主要是由ResNet结构中的Identity Block来完成的,更大程度地去加深网络的深度,实现了深度残差网络。但是add操作可能会阻碍网络中的信息流。

DenseNets和Resnet之间的主要区别,DenseNets通过特征重用来挖掘网络的潜力,产生易于训练且参数效率高的精简模型。将不同层学习到的特征映射进行堆叠操作,可以增加后续层的输入变化,并提高效率。

DenseNet

DenseNet的整体网络架构如下图所示:

一个有三个Dense Block的DenseNet网络。每个Dense Block中含有多个conv blocks,conv blocks中特征图的高度和宽度不发生变化,进行的是通道数的变化。 两个相邻Dense Block之间的层称为Transition Layer过渡层,通过卷积和池化改变特征图的大小

Dense connectivity 紧密连接

为了进一步改善层与层之间的信息流,提出了一种不同的连接模式:引入从任何层到所有后续层的直接连接。正如上图所展示的那样,例如第l层接收前面所有层的特征映射,即x0,x1,…,xl-1作为输入:
在这里插入图片描述
H函数实现每层的非线性变换,主要由BN,Relu和3x3Conv组成,式中[x0,x1,…,xl-1]指的是第0,…,l-1层中生成的特征图进行串联。

Bottleneck layers

每一个Dense Block中的conv block经过H非线性输出k个特征图,但是它通常是输入特征图更多。因此在3x3卷积之前引入1x1卷积作为瓶颈层,以减少特征映射的数量,从而提高计算效率。

Growth rate

如果每个函数H生成k个特征映射,则第l层具有k0+k×(l-1)个输入特征映射,其中k0是输入的通道数。DenseNet与现有网络体系结构的一个重要区别是,DenseNet可以有非常窄的层,例如k=12。我们把超参数k称为网络的growth rate。相对较小的growth rate足以获得最新的结果。
实现代码为:

class Bottleneck(nn.Module):
    def __init__(self, nChannels, growthRate):
        super(Bottleneck, self).__init__()
        interChannels = 4*growthRate
        # 瓶颈结构1x1卷积减少输入的通道数
        self.bn1 = nn.BatchNorm2d(nChannels)
        self.conv1 = nn.Conv2d(nChannels, interChannels, kernel_size=1,bias=False)
        # H函数实现非线性输出BN+Relu+BN
        self.bn2 = nn.BatchNorm2d(interChannels)
        self.conv2 = nn.Conv2d(interChannels, growthRate, kernel_size=3,padding=1, bias=False)

    def forward(self, x):
        out = self.conv1(F.relu(self.bn1(x)))
        out = self.conv2(F.relu(self.bn2(out)))
        out = torch.cat((x, out), 1)
        return out

Pooling layers 池化层

当特征映射的大小发生变化时,上面式子中使用的连接操作是不可行的。然而,卷积网络的一个重要组成部分是向下采样层来改变特征映射的大小。因此在Dense Block之间添加Transition Layer来进行特征图大小的压缩,而Transition Layer主要由一个1x1卷积块以及步长为2的AveragePooling2D来进行特征图大小压缩。

Compression 压缩

为了进一步提高模型的紧凑性,在Transition Layer中减少特征映射的数量。如果一个Desne Block中包含m个特征映射,在Transition Layer中生成的特征图数量为θm,其中0<θ≤1被称为压缩因子。当θ=1时,Transition Layer的特征图数量保持不变,论文中将θ设置为0.5。
Transition Layer实现代码如下:

# reduction即为压缩因子
nOutChannels = int(math.floor(nChannels*reduction))
class Transition(nn.Module):
    def __init__(self, nChannels, nOutChannels):
        super(Transition
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值