Press "Enter" to skip to content

MXNet实现ResNet(残差网络)深度神经网络模型

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

深度在神经网络中是一个非常重要的因素,但存在一个当层数特别深的时候,出现 “退化” 的问题(实验部分中的34层相比较18层的网络,有着更高的验证误差),这个不属于“过拟合”,也不是所谓的梯度消失,因为使用了批量归一化操作,确保了参数在正向传播的时候不会出现为0方差的情况,同样也验证了模型在反向传播的过程中所展示出来的梯度是健康的。

 

于是在2015年提出的这个残差网络设想,很好的解决了层深的问题,甚至实验到了1000层。关于复杂度,论文指出了152层的残差网络(113亿浮点运算次数)仍然有着比VGG16/19(153/196亿次浮点运算次数)更小的时间复杂度,这个也是另一大优点。另外还有一个“瓶颈”设计,使得64维到256维的投影,使其复杂度却差不多。

 

这里也跟其他模型一样,同 MXNet对GoogLeNet的实现(并行连结网络)  里面的 Inception块 和 MXNet对VGGNet的实现(3*3卷积核的重复运用) 里面的 VGG块 ,构造一个残差块,如下图:

 

 

图中右边可以看出,输入的x通过跨层直接作为了下一个激活函数的输入,这种跳过多层的设计使得更快地向前传播,当理想映射f(x)极接近于恒等映射时,残差映射也易于捕捉恒等映射的细微波动。那幺这个理想映射在下一个激活函数之前就成为了一个f(x)+x的输入值了。

 

现在我们的ResNet还是沿用前面介绍过的VGG全3×3卷积层的设计,看下图:

 

 

import d2lzh as d2l
from mxnet import gluon,init,nd
from mxnet.gluon import nn
#残差块
#已在d2lzh包有定义
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)
        #是否有1x1卷积层来修改通道数以及卷积层的步幅
        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)
    
#观察使用1x1卷积前后的输入输出形状
blk=Residual(3)
blk.initialize()
X=nd.random.uniform(shape=(4,3,6,6))
print(blk(X).shape)#输入输出形状一致(4, 3, 6, 6)
blk2=Residual(6,use_1x1conv=True,strides=2)
blk2.initialize()
print(blk2(X).shape)#通道数改变,高宽减半(4, 6, 3, 3)

 

可以看出这个跟上面图中所示,输入值X直接跳过跟经过卷积-批量归一化等操作,然后与这些加权等操作之后的Y相加,然后再输入到激活函数中。

 

了解了残差块之后,我们来构建ResNet模型,跟前面提到的GoogLeNet模型类似,只是增加了一个BN层,以及将Inception块替换成残差块。

 

#构造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))
#对第一个模型做特别处理
def resnet_block(num_channels,num_residuals,first_block=False):
    blk=nn.Sequential()
    for i in range(num_residuals):
        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
#加入残差块,每个模块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))
#观察形状的变化
X=-nd.random.uniform(shape=(1,1,224,224))
net.initialize()
for layer in net:
    X=layer(X)
    print(layer.name,'shape:',X.shape)
    
'''
conv33 shape: (1, 64, 112, 112)
batchnorm27 shape: (1, 64, 112, 112)
relu0 shape: (1, 64, 112, 112)
pool0 shape: (1, 64, 56, 56)
sequential1 shape: (1, 64, 56, 56)
sequential2 shape: (1, 128, 28, 28)
sequential3 shape: (1, 256, 14, 14)
sequential4 shape: (1, 512, 7, 7)
pool1 shape: (1, 512, 1, 1)
dense0 shape: (1, 10)
'''

 

开始训练模型,还是以Fashion-MNIST数据集为例,由于本人内存资源受限,将批处理大小256下调到50,这个取决于自己的计算机资源

 

lr,num_epochs,batch_size,ctx=0.05,5,50,d2l.try_gpu()
net.initialize(force_reinit=True,ctx=ctx,init=init.Xavier())
trainer=gluon.Trainer(net.collect_params(),'sgd',{'learning_rate':lr})
train_iter,test_iter=d2l.load_data_fashion_mnist(batch_size,resize=96)
d2l.train_ch5(net,train_iter,test_iter,batch_size,trainer,ctx,num_epochs)
'''
epoch 1, loss 0.3976, train acc 0.859, test acc 0.895, time 124.1 sec
epoch 2, loss 0.2347, train acc 0.913, test acc 0.903, time 122.9 sec
epoch 3, loss 0.1829, train acc 0.932, test acc 0.887, time 123.1 sec
epoch 4, loss 0.1433, train acc 0.948, test acc 0.916, time 123.0 sec
epoch 5, loss 0.1113, train acc 0.959, test acc 0.921, time 123.0 sec
'''

 

在训练的时候,往往个人由于资源受限,很容易出现内存溢出,可以将batch_size调下来或图片调小等来训练,我们主要是学习论文所表达的设计思想。

 

mxnet.base.MXNetError: [12:10:21] c:\jenkins\workspace\mxnet-tag\mxnet\src\storage\./pooled_storage_manager.h:157: cudaMalloc failed: out of memory
mxnet.base.MXNetError: [12:17:38] c:\jenkins\workspace\mxnet-tag\mxnet\3rdparty\mshadow\mshadow\./stream_gpu-inl.h:62: Check failed: e == cudaSuccess: CUDA: an illegal memory access was encountered

Be First to Comment

发表评论

您的电子邮箱地址不会被公开。