yolov3实战 超简单上手 飞机与油桶数据集之替换bottlenet 为Mobilenetv2,顺便补充相关loss func

mobilenet v2 keras实现

from keras import backend, Input, Model
from keras.layers import Conv2D, BatchNormalization, Activation, ZeroPadding2D, DepthwiseConv2D, Add


# relu6 relu6与relu的区别是relu6在relu的基础上增加了最大值抑制 即经过激活函数函数relu,最大值为6
def relu6(x):
    return backend.relu(x, max_value=6)

# 计算padding的大小
def correct_pad(inputs, kernel_size):
    img_dim = 1
    input_size = backend.int_shape(inputs)[img_dim:(img_dim + 2)]

    if isinstance(kernel_size, int):
        kernel_size = (kernel_size, kernel_size)
    if input_size[0] is None:
        adjust = (1, 1)
    else:
        adjust = (1 - input_size[0] % 2, 1 - input_size[1] % 2)

    correct = (kernel_size[0] // 2, kernel_size[1] // 2)
    return ((correct[0] - adjust[0], correct[0]),
            (correct[1] - adjust[1], correct[1]))

# 使其结果可以被8整除,因为使用到了膨胀系数α
def _make_divisible(v, divisor, min_value=None):
    if min_value is None:
        min_value = divisor
    new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
    if new_v < 0.9 * v:
        new_v += divisor
    return new_v

def _inverted_res_block(inputs, expansion, stride, alpha, filters, block_id):
    in_channels = backend.int_shape(inputs)[-1]
    pointwise_conv_filters = int(filters * alpha)
    pointwise_filters = _make_divisible(pointwise_conv_filters, 8)

    x = inputs
    prefix = 'block_{}_'.format(block_id)
    # 数据扩张
    if block_id:
        x = Conv2D(expansion * in_channels,
                   kernel_size=1,
                   padding='same',
                   use_bias=False,
                   activation=None,
                   name=prefix + 'expand')(x)
        x = BatchNormalization(epsilon=1e-3, name=prefix + 'expand_BN')(x)
        x = Activation(relu6, name = prefix + 'expand_relu')(x)
    else:
        prefix = 'expanded_conv'
    if stride == 2:
        x = ZeroPadding2D(padding=correct_pad(x, 3),
                          name=prefix + 'pad')(x)

    # 可分离卷积
    x = DepthwiseConv2D(kernel_size=3,
                        strides=stride,
                        activation=None,
                        use_bias=False,
                        padding='same' if stride == 1 else 'valid',
                        name= prefix+ 'deptwise')(x)
    x = BatchNormalization(epsilon=1e-3,
                           name=prefix + 'depthwise_BN')(x)
    x = Activation(relu6, name=prefix + 'deptwise_relu')(x)

    # part3 压缩特征,而且不使用relu函数,保证特征不被破坏
    x = Conv2D(pointwise_filters,
               kernel_size=1,
               padding='same',
               use_bias=False,
               activation=None,
               name=prefix + 'project')(x)
    x = BatchNormalization(epsilon=1e-3, name=prefix + 'project_BN')(x)
    if in_channels == pointwise_filters and stride == 1:
        return Add(name=prefix + 'add')([inputs, x])
    return x


def MobileNetV2(inputs, alpha=1.0):
    # stem部分
    first_block_filters = _make_divisible(32 * alpha, 8)
    x = ZeroPadding2D(padding=correct_pad(inputs=inputs, kernel_size=3),
                      name='Conv_pad')(inputs)

    # 416, 416, 3 -> 208,208,32
    x = Conv2D(first_block_filters,
               kernel_size=3,
               strides=(2, 2),
               padding='valid',
               use_bias=False,
               name='Conv1')(x)
    x = BatchNormalization(epsilon=1e-3,
                            name='bn_Conv1')(x)
    x = Activation(relu6, name='Conv_relu')(x)

    # 208,208, 32 -> 208,208,16
    x = _inverted_res_block(x, filters=16, alpha=alpha, stride=1,
                            expansion=1,block_id=0)
    # 208, 208, 16 -> 104,104,24
    x = _inverted_res_block(x, filters=24, alpha=alpha, stride=2,
                            expansion=6, block_id=1)
    x = _inverted_res_block(x, filters=24, alpha=alpha, stride=1,
                            expansion=6, block_id=2)

    # 104,104,24 -> 52,52,32
    x = _inverted_res_block(x, filters=32, alpha=alpha, stride=2,
                            expansion=6, block_id=3)
    x = _inverted_res_block(x, filters=32, alpha=alpha, stride=1,
                            expansion=6, block_id=4)
    x = _inverted_res_block(x, filters=32, alpha=alpha, stride=1,
                            expansion=6,block_id=5)
    feat1 = x
    # 52,52,32 -> 26,26,96
    x = _inverted_res_block(x, filters=64, alpha=alpha, stride=2,
                            expansion=6, block_id=6)
    x = _inverted_res_block(x, filters=64, alpha=alpha, stride=1,
                            expansion=6, block_id=7)
    x = _inverted_res_block(x, filters=64, alpha=alpha, stride=1,
                            expansion=6, block_id=8)
    x = _inverted_res_block(x, filters=96, alpha=alpha, stride=1,
                            expansion=6, block_id=9)
    x = _inverted_res_block(x, filters=96, alpha=alpha, stride=1,
                            expansion=6, block_id=10)
    x = _inverted_res_block(x, filters=96, alpha=alpha, stride=1,
                            expansion=6, block_id=11)
    x = _inverted_res_block(x, filters=96, alpha=alpha, stride=1,
                            expansion=6, block_id=12)

    feat2 = x

    # 26,26,96 -> 13,13,320
    x = _inverted_res_block(x, filters=160, alpha=alpha, stride=2,
                            expansion=6, block_id=13)
    x = _inverted_res_block(x, filters=1600, alpha=alpha, stride=1,
                            expansion=6, block_id=14)
    x = _inverted_res_block(x, filters=160, alpha=alpha, stride=1,
                            expansion=6, block_id=15)
    x = _inverted_res_block(x, filters=320, alpha=alpha, stride=1,
                            expansion=6, block_id=16)
    feat3 = x

    return feat1, feat2, feat3

if __name__ == '__main__':
		# 代码来自@Bubbliiiing
    inputs = Input(shape=(416,416, 3))
    model = MobileNetV2(inputs, )
    model = Model(inputs, model)
    print(model.output[0])

在之前的yolo v3 tensorflow代码中,将model.py中的yolo_body替换成下面代码

def yolo_body(inputs, num_anchors, num_classes):
    '''
    自定义 yolobody 替换成mobilenet v2
    '''
    darknet = Model(inputs, MobileNetV2(inputs))
    x, y1 = make_last_layers(darknet.output[2], 512, num_anchors * (num_classes + 5))

    x = compose(
        DarknetConv2D_BN_Leaky(256, (1, 1)),
        UpSampling2D(2))(x)
    x = Concatenate()([x, darknet.output[1]])
    x, y2 = make_last_layers(x, 256, num_anchors * (num_classes + 5))

    x = compose(
        DarknetConv2D_BN_Leaky(128, (1, 1)),
        UpSampling2D(2))(x)
    x = Concatenate()([x, darknet.output[0]])
    x, y3 = make_last_layers(x, 128, num_anchors * (num_classes + 5))

    return Model(inputs, [y1, y2, y3])

在train.py中替换代码

# 原始代码
model = create_model(input_shape, anchors, num_classes,
            freeze_body=2, weights_path='model_data/yolo_weights.h5') # make sure you know what you freeze

# 替换之后的代码
model = create_model(input_shape, anchors, num_classes,
                             load_pretrained=False ,freeze_body=0)

重新训练

结果如下图:

yolov3实战 超简单上手 飞机与油桶数据集之替换bottlenet 为Mobilenetv2,顺便补充相关loss func_第1张图片

yolov3实战 超简单上手 飞机与油桶数据集之替换bottlenet 为Mobilenetv2,顺便补充相关loss func_第2张图片

yolov3实战 超简单上手 飞机与油桶数据集之替换bottlenet 为Mobilenetv2,顺便补充相关loss func_第3张图片
效果和之前的差不多,但是cpu的速度却快很多,GPU在速度上没有提升。而且模型大小也比之前的小。

loss 函数来自同济子豪兄yolov3实战 超简单上手 飞机与油桶数据集之替换bottlenet 为Mobilenetv2,顺便补充相关loss func_第4张图片

你可能感兴趣的:(#,目标检测,人工智能,深度学习,计算机视觉,tensorflow)