特征提取主干网络采用resnet50
resnet50结构图
其中,conv2d_block和identity_block结构图为
主干网络实现采用tf.contrib.slim模块
# -*- coding: UTF-8 -*-
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import tensorflow.contrib.slim as slim
def conv_block(input_tensor,kernal_size,filters,stage,block,strides=2,is_training=True):
filters1,filters2,filters3 = filters
conv_name_base = 'res' + str(stage) + block + '_branch'
bn_name_base = 'bn' + str(stage) + block + '_branch'
with slim.arg_scope([slim.conv2d],
activation_fn=tf.nn.relu,
weights_initializer=tf.truncated_normal_initializer(0.0, 0.01),
weights_regularizer=slim.l2_regularizer(0.0005),
normalizer_fn=slim.batch_norm,
normalizer_params={'is_training': is_training,
'zero_debias_moving_mean': True,
'decay': 0.99,
'epsilon': 0.0001,
'scale': 0.2,
'updates_collections': tf.GraphKeys.UPDATE_OPS}):
x = slim.conv2d(input_tensor,filters1,[1,1],stride=strides,scope=conv_name_base + '2a')
x = slim.conv2d(x,filters2,kernal_size,scope=conv_name_base + '2b')
x = slim.conv2d(x,filters3,[1,1],activation_fn=None,scope=conv_name_base + '2c')
shortcut = slim.conv2d(input_tensor,filters3,[1,1],stride=strides,activation_fn=None,scope=conv_name_base+'1')
x = x + shortcut
x = tf.nn.relu(x)
return x
def identity_block(input_tensor,kernal_size,filters,stage,block,is_training=True):
filters1,filters2,filters3 = filters
conv_name_base = 'res' + str(stage) + block + '_branch'
bn_name_base = 'bn' + str(stage) + block + '_branch'
with slim.arg_scope([slim.conv2d],
activation_fn=tf.nn.relu,
weights_initializer=tf.truncated_normal_initializer(0.0, 0.01),
weights_regularizer=slim.l2_regularizer(0.0005),
normalizer_fn=slim.batch_norm,
normalizer_params={'is_training': is_training,
'zero_debias_moving_mean': True,
'decay': 0.99,
'epsilon': 0.0001,
'scale': 0.2,
'updates_collections': tf.GraphKeys.UPDATE_OPS}):
x = slim.conv2d(input_tensor,filters1,[1,1],scope= conv_name_base + '2a')
x = slim.conv2d(x,filters2,kernal_size,scope=conv_name_base + '2b')
x = slim.conv2d(x,filters3,[1,1],scope=conv_name_base + '2c')
x = x + input_tensor
x = tf.nn.relu(x)
return x
def ResNet50(inputs,is_training = True):
#建立两个瓶颈结构,conv_block有可能改变特征图的大小,identity_block不会改变特征图的大小
img_input = inputs
with slim.arg_scope([slim.conv2d],
activation_fn=tf.nn.relu,
weights_initializer=tf.truncated_normal_initializer(0.0, 0.01),
weights_regularizer=slim.l2_regularizer(0.0005),
normalizer_fn=slim.batch_norm,
#加入bn层后,要定义传入batch_norm的参数,是字典形式
normalizer_params={'is_training': is_training,
'zero_debias_moving_mean': True,
'decay': 0.99,
'epsilon': 0.0001,
'scale': 0.2,
'updates_collections': tf.GraphKeys.UPDATE_OPS}):
#stage1 --压缩4倍
paddings = [[0,0],[3,3],[3,3],[0,0]]
x = tf.pad(img_input,paddings,"CONSTANT")
x = slim.conv2d(x, 64, (7,7),stride=2,padding='VALID',scope='conv1') # 上面补0了,这里就不用SAME了,特征图计算公式是针对padding=valid的(自己手动补0),如果padding=SAME,stride=2,特征图为输入的1/2,如果stride=1,特征图和输入大小一致。
x = slim.max_pool2d(x,[3,3],padding="SAME")
#stage2 --不压缩
x = conv_block(x,[3,3],[64,64,256],stage=2,block='a',strides=1)
x = identity_block(x,[3,3],[64,64,256],stage=2,block='b')
x = identity_block(x,[3,3],[64,64,256],stage=2,block='c')
#stage3 --压缩2倍
x = conv_block(x,[3,3],[128,128,512],stage=3,block='a')
x = identity_block(x,[3,3],[128,128,512],stage=3,block='b')
x = identity_block(x,[3,3],[128,128,512],stage=3,block='c')
x = identity_block(x,[3,3],[128,128,512],stage=3,block='d')
#stage4 --压缩2倍
x = conv_block(x,[3,3],[256,256,1024],stage=4,block='a')
x = identity_block(x,[3,3],[256,256,1024],stage=4,block='b')
x = identity_block(x,[3,3],[256,256,1024],stage=4,block='c')
x = identity_block(x,[3,3],[256,256,1024],stage=4,block='d')
x = identity_block(x,[3,3],[256,256,1024],stage=4,block='e')
x = identity_block(x,[3,3],[256,256,1024],stage=4,block='f')
#输入如果是600*600的图像,返回的时38X38的特征
return x
if __name__ == '__main__':
img = tf.constant(1,dtype=tf.float32,shape=[1,600,600,3])
x = ResNet50(img)
print(x)
这样就得到了共享特征图。