欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Mxnet练习: ResNet网络

程序员文章站 2024-03-14 20:46:35
...
   **由于新模型在添加层后可能得出更优的解来拟合训练数据集,因此添加层似乎更容易降低训练误差。然而在实践中,添加过多的层后训练误差往往不降反升。	针对这⼀问题,何恺明等⼈提出了残差⽹络(ResNet)** 

残差块:
左图虚线框中的部分需要直接拟合出该映射f(x),而右图
虚线框中的部分则需要拟合出有关恒等映射的残差映射f(x) − x。

相对左图的优点:
残差映射在实际中往往更容易优化;
当理想映射f(x)极接近于恒等映射时,残差映射也易于捕捉恒等映射的细微波动;
在残差块中,输⼊可通过跨层的数据线路更快地向前传播。
Mxnet练习: ResNet网络
ResNet沿⽤了VGG全3 × 3卷积层的设计。残差块⾥⾸先有2个有相同输出通道数的3 × 3卷积层。每个卷积层后接⼀个批量归⼀化层和ReLU**函数。

残差块的实现:

class Residual(nn.Block):
    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)

ResNet的前两层跟之前介绍的GoogLeNet中的⼀样:在输出通道数为64、步幅为2的7 × 7卷积层后接步幅为2的3 × 3的最⼤池化层。不同之处在于ResNet每个卷积层后增加的批量归⼀化层。

net = nn.Sequential()
net.add(nn.Conv2D(64,kernel_size=7,strides=2,padding=3),
        nn.BatchNorm(),nn.Activation('relu'),
        nn.MaxPool2D(pool_size=3,strides=2,padding=1))

GoogLeNet在后⾯接了4个由Inception块组成的模块。 ResNet则使⽤4个由残差块组成的模块,每个模块使⽤若⼲个同样输出通道数的残差块。第⼀个模块的通道数同输⼊通道数⼀致。由于之前已经使⽤了步幅为2的最⼤池化层,所以⽆须减小⾼和宽。之后的每个模块在第⼀个残差块⾥将上⼀个模块的通道数翻倍,并将⾼和宽减半。

#ResNet则使用4个由残差块组成的模块,每个模块使用若干个同样输出通道数的残差块
def resnet_block(num_channels,num_residuals,first_block=False):
    blk = nn.Sequential()
    for i in range(num_residuals):#num_residual个残差块
        if i==0 and not first_block:
            blk.add(Residual(num_channels,use_1x1conv=True,strides=2))
        else:
            blk.add(Residual(num_channels))
    return blk
#4个代码块,每个代码块2个残差块
net.add(resnet_block(64,2,first_block=True),
        resnet_block(128,2),
        resnet_block(256,2),
        resnet_block(512,2))

#加入全局平均池化层后,接上全连接层输出
net.add(nn.GlobalAvgPool2D(),nn.Dense(10))

每个模块⾥有4个卷积层(不计算1 × 1卷积层),加上最开始的卷积层和最后的全连接层,共计18层。这个模型通常也被称为ResNet-18。