卷积神经网络之(稠密连接网络)DenseNet
ResNet中的跨层连接引申出了无数后续工作,DenseNet就是其中之一。
结构
下图所示,ResNet(左)与DenseNet(右)在跨层连接上的主要区别:使用相加和使用连结
上面右图表示B的输出在通道维上连接,A的output直接传入B后面的层。
A直接与B后面的所有层连接在一起,所以叫稠密连接。
DenseNet的优点:
- 网络每层的计算量减少
- 特征的重复利用
第L层的输入直接影响到之后的所有层
第L层的output:
其中是L层之前的feature map以通道的维度合并,每一层都包含之前所有层的输出信息,因此每一层只需要很少的特征图,而不是像其他网络一样动不动就几百上千的宽度。同时这种连接方式使得特征和梯度的传递更加有效,网络也就更加容易训练。
梯度消失问题在网络深度越深的时候越容易出现,原因就是输入信息和梯度信息在很多层之间传递导致的,而现在这种dense connection相当于每一层都直接连接input和loss,因此就可以减轻梯度消失现象,这样更深网络不是问题。
代码
在在conv_block
函数里实现“批量归一化、激活和卷积“结构。
import d2lzh as d2l
from mxnet import gluon, init, nd
from mxnet.gluon import nn
def conv_block(num_channels):
blk = nn.Sequential()
blk.add(nn.BatchNorm(), nn.Activation('relu'),
nn.Conv2D(num_channels, kernel_size=3, padding=1))
return blk
稠密块由多个conv_block
组成,每块使用相同的输出通道数。但在前向计算时,我们将每块的输入和输出在通道维上连结。
class DenseBlock(nn.Block):
def __init__(self, num_convs, num_channels, **kwargs):
super(DenseBlock, self).__init__(**kwargs)
self.net = nn.Sequential()
for _ in range(num_convs):
self.net.add(conv_block(num_channels))
def forward(self, X):
for blk in self.net:
Y = blk(X)
X = nd.concat(X, Y, dim=1) # 在通道维上将输入和输出连结
return X
参考资料:
其他经典网络结构: