ResNet中的tf.variable scope_scope函数使用

后使用快捷导航没有帐号?
致力于提供软件新闻发布,和软件知识学习,包括常用软件应用技巧及评测,创意设计相关的图文及视频教程
0 阅读|294 浏览
0 阅读|71 浏览
0 阅读|61 浏览
0 阅读|197 浏览
TensorFlow实现ResNet(ResNet 152网络结构的forward耗时检测)
结构有ResNet 50、ResNet 152、ResNet 200,考虑耗时原因只跑了ResNet 152网络结构的forward。
# inputs has shape [batch, 224, 224, 3]
with slim.arg_scope(resnet_v2.resnet_arg_scope(is_training)):
net, end_points = resnet_v2.resnet_v2_101(inputs, 1000)
ResNet-101 for semantic segmentation into 21 classes:
# inputs has shape [batch, 513, 513, 3]
with slim.arg_scope(resnet_v2.resnet_arg_scope(is_training)):
net, end_points = resnet_v2.resnet_v2_101(inputs,
global_pool=False,
output_stride=16)
import collections # 原生的collections库
import tensorflow as tf
slim = tf.contrib.slim # 使用方便的contrib.slim库来辅助创建ResNet
使用collections.namedtuple设计ResNet基本模块组的name tuple,并用它创建Block的类
只包含数据结构,不包含具体方法。
定义一个典型的Block,需要输入三个参数:
scope:Block的名称
unit_fn:ResNet V2中的残差学习单元
args:Block的args。
def subsample(inputs, factor, scope=None):
&&&Subsamples the input along the spatial dimensions.
inputs: A `Tensor` of size [batch, height_in, width_in, channels].
factor: The subsampling factor.(采样因子)
scope: Optional variable_scope.
output: 如果factor为1,则不做修改直接返回inputs;如果不为1,则使用
slim.max_pool2d最大池化来实现,通过1*1的池化尺寸,stride作步长,实
现降采样。
if factor == 1:
return inputs
return slim.max_pool2d(inputs, [1, 1], stride=factor, scope=scope)
########创建卷积层########
def conv2d_same(inputs, num_outputs, kernel_size, stride, scope=None):
inputs: A 4-D tensor of size [batch, height_in, width_in, channels].
num_outputs: An integer, the number of output filters.
kernel_size: An int with the kernel_size of the filters.
stride: An integer, the output stride.
rate: An integer, rate for atrous convolution.
scope: Scope.
output: A 4-D tensor of size [batch, height_out, width_out, channels] with
the convolution output.
if stride == 1:
return slim.conv2d(inputs, num_outputs, kernel_size, stride=1,
padding='SAME', scope=scope)
else: # 如果不为1,则显式的pad zero,pad zero总数为kernel_size - 1
#kernel_size_effective = kernel_size + (kernel_size - 1) * (rate - 1)
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], [pad_beg, pad_end], [0, 0]])
# 因为已经进行了zero padding,所以只需再使用一个padding模式为VALID的slim.conv2d创建这个卷积层
return slim.conv2d(inputs, num_outputs, kernel_size, stride=stride,
padding='VALID', scope=scope)
net: A `Tensor` of size [batch, height, width, channels].输入。
blocks: 是之前定义的Block的class的列表。
outputs_collections: 收集各个end_points的collections。
net: Output tensor
# 使用两层循环,逐个Residual Unit地堆叠
for block in blocks: # 先使用两个tf.variable_scope将残差学习单元命名为block1/unit_1的形式
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]):
# 在第2层循环中,我们拿到每个block中每个Residual Unit的args并展开为下面四个参数
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) # 将输出net添加到collections中
return net # 当所有block中的所有Residual Unit都堆叠完成之后,再返回最后的net作为stack_blocks_dense
# 创建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-5
batch_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, # 标准化器设置为BN
normalizer_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: # ResNet原论文是VALID模式,SAME模式可让特征对齐更简单
return arg_sc # 最后将基层嵌套的arg_scope作为结果返回
def bottleneck(inputs, depth, depth_bottleneck, stride,
outputs_collections=None, scope=None):
inputs: A tensor of size [batch, height, width, channels].
depth、depth_bottleneck:、stride三个参数是前面blocks类中的args
rate: An integer, rate for atrous convolution.
outputs_collections: 是收集end_points的collection
scope: 是这个unit的名称。
with tf.variable_scope(scope, 'bottleneck_v2', [inputs]) as sc: # slim.utils.last_dimension获取输入的最后一个维度,即输出通道数。
depth_in = slim.utils.last_dimension(inputs.get_shape(), min_rank=4) # 可以限定最少为四个维度
# 使用slim.batch_norm对输入进行batch normalization,并使用relu函数进行预激活preactivate
preact = slim.batch_norm(inputs, activation_fn=tf.nn.relu, scope='preact')
if depth == depth_in:
shortcut = subsample(inputs, stride, 'shortcut')
# 如果残差单元的输入通道数和输出通道数一致,那么按步长对inputs进行降采样
shortcut = slim.conv2d(preact, depth, [1, 1], stride=stride,
normalizer_fn=None, activation_fn=None,
scope='shortcut')
# 如果不一样就按步长和1*1的卷积改变其通道数,使得输入、输出通道数一致
# 先是一个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')
output = shortcut + residual # 将降采样的结果和residual相加
return slim.utils.collect_named_outputs(outputs_collections, # 将output添加进collection并返回output作为函数结果
########定义生成resnet_v2的主函数########
def resnet_v2(inputs, # A tensor of size [batch, height_in, width_in, channels].输入
blocks, # 定义好的Block类的列表
num_classes=None, # 最后输出的类数
global_pool=True, # 是否加上最后的一层全局平均池化
include_root_block=True, # 是否加上ResNet网络最前面通常使用的7*7卷积和最大池化
reuse=None, # 是否重用
scope=None): # 整个网络的名称
# 在函数体先定义好variable_scope和end_points_collection
with tf.variable_scope(scope, 'resnet_v2', [inputs], reuse=reuse) as sc:
end_points_collection = sc.original_name_scope + '_end_points' # 定义end_points_collection
with slim.arg_scope([slim.conv2d, bottleneck,
stack_blocks_dense],
outputs_collections=end_points_collection): # 将三个参数的outputs_collections默认设置为end_points_collection
net = inputs
if include_root_block: # 根据标记值
with slim.arg_scope([slim.conv2d],
activation_fn=None, normalizer_fn=None):
net = conv2d_same(net, 64, 7, stride=2, scope='conv1') # 创建resnet最前面的64输出通道的步长为2的7*7卷积
net = slim.max_pool2d(net, [3, 3], stride=2, scope='pool1') # 然后接最大池化
# 经历过两个步长为2的层图片缩为1/4
net = 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 = slim.utils.convert_collection_to_dict(end_points_collection) # 将collection转化为python的dict
if num_classes is not None:
end_points['predictions'] = slim.softmax(net, scope='predictions') # 输出网络结果
return net, end_points
#------------------------------ResNet的生成函数定义好了----------------------------------------
# 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)]
'block4', bottleneck, [(, 1)] * 3)]
return resnet_v2(inputs, blocks, num_classes, global_pool,
include_root_block=True, reuse=reuse, scope=scope)
scope='resnet_v2_101'):
&&&ResNet-101 model of [1]. See resnet_v2() for arg and return description.&&&
blocks = [
'block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]),
'block2', bottleneck, [(512, 128, 1)] * 3 + [(512, 128, 2)]),
'block3', bottleneck, [(, 1)] * 22 + [(, 2)]),
'block4', bottleneck, [(, 1)] * 3)]
return resnet_v2(inputs, blocks, num_classes, global_pool,
include_root_block=True, reuse=reuse, scope=scope)
scope='resnet_v2_152'):
&&&ResNet-152 model of [1]. See resnet_v2() for arg and return description.&&&
blocks = [
'block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]),
'block2', bottleneck, [(512, 128, 1)] * 7 + [(512, 128, 2)]),
'block3', bottleneck, [(, 1)] * 35 + [(, 2)]),
'block4', bottleneck, [(, 1)] * 3)]
return resnet_v2(inputs, blocks, num_classes, global_pool,
include_root_block=True, reuse=reuse, scope=scope)
scope='resnet_v2_200'):
&&&ResNet-200 model of [2]. See resnet_v2() for arg and return description.&&&
blocks = [
'block1', bottleneck, [(256, 64, 1)] * 2 + [(256, 64, 2)]),
'block2', bottleneck, [(512, 128, 1)] * 23 + [(512, 128, 2)]),
'block3', bottleneck, [(, 1)] * 35 + [(, 2)]),
'block4', bottleneck, [(, 1)] * 3)]
return resnet_v2(inputs, blocks, num_classes, global_pool,
include_root_block=True, reuse=reuse, scope=scope)
#-------------------评测函数---------------------------------
# 测试152层深的ResNet的forward性能
def time_tensorflow_run(session, target, info_string):
num_steps_burn_in = 10
total_duration = 0.0
total_duration_squared = 0.0
for i in range(num_batches + num_steps_burn_in):
start_time = time.time()
_ = session.run(target)
duration = time.time() - start_time
if i = num_steps_burn_in:
if not i % 10:
print ('%s: step %d, duration = %.3f' %
(datetime.now(), i - num_steps_burn_in, duration))
total_duration += duration
total_duration_squared += duration * duration
mn = total_duration / num_batches
vr = total_duration_squared / num_batches - mn * mn
sd = math.sqrt(vr)
print ('%s: %s across %d steps, %.3f +/- %.3f sec / batch' %
(datetime.now(), info_string, num_batches, mn, sd))
batch_size = 32
height, width = 224, 224
inputs = tf.random_uniform((batch_size, height, width, 3))
with slim.arg_scope(resnet_arg_scope(is_training=False)): # is_training设置为false
net, end_points = resnet_v2_152(inputs, 1000)
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
num_batches=100
time_tensorflow_run(sess, net, &Forward&)
# forward计算耗时相比VGGNet和Inception V3大概只增加了50%,是一个实用的卷积神经网络。
跑的太慢了先来个截图:
本帖子中包含更多资源
才可以下载或查看,没有帐号?
温馨提示:
1、在论坛里发表的文章仅代表作者本人的观点,与本网站立场无关。
2、论坛的所有内容都不保证其准确性,有效性,时间性。阅读本站内容因误导等因素而造成的损失本站不承担连带责任。
3、若因线路及非本站所能控制范围的故障导致暂停服务期间造成的一切不便与损失,论坛不负任何责任。
4,本网站内容均摘自其他网站,如涉及侵权定当第一时间删除
5、如侵犯您的权益请联系TensorFlow(16)
  Inception-ResNet-v1的总体网络结构如下所示:
  下面将每个模块的网络结果展开:
