将yolov3的backbone由darknet53变为mobilenet v2的想法

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

  

猜你喜欢

转载自www.cnblogs.com/liutianrui1/p/13197881.html