ResNet是2015年ImageNet比赛的冠军,将识别错误率降低到了3.6%,这个结果甚至超出了正常人眼识别的精度。
在神经网络模型的发展中,模型的层数逐渐增多,但是在增加模型层数后对应的训练误差并没有一直减小,反而出现了训练误差不降反升的现象。
因此提出了残差网络ResNet来解决这个问题。
ResNet的思想模型:
原模型为y=F(x)表示增加网络时将x映射成y=F(x)输出,但是对原模型改进为y=F(x)+x,只要将x的参数设为0,则与原模型一致。改进后F(x)=y-x,叫做残差项。
2.残差单元的构建
在构建残差单元时通过在进入指定卷积层如3*3的卷积层之前利用1*1的卷积层处理来减少通道数,然后在经过该3*3卷积层之后再通过一个1*1的卷积层来恢复通道数。先这样256->64->256这样类似一个瓶颈的形状,所以被称为“BottleNeck”。
首先要构建一个卷积批归一化块ConvBNLayer包含卷积层和BatchNorm层。
- def __init__(self,
- num_channels,
- num_filters,
- filter_size,
- stride=1,
- groups=1,
- act=None):
- super(ConvBNLayer, self).__init__()
- # 创建卷积层
- self._conv = nn.Conv2D(
- in_channels=num_channels,
- out_channels=num_filters,
- kernel_size=filter_size,
- stride=stride,
- padding=(filter_size - 1) // 2,
- groups=groups,
- bias_attr=False)
通过初始化函数_init_来接受了了一些参数 num_channels,(卷积层的输入通道数)num_filters,(卷积层的输出通道数),stride(卷积层的步幅)groups(分组卷积的组数)然后用这些数据构建了一个二维卷积层
- self._batch_norm = paddle.nn.BatchNorm2D(num_filters)
- self.act = act
接着创建了一个BatchNorcm2D层对卷积层的输出进行批归一化操作。
- def forward(self, inputs):
- y = self._conv(inputs)
- y = self._batch_norm(y)
- if self.act == 'leaky':
- y = F.leaky_relu(x=y, negative_slope=0.1)
- elif self.act == 'relu':
- y = F.relu(x=y)
- return y
在传播函数forward中,它首先将输入inputs通过卷积层和批归一化层进行计算,并将结果保存到变量y中。然后根据激活函数类型act的不同选择使用LeakyReLU或ReLU函数对y进行激活。最后返回激活后的结果y。
卷积批归一化块ConvBNLayer构建完成后,就可以定义残差块BottleneckBlock:
首先初始化函数,用来接收参数num_channels(输入通道数),num_filters(卷积核步数),stride(步长),shortcut=True
- def __init__(self,
- num_channels,
- num_filters,
- stride,
- shortcut=True):
- super(BottleneckBlock, self).__init__()
然后分别创建三个卷积层:
- # 创建第一个卷积层 1x1
- self.conv0 = ConvBNLayer(
- num_channels=num_channels,
- num_filters=num_filters,
- filter_size=1,