对应的代码为
with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],stride=1, padding='SAME'):
net = slim.conv2d(inputs, 32, 3, stride=2, padding='VALID', scope='Conv2d_1a_3x3')
end_points['Conv2d_1a_3x3'] = net
net = slim.conv2d(net, 32, 3, padding='VALID',
scope='Conv2d_2a_3x3')
end_points['Conv2d_2a_3x3'] = net
net = slim.conv2d(net, 64, 3, scope='Conv2d_2b_3x3')
end_points['Conv2d_2b_3x3'] = net
net = slim.max_pool2d(net, 3, stride=2, padding='VALID', scope='MaxPool_3a_3x3')
end_points['MaxPool_3a_3x3'] = net
net = slim.conv2d(net, 80, 1, padding='VALID',
scope='Conv2d_3b_1x1')
end_points['Conv2d_3b_1x1'] = net
net = slim.conv2d(net, 192, 3, padding='VALID',
scope='Conv2d_4a_3x3')
end_points['Conv2d_4a_3x3'] = net
net = slim.conv2d(net, 256, 3, stride=2, padding='VALID',
scope='Conv2d_4b_3x3')
end_points['Conv2d_4b_3x3'] = net
Inception-resnet-A模块
  Inception-resnet-A模块是要重复5次的,网络结构为:
  对应的代码表示为:
def block35(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None):
"""Builds the 35x35 resnet block."""
with tf.variable_scope(scope, 'Block35', [net], reuse=reuse):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, 32, 1, scope='Conv2d_1x1')
with tf.variable_scope('Branch_1'):
tower_conv1_0 = slim.conv2d(net, 32, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1_0, 32, 3, scope='Conv2d_0b_3x3')
with tf.variable_scope('Branch_2'):
tower_conv2_0 = slim.conv2d(net, 32, 1, scope='Conv2d_0a_1x1')
tower_conv2_1 = slim.conv2d(tower_conv2_0, 32, 3, scope='Conv2d_0b_3x3')
tower_conv2_2 = slim.conv2d(tower_conv2_1, 32, 3, scope='Conv2d_0c_3x3')
mixed = tf.concat([tower_conv, tower_conv1_1, tower_conv2_2], 3)
up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None,activation_fn=None, scope='Conv2d_1x1')
net += scale * up
if activation_fn:
net = activation_fn(net)
return net
net = slim.repeat(net, 5, block35, scale=0.17)
end_points['Mixed_5a'] = net
Reduction-A结构
  Reduction-A中含有4个参数k、l、 m、 n,它们对应的值分别为:192, 192, 256, 384,在该层网络结构,输入为35×35×256,输出为17×17×896.
