https://github.com/GuodongQi/yolo3_tensorflow
import tensorflow as tf #darknet53的卷积等封装 def convolutional(input_data, filters_shape, trainable, name, downsample=False, activate=True, bn=True): with tf.variable_scope(name): if downsample: pad_h, pad_w = (filters_shape[0] - 2) // 2 + 1, (filters_shape[1] - 2) // 2 + 1 paddings = tf.constant([[0, 0], [pad_h, pad_h], [pad_w, pad_w], [0, 0]]) input_data = tf.pad(input_data, paddings, 'CONSTANT') strides = (1, 2, 2, 1) padding = 'VALID' else: strides = (1, 1, 1, 1) padding = "SAME" #讨论initializer对卷积的影响 0513 weight = tf.get_variable(name='weight', dtype=tf.float16, trainable=True,shape=filters_shape, # initializer=tf.random_normal_initializer(stddev=0.01)) #run ok initializer=tf.truncated_normal_initializer(stddev=0.01)) #run ok # initializer=tf.contrib.layers.xavier_initializer()) #not ok # initializer=tf.glorot_normal_initializer()) #not ok # initializer=tf.keras.initializers.he_normal()) #not ok # initializer=tf.random_uniform_initializer())#not ok conv = tf.nn.conv2d(input=input_data, filter=weight, strides=strides, padding=padding) if bn: conv = tf.layers.batch_normalization(conv, beta_initializer=tf.zeros_initializer(), gamma_initializer=tf.ones_initializer(), moving_mean_initializer=tf.zeros_initializer(), moving_variance_initializer=tf.ones_initializer(), training=trainable) else: bias = tf.get_variable(name='bias', shape=filters_shape[-1], trainable=True, dtype=tf.float16, initializer=tf.constant_initializer(0.0)) conv = tf.nn.bias_add(conv, bias) if activate == True: conv = tf.nn.leaky_relu(conv, alpha=0.1) return conv def residual_block(input_data, input_channel, filter_num1, filter_num2, trainable, name): short_cut = input_data with tf.variable_scope(name): input_data = convolutional(input_data, filters_shape=(1, 1, input_channel, filter_num1), trainable=trainable, name='conv1') input_data = convolutional(input_data, filters_shape=(3, 3, filter_num1, filter_num2), trainable=trainable, name='conv2') residual_output = input_data + short_cut return residual_output def route(name, previous_output, current_output): with tf.variable_scope(name): output = tf.concat([current_output, previous_output], axis=-1) return output def upsample(input_data, name, method="deconv"): assert method in ["resize", "deconv"] if method == "resize": with tf.variable_scope(name): input_shape = tf.shape(input_data) output = tf.image.resize_nearest_neighbor(input_data, (input_shape[1] * 2, input_shape[2] * 2)) if method == "deconv": # replace resize_nearest_neighbor with conv2d_transpose To support TensorRT optimization numm_filter = input_data.shape.as_list()[-1] output = tf.layers.conv2d_transpose(input_data, numm_filter, kernel_size=2, padding='same', strides=(2,2), kernel_initializer=tf.random_normal_initializer()) return output #mobilenet_v2的卷积等封装 xavier_initializer = tf.initializers.glorot_uniform(dtype=tf.float16) leaky_alpha = 0.1 def conv_block(x, filters, stride, out_channel,is_training, name='', relu=True): """ :param x: input :nhwc :param filters: list [f_w, f_h] :param stride: list int :param out_channel: int, out_channel :param net_type: cnn mobilenet :param is_training: used in BN :param name: str :param relu: boolean :return: depwise and pointwise out """ with tf.name_scope('' + name): in_channel = x.shape[3].value tmp_channel = out_channel * 3 #中间的临时channel with tf.name_scope('expand_pointwise'): pointwise_weight = tf.Variable(xavier_initializer([1, 1, in_channel, tmp_channel])) x = tf.nn.conv2d(x, pointwise_weight, [1, 1, 1, 1], 'SAME') x = tf.layers.batch_normalization(x, training=is_training) x = tf.nn.relu6(x) with tf.name_scope('depthwise'): depthwise_weight = tf.Variable(xavier_initializer([filters[0], filters[1], tmp_channel, 1])) x = tf.nn.depthwise_conv2d(x, depthwise_weight, [1, stride[0], stride[1], 1], 'SAME') x = tf.layers.batch_normalization(x, training=is_training) x = tf.nn.relu6(x) with tf.name_scope('project_pointwise'): pointwise_weight = tf.Variable(xavier_initializer([1, 1, tmp_channel, out_channel])) x = tf.nn.conv2d(x, pointwise_weight, [1, 1, 1, 1], 'SAME') if relu: x = tf.layers.batch_normalization(x, training=is_training) else: bias = tf.Variable(tf.zeros(shape=out_channel),dtype=tf.float16) x += bias return x def residual(x,is_training, out_channel=1, expand_time=1, stride=1,name=''): shortcut = x in_channel = x.shape[3].value tmp_channel = in_channel * expand_time with tf.name_scope(name): with tf.name_scope('expand_pointwise'):#点卷积 拓展,生成一个高维信息域 参考《深度可分离卷积文档》 pointwise_weight = tf.Variable(xavier_initializer([1, 1, in_channel, tmp_channel])) x = tf.nn.conv2d(x, pointwise_weight, [1, 1, 1, 1], 'SAME') x = tf.layers.batch_normalization(x, training=is_training) x = tf.nn.relu6(x) with tf.name_scope('depthwise'):#深度卷积 depthwise_weight = tf.Variable(xavier_initializer([3, 3, tmp_channel, 1])) x = tf.nn.depthwise_conv2d(x, depthwise_weight, [1, stride, stride, 1], 'SAME') x = tf.layers.batch_normalization(x, training=is_training) x = tf.nn.relu6(x) with tf.name_scope('project_pointwise'):#点卷积 pointwise_weight = tf.Variable(xavier_initializer([1, 1, tmp_channel, out_channel])) x = tf.nn.conv2d(x, pointwise_weight, [1, 1, 1, 1], 'SAME') x = tf.layers.batch_normalization(x, training=is_training) x += shortcut return x def mobilenet_v2_body(x,is_training): # 特征检测网络 """ :param x: :param is_training: :return: """ with tf.variable_scope('mobilenet_v2'): # x为 416×416 图像 标准的mobilnet v2 输入为 224 ×224有一定差异 x = conv_block(x, [3, 3],[2, 2],32,is_training=is_training) # conv2d正常卷积,输出208×208×32通道 x = conv_block(x, [3, 3], [2, 2], 16, is_training=is_training) # 残差块卷积,输出104×104×16 下采样 x = conv_block(x, [3, 3], [1, 1], 24, is_training=is_training) # 残差块卷积,输出104×104×24 x = residual(x, is_training, 24, 1) # 残差块卷积,输出104×104×24 x = conv_block(x, [3, 3], [2, 2], 32, is_training=is_training) # 残差块卷积,输出52×52×32 下采样 for i in range(2): # 残差块卷积 输出 52×52×32 x = residual(x, is_training, 32, 1) route2 = x #[52,52,32] x = conv_block(x, [3, 3], [2, 2], 64,is_training=is_training) # 残差块卷积,输出26×26×64 下采样 for i in range(3): # 残差块卷积 输出 26×26×64 x = residual(x, is_training, 64, 6) x = conv_block(x, [3, 3], [1, 1], 96, is_training=is_training) # 残差块卷积,输出26×26×96 更改输出通道 for i in range(2): # 残差块卷积 输出 26×26×64 x = residual(x, is_training, 96, 6) route1 = x #[26,26,64] # down sample x = conv_block(x, [3, 3], [2, 2], 160, is_training=is_training) # 残差块卷积,输出13×13×160 下采样 for i in range(2): x = residual(x, is_training, 160, 1) x = conv_block(x, [3, 3], [1, 1], 320, is_training=is_training) # 残差块卷积,输出13×13×320 更改输出通道 return x, route1, route2 def darknet_depthwise(input_data,training): # 特征检测网络 """ :param x: :param is_training: :return: """ with tf.variable_scope('darknet_depthwise'): input_data = conv_block(input_data,filters=[3, 3],stride=[1, 1],out_channel=32, is_training=training, name='conv0') input_data = conv_block(input_data,filters=[3, 3],stride=[2, 2],out_channel=64, is_training=training, name='conv1') for i in range(1): input_data = residual(input_data,is_training=training,out_channel=64,name='residual%d' % (i + 0)) #[?,208,208,64] input_data = conv_block(input_data, filters=[3, 3],stride=[2,2],out_channel=128, is_training=training, name='conv4') #[?,104,104,128] for i in range(2): input_data = residual(input_data,is_training=training,out_channel=128,name='residual%d' % (i + 1)) # [?,104,104,128] input_data = conv_block(input_data, filters=[3, 3], stride=[2, 2], out_channel=256, is_training=training,name='conv9') # [?,52,52,256] for i in range(8): input_data = residual(input_data, is_training=training, out_channel=256, name='residual%d' % (i + 3)) input_data = conv_block(input_data, filters=[3, 3], stride=[2, 2], out_channel=512, is_training=training,name='conv26') # [?,26,26,512] for i in range(8): input_data = residual(input_data, is_training=training, out_channel=512, name='residual%d' % (i + 11)) input_data = conv_block(input_data, filters=[3, 3], stride=[2, 2], out_channel=1024, is_training=training,name='conv43') # [?,13,13,512] for i in range(4): input_data = residual(input_data, is_training=training, out_channel=1024, name='residual%d' % (i + 19)) return input_data