各种层数的残差网络:

34-layer的残差网络结构:

ResNet 的核心结构——bottleneck残差模块

在通道数相同情况下,bottleneck残差模块要比朴素残差模块节省大量的参数,一个单元内的参数少了,就可以做出更深的结构。从上面两个图可以看到,bottleneck残差模块将两个3*3换成了1*1、3*3、1*1的形式,这就达到了减少参数的目的。和Inception中的1*1卷积核作用相同。

这种结构也称为 shortcut 或 skip connection。

# -*- coding:UTF-8 -*-import collections
import tensorflow as tffrom tf.contrib.layers.python.layers import utilsslim = tf.contrib.slimclass Block(collections.namedtuple('Block', ['scope', 'unit_fn', 'args'])):'''使用collections.namedtuple设计ResNet基本block模块组的named tuple,定义一个典型的Block需要输入三个参数:scope:  Block的名称unit_fn:ResNet V2中的残差学习单元 args:   它决定该block有几层,格式是[(depth, depth_bottleneck, stride)]示例:Block('block1', bottleneck, [(256,64,1),(256,64,1),(256,64,2)])'''def subsample(inputs, factor, scope=None): if factor == 1:return inputselse:return slim.max_pool2d(inputs, [1, 1], stride=factor, scope=scope)def conv2d_same(inputs, num_outputs, kernel_size, stride, scope=None): """if stride>1, then we do explicit zero-padding, followed by conv2d with 'VALID' padding"""if stride == 1:return slim.conv2d(inputs, num_outputs, kernel_size, stride=1, padding='SAME', scope=scope)else:pad_total = kernel_size - 1pad_beg = pad_total // 2pad_end = pad_total - pad_beginputs = tf.pad(inputs, [[0, 0], [pad_beg, pad_end], [pad_beg, pad_end], [0, 0]])return slim.conv2d(inputs, num_outputs, kernel_size, stride=stride, padding='VALID', scope=scope)#---------------------定义堆叠Blocks的函数-------------------
@slim.add_arg_scope
def stack_blocks_dense(net, blocks, outputs_collections=None):"""Args:net: A Tensor of size [batch, height, width, channels].输入blocks: 是之前定义的Block的class的列表。outputs_collections: 收集各个end_points的collectionsReturns:net: Output tensor"""# 循环Block类对象的列表blocks,即逐个Residual Unit地堆叠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 = unitnet = block.unit_fn(net, depth=unit_depth, depth_bottleneck=unit_depth_bottleneck,stride=unit_stride)net = utils.collect_named_outputs(outputs_collections, sc.name, net)return net# 创建ResNet通用的arg_scope,arg_scope用来定义某些函数的参数默认值
def resnet_arg_scope(is_training=True,  # 训练标记weight_decay=0.0001,  # 权重衰减速率batch_norm_decay=0.997,  # BN的衰减速率batch_norm_epsilon=1e-5,  #  BN的epsilon默认1e-5batch_norm_scale=True):  # BN的scale默认值batch_norm_params = { # 定义batch normalization(标准化)的参数字典'is_training': is_training,'decay': batch_norm_decay,'epsilon': batch_norm_epsilon,'scale': batch_norm_scale,'updates_collections': tf.GraphKeys.UPDATE_OPS,}with slim.arg_scope( # 通过slim.arg_scope将[slim.conv2d]的几个默认参数设置好[slim.conv2d],weights_regularizer=slim.l2_regularizer(weight_decay), # 权重正则器设置为L2正则 weights_initializer=slim.variance_scaling_initializer(), # 权重初始化器activation_fn=tf.nn.relu, # 激活函数normalizer_fn=slim.batch_norm, # 标准化器设置为BNnormalizer_params=batch_norm_params):with slim.arg_scope([slim.batch_norm], **batch_norm_params):with slim.arg_scope([slim.max_pool2d], padding='SAME') as arg_sc:return arg_sc # 最后将基层嵌套的arg_scope作为结果返回#------------------定义核心的bottleneck残差学习单元--------------------
@slim.add_arg_scope
def bottleneck(inputs, depth, depth_bottleneck, stride,outputs_collections=None, scope=None):"""Args:inputs: A tensor of size [batch, height, width, channels].depth、depth_bottleneck:、stride三个参数是前面blocks类中的argsrate: An integer, rate for atrous convolution.outputs_collections: 是收集end_points的collection"""with tf.variable_scope(scope, 'bottleneck_v2', [inputs]) as sc: depth_in = utils.last_dimension(inputs.get_shape(), min_rank=4) #最后一个维度,即输出通道数preact = slim.batch_norm(inputs, activation_fn=tf.nn.relu, scope='preact') if depth == depth_in:# 如果残差单元的输入通道数和输出通道数一致,那么按步长对inputs进行降采样shortcut = subsample(inputs, stride, 'shortcut')else:# 如果不一样就按步长和1*1的卷积改变其通道数,使得输入、输出通道数一致shortcut = slim.conv2d(preact, depth, [1, 1], stride=stride,normalizer_fn=None, activation_fn=None,scope='shortcut')# 先是一个1*1尺寸,步长1,输出通道数为depth_bottleneck的卷积residual = slim.conv2d(preact, depth_bottleneck, [1, 1], stride=1, scope='conv1')# 然后是3*3尺寸,步长为stride,输出通道数为depth_bottleneck的卷积residual = conv2d_same(residual, depth_bottleneck, 3, stride, scope='conv2')# 最后是1*1卷积,步长1,输出通道数depth的卷积,得到最终的residual。最后一层没有正则项也没有激活函数residual = slim.conv2d(residual, depth, [1, 1], stride=1,normalizer_fn=None, activation_fn=None,scope='conv3')# 将降采样的结果和residual相加output = shortcut + residualreturn utils.collect_named_outputs(outputs_collections, sc.name, output)#-------------------定义生成resnet_v2网络的主函数------------------def resnet_v2(inputs, blocks, num_classes=None, global_pool=True, include_root_block=True, reuse=None, scope=None):with tf.variable_scope(scope, 'resnet_v2', [inputs], reuse=reuse) as sc:end_points_collection = sc.original_name_scope + '_end_points'with slim.arg_scope([slim.conv2d, bottleneck, stack_blocks_dense],outputs_collections=end_points_collection):net = inputsif include_root_block: # 根据标记值,创建resnet最前面的64输出通道的步长为2的7*7卷积,然后接最大池化with slim.arg_scope([slim.conv2d], activation_fn=None, normalizer_fn=None):net = conv2d_same(net, 64, 7, stride=2, scope='conv1')net = slim.max_pool2d(net, [3, 3], stride=2, scope='pool1')# 经历过两个步长为2的层图片缩为1/4net = stack_blocks_dense(net, blocks) # 将残差学习模块组生成好net = slim.batch_norm(net, activation_fn=tf.nn.relu, scope='postnorm')if global_pool:net = tf.reduce_mean(net, [1, 2], name='pool5', keep_dims=True) # tf.reduce_mean实现全局平均池化效率比avg_pool高if num_classes is not None:  # 是否有通道数net = slim.conv2d(net, num_classes, [1, 1], activation_fn=None, # 无激活函数和正则项normalizer_fn=None, scope='logits') # 添加一个输出通道num_classes的1*1的卷积end_points = utils.convert_collection_to_dict(end_points_collection) # 将collection转化为python的dictif num_classes is not None:end_points['predictions'] = slim.softmax(net, scope='predictions') # 输出网络结果return net, end_points#-------------------建立模型 ResNet-50/101/152/200 model--------------------def resnet_v2_50(inputs, num_classes=None, global_pool=True, reuse=None,scope='resnet_v2_50'):blocks = [Block('block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]),# Args::# 'block1':Block名称(或scope)# bottleneck:ResNet V2残差学习单元# [(256, 64, 1)] * 2 + [(256, 64, 2)]:Block的Args,Args是一个列表。其中每个元素都对应一个bottleneck#                                     前两个元素都是(256, 64, 1),最后一个是(256, 64, 2)。每个元素#                                     都是一个三元tuple,即(depth,depth_bottleneck,stride)。# (256, 64, 3)代表构建的bottleneck残差学习单元(每个残差学习单元包含三个卷积层)中,第三层输出通道数# depth为256,前两层输出通道数depth_bottleneck为64,且中间那层步长3。这个残差学习单元结构为:# [(1*1/s1,64),(3*3/s2,64),(1*1/s1,256)]Block('block2', bottleneck, [(512, 128, 1)] * 3 + [(512, 128, 2)]),Block('block3', bottleneck, [(1024, 256, 1)] * 5 + [(1024, 256, 2)]),Block('block4', bottleneck, [(2048, 512, 1)] * 3)]return resnet_v2(inputs, blocks, num_classes, global_pool,include_root_block=True, reuse=reuse, scope=scope)def resnet_v2_101(inputs, num_classes=None, global_pool=True, reuse=None,scope='resnet_v2_101'):"""ResNet-101 model of [1]. See resnet_v2() for arg and return description."""blocks = [Block('block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]),Block('block2', bottleneck, [(512, 128, 1)] * 3 + [(512, 128, 2)]),Block('block3', bottleneck, [(1024, 256, 1)] * 22 + [(1024, 256, 2)]),Block('block4', bottleneck, [(2048, 512, 1)] * 3)]return resnet_v2(inputs, blocks, num_classes, global_pool,include_root_block=True, reuse=reuse, scope=scope)# unit提升的主要场所是block3
def resnet_v2_152(inputs, num_classes=None, global_pool=True, reuse=None,scope='resnet_v2_152'):"""ResNet-152 model of [1]. See resnet_v2() for arg and return description."""blocks = [Block('block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]),Block('block2', bottleneck, [(512, 128, 1)] * 7 + [(512, 128, 2)]),Block('block3', bottleneck, [(1024, 256, 1)] * 35 + [(1024, 256, 2)]),Block('block4', bottleneck, [(2048, 512, 1)] * 3)]return resnet_v2(inputs, blocks, num_classes, global_pool,include_root_block=True, reuse=reuse, scope=scope)# unit提升的主要场所是block2
def resnet_v2_200(inputs, num_classes=None, global_pool=True, reuse=None,scope='resnet_v2_200'):"""ResNet-200 model of [2]. See resnet_v2() for arg and return description."""blocks = [Block('block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]),Block('block2', bottleneck, [(512, 128, 1)] * 23 + [(512, 128, 2)]),Block('block3', bottleneck, [(1024, 256, 1)] * 35 + [(1024, 256, 2)]),Block('block4', bottleneck, [(2048, 512, 1)] * 3)]return resnet_v2(inputs, blocks, num_classes, global_pool,include_root_block=True, reuse=reuse, scope=scope)

神经网络之ResNet模型的实现(Python+TensorFlow)相关推荐

  1. 基于回归神经网络的中文语句模型实践(Python+Tensorflow+阿里云)

    回归神经网络(Recurrent neural network)在机器学习领域取得了非凡的成就.因其模型特征尤其适合于具有序列特性的数据,所以在自然语言建模,机器翻译,语音识别等领域表现尤其不俗. 语 ...

  2. python tensorflow web_如何在浏览器中使用TensorFlow?

    原标题:如何在浏览器中使用TensorFlow? 虽然您可以借助TensorFlow用数量较少的训练数据来训练简单的神经网络,但对于拥有庞大训练数据集的深度神经网络而言,确实需要使用具有CUDA功能的 ...

  3. tensorflow保存模型和加载模型的方法(Python和Android)

    tensorflow保存模型和加载模型的方法(Python和Android) 一.tensorflow保存模型的几种方法: (1) tf.train.saver()保存模型 使用 tf.train.s ...

  4. 【TensorFlow实战】TensorFlow实现经典卷积神经网络之ResNet

    ResNet ResNet(Residual Neural Network)通过使用Residual Unit成功训练152层深的神经网络,在ILSVRC 2015比赛中获得冠军,取得3.57%的to ...

  5. Python银行风控模型的建立 SVM 决策树 神经网络 三种模型比较

    一.首先要感谢原作者的无私分享 原文网页链接: Python银行风控模型的建立_DG息的博客-CSDN博客_银行风控模型 首先感谢"Python银行风控模型的建立"()这位老师,他 ...

  6. Tensorflow BP神经网络多输出模型在生产管理中应用实践

    本文以某企业组织建设为研究对象,采用大数据神经网络算法中的BP算法, 基于该算法建立了企业组织建设评价模型,最后基于Tensorflow的神经网络开发包实现模型并训练.根据评价结果可评价企业组织建设状 ...

  7. Python TensorFlow循环神经网络RNN-LSTM神经网络预测股票市场价格时间序列和MSE评估准确性...

    全文链接:http://tecdat.cn/?p=26562 该项目包括: 自 2000 年 1 月以来的股票价格数据.我们使用的是 Microsoft 股票. 将时间序列数据转换为分类问题. 使用 ...

  8. Tensorflow实例:(卷积神经网络)LeNet-5模型

    通过卷积层.池化层等结构的任意组合得到的神经网络有无限多种,怎样的神经网络更有可能解决真实的图像处理问题?本文通过LeNet-5模型,将给出卷积神经网络结构设计的一个通用模式. LeNet-5模型 L ...

  9. c语言调用tensorflow模型,C++调用Python中的Tensorflow模型

    C++调用Python中的Tensorflow模型 利用c++调用Python2.7的程序,加载tensorflow模型(为什么不使用Python3,坑太多了,一直解决不好).整个环境在Ubuntu1 ...

最新文章

  1. 15 个 JavaScript Web UI 库
  2. proc文件系统编程
  3. C#机房重构-总结(二)
  4. mysql-5.7.20实用下载、安装和配置方法,以及简单操作
  5. android 直播 app下载地址,蓝泡泡直播
  6. mysql 两列数据互换_mysql 实现互换表中两列数据方法简单实例
  7. LeetCode之两数相加
  8. kill 进程_如何查杀stopped进程
  9. $.grep()函数
  10. 读《大道至简》第三章 有感
  11. 【TWVRP】基于matlab遗传和模拟退火算法求解带时间窗的取送货问题【含Matlab源码 1139期】
  12. RGB和CMYK配色表
  13. java中像scanf一样多个输入_VB模拟键盘输入的N种方法
  14. okhttp使用总结
  15. 流水作业调度(动态规划)
  16. 利用Matlab进行高斯消元法
  17. 根据需求,完成如下代码(按照标准格式写),并在测试类中进行测试?
  18. 电脑卡死、死机、黑屏怎么办?驱动人生教你如何解决
  19. 【Pandas总结】第一节 Pandas 简介与Series,DataFrame的创建
  20. php服务宕机,PHP漏洞|一张GIF图片就能让服务器宕机的PHP漏洞

热门文章

  1. 今日头条2019Java开发面试
  2. 王飞跃:产业突围还是产业革命?
  3. Java 有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位
  4. SSO单点登录详解-------二、单点登录流程解析
  5. 牵手,只为来生的相聚
  6. WinFrom中实现点击关闭按钮窗口在靠屏幕左边中间缓缓收缩
  7. 产品面试常见问题和解读(一)
  8. python文本统计单词_Python实现文本单词统计
  9. 第3章 SQL 语法
  10. C语言 char*和char[]用法