def reduction_a(net, k, l, m, n):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, n, 3, stride=2, padding='VALID',
scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_1'):
tower_conv1_0 = slim.conv2d(net, k, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1_0, l, 3,
scope='Conv2d_0b_3x3')
tower_conv1_2 = slim.conv2d(tower_conv1_1, m, 3,
stride=2, padding='VALID',
scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_2'):
tower_pool = slim.max_pool2d(net, 3, stride=2, padding='VALID',
scope='MaxPool_1a_3x3')
net = tf.concat([tower_conv, tower_conv1_2, tower_pool], 3)
return net
with tf.variable_scope('Mixed_6a'):
net = reduction_a(net, 192, 192, 256, 384)
end_points['Mixed_6a'] = net
Inception-Resnet-B
  Inception-Resnet-B模块是要重复10次,输入为17×17×896,输出为17×17×896,网络结构为:
def block17(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None):
"""Builds the 17x17 resnet block."""
with tf.variable_scope(scope, 'Block17', [net], reuse=reuse):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, 128, 1, scope='Conv2d_1x1')
with tf.variable_scope('Branch_1'):
tower_conv1_0 = slim.conv2d(net, 128, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1_0, 128, [1, 7],
scope='Conv2d_0b_1x7')
tower_conv1_2 = slim.conv2d(tower_conv1_1, 128, [7, 1],
scope='Conv2d_0c_7x1')
mixed = tf.concat([tower_conv, tower_conv1_2], 3)
up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None,activation_fn=None, scope='Conv2d_1x1')
net += scale * up
if activation_fn:
net = activation_fn(net)
return net
net = slim.repeat(net, 10, block17, scale=0.10)
end_points['Mixed_6b'] = net
Reduction-B
  Reduction-B的输入为17*17*896,输出为8*8*1792。网络结构为:
