YoloV3网络见解与模型搭建

    这几天看了下yolo的第三个改进版本,代码的链接https://github.com/qqwweee/keras-yolo3。并没有从头阅读所有代码,只是看了自己感觉的关键点。yolo3想比较于yolo2的改进在于,使用不同的特征尺度来预测物体,这点和SSD多尺度是类似的。输入尺寸还是416×416,使用3个输出分别为52×52,26×26,13×13。这三个输出分别采用不同的anchor_box,论文中是采用3个。这些anchor_box依然是采用k-means算法对样本的长宽聚类得来的。yolo2中,输出一共有13×13×5=845个预测框,对于小目标的定位并不太好。因此,对于yolo3采用不同卷积层的特征图进行物体预测,对于小目标的定位会更加好一点,一共预测52×52×3+26×26×3+13×13×3=10647个预测框。对于网络模型的输入输出来讲,可以使用代码大概说一下。由于本人比较懒,并没有针对特定的数据集进行验证模型的好坏,不能记录模型的孰优孰劣和训练需要注意的事项等,不过我使用伪造的数据集,采用上一章节yolov2的损失函数和输入输出,分别构建了yolov2和yolov3模型并进行运行,并没有任何问题。因此,只要掌握网络算法的核心流程就可以自己搭建想要的网络结构并进行训练和调参,并不要局限与别人的代码,掌握思想最重要。yolo3的多输出label构建和yolov2是类似的。具体说下需要注意的点:

    原始yolov3中,三个输出层中,每层预测3个框,一共9个框。那么构建label时要选择与9个框中IOU最大的那个进行打上实际box和置信度,其他8个全部为0。每一层并不是单独的存在,只标注IOU最大的。不过我们也可以不考虑这些,每一层单独考虑去选择3个框中最大的IOU进行打上实际box。这样的模型就类似与集成学习,每一层输出都是独立的,和SSD类似。这里3层输出每一层的3个框都是独立聚类得到的,这点需要注意。下面简单说下模型搭建,并没有进行整理,定义比较乱,请见谅:

定义网络输入,其中true_boxes,true_boxes1,true_boxes2是相同的data,是图片中真实目标的x,y,h,w,10代表最大目标数,输入图片416×416×3
input_image = Input(shape=(416, 416, 3))
true_boxes = Input(shape=(1, 1, 1, 10 , 4))
true_boxes1 = Input(shape=(1, 1, 1, 10 , 4))
true_boxes2 = Input(shape=(1, 1, 1, 10 , 4))

def my_net():
    # Layer 1
    x = Conv2D(16, (3, 3), strides=(1, 1), padding='same', name='conv_1', use_bias=False)(input_image)
    x = BatchNormalization(name='norm_1')(x)
    x = LeakyReLU(alpha=0.1)(x)
    x = MaxPooling2D(pool_size=(2, 2))(x)
    # Layer 2 - 5

    x = Conv2D(32 * (2 ** 0), (3, 3), strides=(1, 1), padding='same', name='conv_' + str(0 + 2), use_bias=False)(x)
    x = BatchNormalization(name='norm_' + str(0 + 2))(x)
    x = LeakyReLU(alpha=0.1)(x)
    x = MaxPooling2D(pool_size=(2, 2))(x)

    x = Conv2D(32 * (2 ** 1), (3, 3), strides=(1, 1), padding='same', name='conv_' + str(1 + 2), use_bias=False)(x)
    x = BatchNormalization(name='norm_' + str(1 + 2))(x)
    x = LeakyReLU(alpha=0.1)(x)
    x = MaxPooling2D(pool_size=(2, 2))(x)
    ####52到这里进行一次输出预测 特征图(52,52)
    output1 = Conv2D(5 * (4 + 1 + 1),
                    (1, 1), strides=(1, 1),
                    padding='same',
                    name='DetectionLayer1',
                    kernel_initializer='lecun_normal')(x)
    output1 = Reshape((52, 52, 5, 4 + 1 + 1))(output1)
    output1 = Lambda(lambda args: args[0])([output1, true_boxes])
    x = Conv2D(32 * (2 ** 2), (3, 3), strides=(1, 1), padding='same', name='conv_' + str(2 + 2), use_bias=False)(x)
    x = BatchNormalization(name='norm_' + str(2 + 2))(x)
    x = LeakyReLU(alpha=0.1)(x)
    x = MaxPooling2D(pool_size=(2, 2))(x)
    ####26到这里再进行一次输出预测 特征图(26,26)
    output2 = Conv2D(5 * (4 + 1 + 1),
                    (1, 1), strides=(1, 1),
                    padding='same',
                    name='DetectionLayer2',
                    kernel_initializer='lecun_normal')(x)
    output2 = Reshape((26, 26, 5, 4 + 1 + 1))(output2)
    output2 = Lambda(lambda args: args[0])([output2, true_boxes])
    x = Conv2D(32 * (2 ** 3), (3, 3), strides=(1, 1), padding='same', name='conv_' + str(3 + 2), use_bias=False)(x)
    x = BatchNormalization(name='norm_' + str(3 + 2))(x)
    x = LeakyReLU(alpha=0.1)(x)
    x = MaxPooling2D(pool_size=(2, 2))(x)
    # Layer 6
    x = Conv2D(512, (3, 3), strides=(1, 1), padding='same', name='conv_6', use_bias=False)(x)
    x = BatchNormalization(name='norm_6')(x)
    x = LeakyReLU(alpha=0.1)(x)
    # a = x.get_shape()
    # print(a)

    x = MaxPooling2D(pool_size=(2, 2), strides=(1, 1), padding='same')(x)

    # Layer 7 - 8
    for i in range(0, 2):
        x = Conv2D(1024, (3, 3), strides=(1, 1), padding='same', name='conv_' + str(i + 7), use_bias=False)(x)
        x = BatchNormalization(name='norm_' + str(i + 7))(x)
        x = LeakyReLU(alpha=0.1)(x)
#######最后进行预测  特征图(13,13)
    output = Conv2D(5 * (4 + 1 +1),
                    (1, 1), strides=(1, 1),
                    padding='same',
                    name='DetectionLayer',
                    kernel_initializer='lecun_normal')(x)
    output = Reshape((13, 13, 5, 4 + 1 + 1))(output)
    output = Lambda(lambda args: args[0])([output,true_boxes])

    model = Model([input_image, true_boxes],[output1,output2,output])
    return model

    模型定义好以后,使用上一章节的损失函数。一共三个输出,所以需要定义3个loss_function,但是这里也可以在最后输出层构建一个Lambda层损失函数,那样只需要1个loss_function,上面github上项目就是这样定义的。模型图使用https://blog.csdn.net/leviopku/article/details/82660381文章,大家可以看看。本次模型和下面的模型图有一点差异在于分支处,并没有使用Unsample进行特征拼接,采用SSD中直接进行分叉预测。有什么不懂的可以留言或者邮箱给我。邮箱zhsklearn@163.com

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值