用tensorflow实现一个简单的ResNet,体会ResNet的简单有效。

完整代码已经放置在GitHub:https://github.com/colin0000007/Simple-ResNet

ResNet全称residual neural network。主要是解决过深的网络带来的梯度弥散,梯度爆炸,网络退化的问题。

下面是ResNet一个单元的结构,单元中有多少个layer应该是我们自己决定。

从图片中很容易看出ResNet做了什么,就只是把输入x和网络的输出f(x)加了起来。但这种方式却是简单有效的。我在实验中堆叠了100层的全连接网络,如果不做这个x+f(x)操作,网络直接训练不起来。后面我会再给出具体的实验结果。

那么如何从原理上解释ResNet呢?(摘自知乎,侵权删

(1)

网络输入是x,网络的输出是F(x),网络要拟合的目标是H(x),传统网络的训练目标是F(x)=H(x)。残差网络,则是把传统网络的输出F(x)处理一下,加上输入,将F(x)+x作为最终的输出,训练目标是F(x)=H(x)-x,H(x) = F(x)+x,因此得名残差网络。现在我们要训练一个深层的网络,它可能过深,假设存在一个性能最强的完美网络N,与它相比我们的网络中必定有一些层是多余的那么这些多余的层的训练目标是恒等变换,只有达到这个目标我们的网络性能才能跟N一样。对于这些需要实现恒等变换的多余的层,要拟合的目标就成了H(x)=x在传统网络中,网络的输出目标是F(x)=x,这比较困难,而在残差网络中,拟合的目标成了x-x=0网络的输出目标为F(x)=0,这比前者要容易得多。最后总结并回答题主的问题:resnet的F(x)长什么样?就是传统网络的输出F(x)加上输入x:F(x)+x为什么是x而不是其他?因为多余的层的目标是恒等变换,即F(x)+x=x,那F(x)的训练目标就是0,比较容易。如果是其他,比如x/2,那F(x)的训练目标就是x/2,是一个非0的值,比0难实现。

(2)

F是求和前网络映射,H是从输入到求和后的网络映射。比如把5映射到5.1,那么引入残差前是F'(5)=5.1,引入残差后是H(5)=5.1, H(5)=F(5)+5, F(5)=0.1。这里的F'和F都表示网络参数映射,引入残差后的映射对输出的变化更敏感。比如s输出从5.1变到5.2,映射F'的输出增加了1/51=2%,而对于残差结构输出从5.1到5.2,映射F是从0.1到0.2,增加了100%。明显后者输出变化对权重的调整作用更大,所以效果更好。残差的思想都是去掉相同的主体部分,从而突出微小的变化

理论部分差不多就是这些,对,ResNet就是这么简单。下面看看我自己做的实验。

我直接使用了最简单的全连接层。堆叠了50个resNet block,每个block由2个全连接层组成。共102层全连接神经网络。由于加操作,所以输入x的维度要和网络输出f(x)保持一致,这里简单的粗暴的设置了一样的units。

每个block就是把输入x和网络输出f(x)加起来再送到激活函数中。

def resNet_block_with_two_layer(units,inputs,activation_function ="relu"):
    if activation_function == None:
        raise Exception("activation function can't be None")
    activation_function = activation_function.strip().lower()
    if activation_function != "relu" and activation_function != "sigmoid":
        raise Exception("Unsupported activation function, only 'sigmoid' or 'relu' are Candidate")
    if inputs.shape[1] != units:
        raise Exception("the rank 2 of inputs must equal units")
    d1_output = dense_layer(units, units, inputs, activation_function)
    d2_output = dense_layer(units, units, d1_output, activation_function = None)
    #ResNet的体现,先相加再送入到激活函数
    #H(x) = f(x) + x,使得训练的目标f(x) = H(x) - x即残差
    d2_output = d2_output + inputs
    if activation_function == "sigmoid":
        d2_output = tf.nn.sigmoid(d2_output)
    else:
        d2_output = tf.nn.relu(d2_output)
    return d2_output

有一个问题需要注意的是,由于网络很深,前向传播过程值不断变大,送到softmax中有指数会使得值为无穷,所以权重矩阵W初始时设置为stddev=0.01

直接训练后的结果:

去掉x+f(x)的操作也就是代码中的d2_output = d2_output + inputs

可以看到去掉后模型直接崩了。

尽管可以看到ResNet确实很有效果,但正如前面理论所说模型相当于丢掉了一些层,使得f(x) = 0,这让我觉得和更浅层的网络没有太大差别,当然这一点我并没有去考证,做实验对比。看到有人说 “ResNet Unit成功训练出了152层的神经网络,并在ILSVRC2015比赛中取得冠军,在top5上的错误率为3.57%,同时参数量比VGGNet低,效果非常突出。”。 可能对于卷积更有用,卷积层更深越能提取特征。

 

 

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值