对应的代码为:
def reduction_b(net):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1')
tower_conv_1 = slim.conv2d(tower_conv, 384, 3, stride=2,
padding='VALID', scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_1'):
tower_conv1 = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1, 256, 3, stride=2,
padding='VALID', scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_2'):
tower_conv2 = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1')
tower_conv2_1 = slim.conv2d(tower_conv2, 256, 3,
scope='Conv2d_0b_3x3')
tower_conv2_2 = slim.conv2d(tower_conv2_1, 256, 3, stride=2,
padding='VALID', scope='Conv2d_1a_3x3')
with tf.variable_scope('Branch_3'):
tower_pool = slim.max_pool2d(net, 3, stride=2, padding='VALID',
scope='MaxPool_1a_3x3')
net = tf.concat([tower_conv_1, tower_conv1_1,
tower_conv2_2, tower_pool], 3)
return net
with tf.variable_scope('Mixed_7a'):
net = reduction_b(net)
end_points['Mixed_7a'] = net
Inception-Resnet-C结构
  Inception-Resnet-C结构重复5次。它输入为8*8*1792,输出为8*8*1792。对应的结构为:
  对应的代码为:
def block8(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None):
"""Builds the 8x8 resnet block."""
with tf.variable_scope(scope, 'Block8', [net], reuse=reuse):
with tf.variable_scope('Branch_0'):
tower_conv = slim.conv2d(net, 192, 1, scope='Conv2d_1x1')
with tf.variable_scope('Branch_1'):
tower_conv1_0 = slim.conv2d(net, 192, 1, scope='Conv2d_0a_1x1')
tower_conv1_1 = slim.conv2d(tower_conv1_0, 192, [1, 3],
scope='Conv2d_0b_1x3')
tower_conv1_2 = slim.conv2d(tower_conv1_1, 192, [3, 1],
scope='Conv2d_0c_3x1')
mixed = tf.concat([tower_conv, tower_conv1_2], 3)
up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None,activation_fn=None, scope='Conv2d_1x1')
net += scale * up
if activation_fn:
net = activation_fn(net)
return net
net = slim.repeat(net, 5, block8, scale=0.20)
end_points['Mixed_8a'] = net
  但是在facenet中,接下来又是一层Inception-Resnet-C,但是它没有重复,并且没有激活函数。输入与输出大小相同。
net = block8(net, activation_fn=None)
end_points['Mixed_8b'] = net
  结果输出包含Average Pooling和Dropout (keep 0.8)及Softmax三层,这里我们以facenet中为例:具体的代码如下:
with tf.variable_scope('Logits'):
end_points['PrePool'] = net
net = slim.avg_pool2d(net, net.get_shape()[1:3], padding='VALID',scope='AvgPool_1a_8x8')
net = slim.flatten(net)
net = slim.dropout(net, dropout_keep_prob, is_training=is_training,scope='Dropout')
end_points['PreLogitsFlatten'] = net
net = slim.fully_connected(net, bottleneck_layer_size, activation_fn=None,scope='Bottleneck', reuse=False)
  至此,inception_resnet_v1网络结构就结束了,但facenet的代码分析未完,待续~~~~
