Tensorflow实现ResNet及其原理

本文介绍了ResNet的残差学习模块,通过直接的shortcut或skip connections解决传统深度网络的信息损失问题。ResNet在ILSVRC 2015比赛中表现出色,其152层网络在保持高效的同时,参数量少于VGGNet。文章还讨论了ResNet的不同层级配置,并提供了使用Tensorflow实现ResNet V2的示例。在CPU上运行速度较慢,推荐使用GPU运行。
摘要由CSDN通过智能技术生成

 一、ResNet由微软研究院的Kaiming He等4名华人提出,有152层深的神经网络,在ILSVRC 2015比赛中获得冠军,其top-5错误率为3.57%,但参数量比VGGNet低,可以说效果很好了。ResNet和HighWay Network非常类似,也是允许原始输入信息直接传输到后面的层中,如图1所示,这就是一个ResNet的残差学习单元,ResNet相当于将学习目标改变,不再是学习一个完整的输出H(x),只是输出和输入的差别H(x)-x,即残差。

图1.ResNet的残差学习模块 

我们从图2可以看出普通直连的卷积神经网络和ResNet的最大区别在于,ResNet有很多旁路的支线将输入直接连在后面的层,使得后面的层可以直接学习残差,这种结构也称shortcut或skip connections。传统的卷积层或全连接层在信息传递时,或多或少存在信息丢失,损耗的问题。ResNet在某种程度上解决了这个问题,通过直接将输入信息绕道传到输出,保护信息的完整性,整个网络则只需要学习输入、输出差别的那一部分,简化学习目标和难度。

 

图2.VGGNet-19、34层深的普通卷积神经网络、34层深的ResNet的对比图

除了图1提出的两层学习单元,还有三层的残差学习单元,如图3,两层的残差学习单元包括两个相同输出通道数的3X3卷积。而3层的使用了Network In Network和Inception Net中的1*1的卷积,并且在3*3的前后都使用了1*1卷积,先降维再升维的操作。如果输入和输出的维度不同,可以先对x做一个线性映射变换维度,在连接到后面的层。

图3 两层和三层的ResNet残差学习模块

图4所示的为ResNet在不同层数时的网络配置,其他基本结构很类似,都是前面提到的两层和三层的残差学习单元的堆叠。

下面我们使用Tensorflow实现一个ResNet V2的网络:

#contrib.slim库辅助创建ResNet
import collections
import tensorflow as tf
slim=tf.contrib.slim
from datetime import datetime
import math 
import time
tf.reset_default_graph()#出现后面所示错误所加的
#设计ResNet基本Block模块组的named tuple,并用它创建Block的类
#但只包含数据结构,不包含具体方法
class Block(collections.namedtuple('Block',['scope','unit_fn','args'])):
    'A named tuple describing a ResNet block.'
#定义一个降采样的subsample的方法,factor为采样因子
def subsample(inputs,factor,scope=None):
    if factor==1:
        return inputs
    else:
        return slim.max_pool2d(inputs,[1,1],stride=factor,scope=scope)
#定义一个conv2d_same函数创建卷积层
def conv2d_same(inputs,num_outputs,kernel_size,stride,scope=None):
    if stride==1:
        return slim.conv2d(inputs,num_outputs,kernel_size,stride=1,
                           padding='SAME',scope=scope)
    else:
        pad_total=kernel_size-1
        pad_beg=pad_total//2
        pad_end=pad_total-pad_beg
        inputs=tf.pad(inputs,[[0,0],[pad_beg,pad_end],#用tf.pad对输入变量进行补零操作
                              [pad_beg,pad_end],[0,0]])
        return slim.conv2d(inputs,num_outputs,kernel_size,stride=stride,
                           padding='VALID',scope=scope)
#定义堆叠Blocks的函数,net为输入
#使用两层循环,逐个Block,逐个Residual Unit的堆叠
@slim.add_arg_scope
def stack_blocks_dense(net,blocks,outputs_collections=None):
    for block in blocks:
        with tf.variable_scope(block.scope,'block',[net]) as sc:
            for i,unit in enumerate(block.args):
                with tf.variable_scope('unit_%d' % (i+1),values=[net]):
                    unit_depth,unit_depth_bottleneck,unit_stride=unit
                    net=block.unit_fn(net,#顺序的创建并连接所有的残差学习单元
                                     depth=unit_depth,
                                     depth_bottleneck=unit_depth_bottleneck,
                                     stride=unit_stride)
            net=slim.utils.collect_named_outputs(outputs_collections,sc.name,net)
    return net
#创建arg_scope,用于定义某些函数的参数默认值
def resnet_arg_scope(is_training=True,
                     weight_decay=0.0001,
                     batch_norm_decay=0.997,
                     batch_norm_epsilon=1e-5,
                     batch_norm_scale=T
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值