卷积神经网络之残差网络ResNet详解

理论上,在网络中添加新的层得到的新模型可能会更好地拟合训练数据集,因此添加层似乎更容易降低训练误差。然而在事件中,添加过多的层后训练误差反而会升高。针对这一问题,何凯明团队于2015年提出了残差网络(ResNet)在一定程度上解决了这一问题。

残差块

如下图所示,输入为x,理想映射为f(x)。

左图需要直接拟合出该映射f(x),右图则需要拟合出残差映射f(x)-x。残差映射在实际中往往更容易优化。

右图是ResNet的基础块(残差块Residual block)。残差块中,输入可通过跨层的数据线路更快向前传播。

 

残差块的组成:

两个有相同输出通道的卷积层,将输入跳过这两个卷积运算后直接加在最后的Relu前。

现在我们会得到一个H(x)=f(x)+x,我们需要f(x)=H(x)-x,

通过训练参数,得到H(x)-x,即残差,这样要比学习H(x)简单得多。

瓶颈(BottleNeck)模块

瓶颈是指block的输入和输出的通道数一样,再block中间的通道数是小于输入或输出,即采用先降维再升维。

比如右图的带瓶颈模块共使用参数个数:1*1*256*64+3*3*64*64+1*1*64*256=69632

未使用瓶颈共需要参数:3*3*256*256*2=1179648

很明显数据量减少了很多。

代码


import d2lzh as d2l
from mxnet import gluon, init, nd
from mxnet.gluon import nn

class Residual(nn.Block):  # 本类已保存在d2lzh包中方便以后使用
    def __init__(self, num_channels, use_1x1conv=False, strides=1, **kwargs):
        super(Residual, self).__init__(**kwargs)
        self.conv1 = nn.Conv2D(num_channels, kernel_size=3, padding=1,
                               strides=strides)
        self.conv2 = nn.Conv2D(num_channels, kernel_size=3, padding=1)
        if use_1x1conv:
            self.conv3 = nn.Conv2D(num_channels, kernel_size=1,
                                   strides=strides)
        else:
            self.conv3 = None
        self.bn1 = nn.BatchNorm()
        self.bn2 = nn.BatchNorm()

    def forward(self, X):
        Y = nd.relu(self.bn1(self.conv1(X)))
        Y = self.bn2(self.conv2(Y))
        if self.conv3:
            X = self.conv3(X)
        return nd.relu(Y + X)

残差网络的背后原理

详见:详解残差网络

参考资料:<<动手学深度学习>>

其他经典网络结构:

卷积神经网络之 LeNet卷积神经网络之(稠密连接网络)DenseNet

卷积神经网络之(深度卷积神经网络)AlexNet

卷积神经网络之(使用重复元素的网络)VGG

卷积神经网络之残差网络ResNet详解

本文地址:https://blog.csdn.net/qq_36766560/article/details/110672378