访问:87035次
积分:1450
排名:千里之外
原创:61篇
转载:17篇
评论:11条
(1)(4)(10)(14)(1)(4)(3)(3)(1)(3)(1)(4)(4)(3)(1)(2)(1)(1)(1)(5)(4)(6)(1)他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)TensorFlow(21)
主要涉及:
首先建议阅读Tensorflow和slim的官方文档,获取arg_scope,variable_scope,outputs_collections等的基础知识。
本文主要是记录一下代码的大概逻辑,备忘。
resnet_utils.py
需了解collections.namedtuple,相当于一个命名了的元组,且可以通过属性的名字访问属性值。
class Block(collections.namedtuple('Block', ['scope', 'unit_fn', 'args'])):
简单,用最大池化来降采样(其实是通过stride)
def subsample(inputs, factor, scope=None):
1. net = conv2d_same(inputs, num_outputs, 3, stride=stride)
2. net = slim.conv2d(inputs, num_outputs, 3, stride=1, padding='SAME')
net = subsample(net, factor=stride)
3. net = slim.conv2d(inputs, num_outputs, 3, stride=stride, padding='SAME')
1和2是等价的,当inputs的高或宽是偶数时3与1,2不一样。
"VALID" only ever drops the right-most columns (or bottom-most rows).
默认的"SAME" tries to pad evenly left and right, but if the amount of columns to be added is odd, it will add the extra column to the right, as is the case in this example (the same logic applies vertically: there may be an extra row of zeros at the bottom).
在testConv2DSameEven中可以清楚看出来由于对偶数大小的边进行pad会造成最终结果的不同,细节不写了。
所以在这个函数中先手动进行padding,然后再调用conv2d。
def conv2d_same(inputs, num_outputs, kernel_size, stride, rate=1, scope=None):
比较核心的函数,作用是将不同的block(一般一共四个)组装起来,当然肚子里也将同一个block的bottleneck组装起来。block.unit_fn调用的就是该block的bottleneck,原因见 class Block(collections.namedtuple('Block', ['scope', 'unit_fn', 'args']))。
@slim.add_arg_scope
def stack_blocks_dense(net, blocks, output_stride=None,
outputs_collections=None):
为resnet定义了arg_scope,方便定义各种层的时候少写代码。
def resnet_arg_scope(weight_decay=0.0001,
batch_norm_decay=0.997,
batch_norm_epsilon=1e-5,
batch_norm_scale=True,
activation_fn=tf.nn.relu,
use_batch_norm=True):
resnet_v2.py
Bottleneck residual unit variant with BN before convolutions.
就是三个连续的卷积层(BN和relu都被arg_scope定义了),另外当通道数变化时会有一个额外的shortcut卷积层,利用1*1卷积修正通道数,使得shortcut过来的输入可以直接和三个卷积分支的输出相加。
def bottleneck(inputs, depth, depth_bottleneck, stride, rate=1,
outputs_collections=None, scope=None)
'''构建整个resnet的函数。
看懂这个就知道end_points为什么可以获取各层输出了:
with slim.arg_scope([slim.conv2d, bottleneck,
resnet_utils.stack_blocks_dense],
outputs_collections=end_points_collection)
这个函数调用了resnet_utils.stack_blocks_dense,上面介绍过,用来组装四个大block。
def resnet_v2(inputs,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
include_root_block=True,
spatial_squeeze=True,
reuse=None,
scope=None)
'''这个函数就是封装了创建class Block(collections.namedtuple('Block', ['scope', 'unit_fn', 'args']))对象的代码。
def resnet_v2_block(scope, base_depth, num_units, stride)
'''这个函数全抄过来了,是对外的接口,主要调用了resnet_v2_block和resnet_v2这两个函数。
def resnet_v2_152(inputs,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
spatial_squeeze=True,
reuse=None,
scope='resnet_v2_152'):
blocks = [
resnet_v2_block('block1', base_depth=64, num_units=3, stride=2),
resnet_v2_block('block2', base_depth=128, num_units=8, stride=2),
resnet_v2_block('block3', base_depth=256, num_units=36, stride=2),
resnet_v2_block('block4', base_depth=512, num_units=3, stride=1),
return resnet_v2(inputs, blocks, num_classes, is_training=is_training,
global_pool=global_pool, output_stride=output_stride,
include_root_block=True, spatial_squeeze=spatial_squeeze,
reuse=reuse, scope=scope)
resnet_v2_152.default_image_size = resnet_v2.default_image_size
访问:30351次
排名:千里之外
原创:62篇
评论:37条
(4)(9)(19)(5)(6)(13)(6)}

我要回帖

更多关于 variable scope 用法 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信