残差网络ResNet网络原理及实现


全文共1483字,5张图,预计阅读时间10分钟。

作者介绍:

石晓文,中国人民大学信息学院在读研究生,美团外卖算法实习生

简书ID:石晓文的学习日记(https://www.jianshu.com/u/c5df9e229a67)

天善社区:https://www.hellobi.com/u/58654/articles

腾讯云:https://cloud.tencent.com/developer/user/1622140

开发者头条:https://toutiao.io/u/470599


论文地址:https://arxiv.org/pdf/1512.03385.pdf


引言-深度网络的退化问题


在深度神经网络训练中,从经验来看,随着网络深度的增加,模型理论上可以取得更好的结果。但是实验却发现,深度神经网络中存在着退化问题(Degradation problem)。可以看到,在下图中56层的网络比20层网络效果还要差。


残差网络ResNet网络原理及实现_第1张图片


上面的现象与过拟合不同,过拟合的表现是训练误差小而测试误差大,而上面的图片显示训练误差和测试误差都是56层的网络较大。


深度网络的退化问题至少说明深度网络不容易训练。我们假设这样一种情况,56层的网络的前20层和20层网络参数一模一样,而后36层是一个恒等映射( identity mapping),即输入x输出也是x,那么56层的网络的效果也至少会和20层的网络效果一样,可是为什么出现了退化问题呢?因此我们在训练深层网络时,训练方法肯定存在的一定的缺陷。


正是上面的这个有趣的假设,何凯明博士发明了残差网络ResNet来解决退化问题!让我们来一探究竟!


ResNet网络结构


ResNet中最重要的是残差学习单元:


残差网络ResNet网络原理及实现_第2张图片



对于一个堆积层结构(几层堆积而成)当输入为x时其学习到的特征记为H(x),现在我们希望其可以学习到残差F(x)=H(x)-x,这样其实原始的学习特征是F(x)+x 。当残差为0时,此时堆积层仅仅做了恒等映射,至少网络性能不会下降,实际上残差不会为0,这也会使得堆积层在输入特征基础上学习到新的特征,从而拥有更好的性能。一个残差单元的公式如下:

残差网络ResNet网络原理及实现_第3张图片


后面的x前面也需要经过参数Ws变换,从而使得和前面部分的输出形状相同,可以进行加法运算。


在堆叠了多个残差单元后,我们的ResNet网络结构如下图所示:

残差网络ResNet网络原理及实现_第4张图片


ResNet代码实战


我们来实现一个mnist手写数字识别的程序。代码中主要使用的是tensorflow.contrib.slim中定义的函数,slim作为一种轻量级的tensorflow库,使得模型的构建,训练,测试都变得更加简单。卷积层、池化层以及全联接层都可以进行快速的定义,非常方便。这里为了方便使用,我们直接导入slim。


import tensorflow.contrib.slim as slim


我们主要来看一下我们的网络结构。首先定义两个残差结构,第一个是输入和输出形状一样的残差结构,一个是输入和输出形状不一样的残差结构。


下面是输入和输出形状相同的残差块,这里slim.conv2d函数的输入有三个,分别是输入数据、卷积核数量、卷积核的大小,默认的话padding为SAME,即卷积后形状不变,由于输入和输出形状相同,因此我们可以在计算outputs时直接将两部分相加。


def res_identity(input_tensor,conv_depth,kernel_shape,layer_name):
with tf.variable_scope(layer_name):
relu = tf.nn.relu(slim.conv2d(input_tensor,conv_depth,kernel_shape))
outputs = tf.nn.relu(slim.conv2d(relu,conv_depth,kernel_shape) + input_tensor)
return outputs


下面是输入和输出形状不同的残差块,由于输入和输出形状不同,因此我们需要对输入也进行一个卷积变化,使二者形状相同。ResNet作者建议可以用1*1的卷积层,stride=2来进行变换:

def res_change(input_tensor,conv_depth,kernel_shape,layer_name):
with tf.variable_scope(layer_name):
relu = tf.nn.relu(slim.conv2d(input_tensor,conv_depth,kernel_shape,stride=2))
input_tensor_reshape = slim.conv2d(input_tensor,conv_depth,[1,1],stride=2)
outputs = tf.nn.relu(slim.conv2d(relu,conv_depth,kernel_shape) + input_tensor_reshape)
return outputs


最后是整个网络结构,对于x的输入,我们先进行一次卷积和池化操作,然后接入四个残差块,最后接两层全联接层得到网络的输出。


def inference(inputs):
x = tf.reshape(inputs,[-1,28,28,1])
conv_1 = tf.nn.relu(slim.conv2d(x,32,[3,3])) #28 * 28 * 32
pool_1 = slim.max_pool2d(conv_1,[2,2]) # 14 * 14 * 32
block_1 = res_identity(pool_1,32,[3,3],'layer_2')
block_2 = res_change(block_1,64,[3,3],'layer_3')
block_3 = res_identity(block_2,64,[3,3],'layer_4')
block_4 = res_change(block_3,32,[3,3],'layer_5')
net_flatten = slim.flatten(block_4,scope='flatten')
fc_1 = slim.fully_connected(slim.dropout(net_flatten,0.8),200,activation_fn=tf.nn.tanh,scope='fc_1')
output = slim.fully_connected(slim.dropout(fc_1,0.8),10,activation_fn=None,scope='output_layer')
return output


完整的代码地址在:https://github.com/princewen/tensorflow_practice/tree/master/CV/ResNet


参考方式


1、论文:https://arxiv.org/pdf/1512.03385.pdf


2、https://blog.csdn.net/kaisa158/article/details/81096588?utm_source=blogxgwz4


原文链接:https://mp.weixin.qq.com/s/AsCF4dsuS-XTF1Yr_tKKTQ


查阅更为简洁方便的分类文章以及最新的课程、产品信息,请移步至全新呈现的“LeadAI学院官网”:

www.leadai.org


请关注人工智能LeadAI公众号,查看更多专业文章

640?wx_fmt=jpeg

大家都在看

640.png?

LSTM模型在问答系统中的应用

基于TensorFlow的神经网络解决用户流失概览问题

最全常见算法工程师面试题目整理(一)

最全常见算法工程师面试题目整理(二)

TensorFlow从1到2 | 第三章 深度学习革命的开端:卷积神经网络

装饰器 | Python高级编程

今天不如来复习下Python基础

你可能感兴趣的:(残差网络ResNet网络原理及实现)