slim中给出了resnet、vgg卷积网络的快速实现方法,定义的位置为:D:\anaconda\envs\tensorflow\Lib\site-packages\tensorflow\contrib\slim\python\slim\nets,构建残差网络主要使用的模块为resnet_utils.py、resnet_v1.py、resnet_v2.py。下面
def resnet_v1(inputs,
blocks,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
include_root_block=True,
reuse=None,
scope=None):
with variable_scope.variable_scope(
scope, 'resnet_v1', [inputs], reuse=reuse) as sc:
end_points_collection = sc.original_name_scope + '_end_points'
with arg_scope(
[layers.conv2d, bottleneck, resnet_utils.stack_blocks_dense],
outputs_collections=end_points_collection):
with arg_scope([layers.batch_norm], is_training=is_training):
net = inputs
if include_root_block:
if output_stride is not None:
if output_stride % 4 != 0:
raise ValueError('The output_stride needs to be a multiple of 4.')
output_stride /= 4
net = resnet_utils.conv2d_same(net, 64, 7, stride=2, scope='conv1')
net = layers_lib.max_pool2d(net, [3, 3], stride=2, scope='pool1')
net = resnet_utils.stack_blocks_dense(net, blocks, output_stride)
if global_pool:
# Global average pooling.
net = math_ops.reduce_mean(net, [1, 2], name='pool5', keepdims=True)
if num_classes is not None:
net = layers.conv2d(
net,
num_classes, [1, 1],
activation_fn=None,
normalizer_fn=None,
scope='logits')
# Convert end_points_collection into a dictionary of end_points.
end_points = utils.convert_collection_to_dict(end_points_collection)
if num_classes is not None:
end_points['predictions'] = layers_lib.softmax(
net, scope='predictions')
return net, end_points
resnet_v1.default_image_size = 224
该函数生成一系列ResNet v1模型。有关特定的模型实例化,请参见resnet_v1_*()方法,该方法通过选择产生不同深度的resnet的不同块实例化获得。
Imagenet上的图像分类训练通常使用[224,224]输入,对于[1]中定义的、标称步长为32的ResNet,在最后一个ResNet块的输出生成[7,7]特征图。对于密集预测任务,建议使用空间维度为32 + 1的倍数的输入,例如[321,321]。在这种情况下,ResNet输出处的特征映射将具有空间形状[(height - 1) / output_stride + 1, (width - 1) / output_stride + 1]和与输入图像角完全对齐的角,这极大地促进了特征与图像的对齐。使用作为输入的[225,225]图像在最后一个ResNet块的输出处生成[8,8]feature map。
对于密集预测任务,ResNet需要在全卷积(FCN)模式下运行,global_pool需要设置为False。
[1,2]中的ResNets都有公称stride= 32,在FCN模式下,一个很好的选择是使用output_stride=16,以便在较小的计算和内存开销下增加计算特性的密度,cf. http://arxiv.org/abs/1606.00915。
参数:
返回:
可能产生的异常:
def resnet_v1_block(scope, base_depth, num_units, stride):
return resnet_utils.Block(scope, bottleneck, [{
'depth': base_depth * 4,
'depth_bottleneck': base_depth,
'stride': 1
}] * (num_units - 1) + [{
'depth': base_depth * 4,
'depth_bottleneck': base_depth,
'stride': stride
}])
用于创建resnet_v1 bottleneck的Helper函数。 参数:
返回值:
def resnet_v1_50(inputs,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
reuse=None,
scope='resnet_v1_50'):
"""ResNet-50 model of [1]. See resnet_v1() for arg and return description."""
blocks = [
resnet_v1_block('block1', base_depth=64, num_units=3, stride=2),
resnet_v1_block('block2', base_depth=128, num_units=4, stride=2),
resnet_v1_block('block3', base_depth=256, num_units=6, stride=2),
resnet_v1_block('block4', base_depth=512, num_units=3, stride=1),
]
return resnet_v1(
inputs,
blocks,
num_classes,
is_training,
global_pool,
output_stride,
include_root_block=True,
reuse=reuse,
scope=scope)
[1]的ResNet-50模型。有关arg和返回描述,请参见resnet_v1()。
def resnet_v1_50(inputs,
num_classes=None,
is_training=True,
global_pool=True,
output_stride=None,
reuse=None,
scope='resnet_v1_50'):
"""ResNet-50 model of [1]. See resnet_v1() for arg and return description."""
blocks = [
resnet_v1_block('block1', base_depth=64, num_units=3, stride=2),
resnet_v1_block('block2', base_depth=128, num_units=4, stride=2),
resnet_v1_block('block3', base_depth=256, num_units=6, stride=2),
resnet_v1_block('block4', base_depth=512, num_units=3, stride=1),
]
return resnet_v1(
inputs,
blocks,
num_classes,
is_training,
global_pool,
output_stride,
include_root_block=True,
reuse=reuse,
scope=scope)
def conv2d_same(inputs, num_outputs, kernel_size, stride, rate=1, scope=None):
if stride == 1:
return layers_lib.conv2d(
inputs,
num_outputs,
kernel_size,
stride=1,
rate=rate,
padding='SAME',
scope=scope)
else:
kernel_size_effective = kernel_size + (kernel_size - 1) * (rate - 1)
pad_total = kernel_size_effective - 1
pad_beg = pad_total // 2
pad_end = pad_total - pad_beg
inputs = array_ops.pad(
inputs, [[0, 0], [pad_beg, pad_end], [pad_beg, pad_end], [0, 0]])
return layers_lib.conv2d(
inputs,
num_outputs,
kernel_size,
stride=stride,
rate=rate,
padding='VALID',
scope=scope)
"""
用'SAME'padding进行2-D卷积。如果stride > 1,然后明确的执行零填充,然后是一个'VALID'填充的二维卷积。
注意
net = conv2d_same(inputs, num_outputs, 3, stride=stride)等于
net = tf.contrib.layers.conv2d(inputs, num_outputs, 3, stride=1,padding='SAME') net = subsample(net, factor=stride)
然而
net = tf.contrib.layers.conv2d(inputs, num_outputs, 3, stride=stride,padding='SAME')当输入的高度或宽度为偶数时,则不同,这就是我们添加当前函数的原因。
参数:
返回值: