zoukankan      html  css  js  c++  java
  • 【华为云技术分享】物体检测yolo3算法 学习笔记(1)

    【摘要】 YOLO作为一个one-stage目标检测算法,在速度和准确度上都有杰出的表现。而YOLO v3是YOLO的第3个版本(即YOLO、YOLO 9000、YOLO v3),检测效果,更准更强。

    YOLO场景运用: YOLO作为一个one-stage目标检测算法,在速度和准确度上都有杰出的表现。

    在ModelArts 实战营第四期中,我们学习使用了YOLO V3算法进行的物体检测训练和推理,这里对notebook代码的学习做个整理

     

    准备数据

    有很多开源的数据集可以用来进行目标检测任务的训练,如COCO数据集,PASCAL VOC数据集,BDD100K等,可以根据不同的需求和偏好进行选择。在获得数据集之后,需要对数据进行格式统一,然后便可以进行训练了。

    本案例中使用的是COCO数据集,

    解压后图片文件路径:data_path = "./coco/coco_data",

     

    一、参数

    1、标注信息

    coco数据标注信息文件存储位置:

    annotation_path = './coco/coco_train.txt'

    格式如下:

    图片的文件名 框的四个坐标(xmin,ymin,xmax,ymax,label_id)

    923 168,131,289,270,6

    400 1,64,636,477,8

    ... ...

    2、coco类型

    coco类型定义文件存储位置,

    classes_path = './model_data/coco_classes.txt'

    共有80个分类:

    person

    bicycle

    car

    motorbike

    aeroplane

    bus

    train

    truck

    boat

    traffic light

    ... ...

    3、预测特征图(Prediction Feature Map)的anchor框(anchor box)集合

    coco数据anchor值文件存储位置:

    anchors_path = './model_data/yolo_anchors.txt'

    • 3个尺度(scale)的特征图,每个特征图3个anchor框,共9个框,从小到大排列;

    • 1 ~ 3是大尺度(52x52)特征图所使用的,4 ~ 6是中尺度(26x26),7 ~ 9是小尺度(13x13)

    • 大尺度特征图检测小物体,小尺度检测大物体;

    • 9个anchor来源于边界框(Bounding Box)的k-means聚类。

    COCO的anchors,如下:

    [[ 10.,  13.],       [ 16.,  30.],       [ 33.,  23.],       [ 30.,  61.],       [ 62.,  45.],       [ 59., 119.],       [116.,  90.],       [156., 198.],       [373., 326.]]

    4、预训练模型

    用于迁移学习(Transfer Learning)中的微调(Fine Tune),支持使用已训练完成的COCO模型参数,即:

    预训练权重文件存储位置:

    weights_path = "./model_data/yolo.h5"

    # 模型文件存储位置

    save_path = "./result/models/"

    5、图片输入尺寸

    默认为416x416。图片尺寸满足32的倍数,在DarkNet网络中,含有5次步长为2的降采样卷积(32=2^5),其中,卷积操作如下:

    x = DarknetConv2D_BN_Leaky(num_filters, (3, 3), strides=(2, 2))(x)

    在最底层时,特征图尺寸需要满足为奇数,如13,以保证中心点落在唯一框中。当为偶数时,则导致中心点落在中心的4个框中。

     

    二、创建模型

    创建YOLOv3的网络模型,输入:

    • input_shape:图片尺寸

    • anchors:9个anchor box;

    • num_classes:类别数;

    • weights_path:预训练模型的权重

    实现如下:

    # 初始化session

    K.clear_session()

    input_shape = (416,416)

    image_input = Input(shape=(None, None, 3))

    h, w = input_shape

    # 对模型预测结果形状进行定义

    y_true = [Input(shape=(h//{0:32, 1:16, 2:8}[l], w//{0:32, 1:16, 2:8}[l], num_anchors//3, num_classes+5))

             for l in range(3)]

    # 构建YOLO模型结构

    model_body = yolo_body(image_input, num_anchors//3, num_classes)

    # 将YOLO权重文件加载进来,如果希望不加载预训练权重,从头开始训练的话,可以将这条语句删掉

    model_body.load_weights(weights_path, by_name=True, skip_mismatch=True)

    # 定义YOLO损失函数

    model_loss = Lambda(yolo_loss,

                       output_shape=(1,), name='yolo_loss',

                       arguments={'anchors': anchors, 'num_classes': num_classes, 'ignore_thresh': 0.5})(

       [*model_body.output, *y_true])

    # 构建Model,为训练做准备

    model = Model([model_body.input, *y_true], model_loss)

    三、划分数据集

    val_split = 0.1

    with open(annotation_path) as f:

    lines = f.readlines()

    np.random.seed(10101)

    np.random.shuffle(lines)

    np.random.seed(None)

    num_val = int(len(lines)*val_split)

    num_train = len(lines) - num_val

    样本洗牌(shuffle),将数据集拆分为10份,训练9份,验证1份。

     

    四、第1阶段训练过程

    第1阶段,冻结部分网络,训练底层参数,优化器使用Adam;

    损失函数,直接使用模型的输出y_pred,忽略真值y_true;

    代码如下:

    model.compile(optimizer=Adam(lr=1e-4), loss=

    # 使用定制的 yolo_loss Lambda层

    {'yolo_loss': lambda y_true, y_pred: y_pred})  # 损失函数

    对于损失函数yolo_loss,以及y_true和y_pred:

    把y_true当成一个输入,构成多输入模型,把loss写成层(Lambda层),作为最后的输出。这样,构建模型的时候,就只需要将模型的输出(output)定义为loss即可。而编译(compile)的时候,直接将loss设置为y_pred,因为模型的输出就是loss,即y_pred就是loss,因而无视y_true。训练的时候,随便添加一个符合形状的y_true数组即可。

    模型训练,使用数据生成包装器(data_generator_wrapper),按批次生成训练和验证数据。最终,模型model存储权重。实现如下:

    # 开始训练

    batch_size = 16

    print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))

    model.fit_generator(data_generator_wrapper(lines[:num_train], batch_size, input_shape, data_path,anchors, num_classes),

    steps_per_epoch=max(1, num_train//batch_size),

    validation_data=data_generator_wrapper(lines[num_train:], batch_size, input_shape, data_path,anchors, num_classes),

    validation_steps=max(1, num_val//batch_size),

    epochs=5,

    initial_epoch=0,

    callbacks=[reduce_lr, early_stopping])

    保存训练数据

    import os

    os.makedirs(save_path)

    # 存储第1阶段的参数,再训练过程中,也通过回调存储

    model.save_weights(log_dir + 'trained_weights_stage_1.h5')

    在训练过程中,也会存储模型的参数,只存储权重(save_weights_only),只存储最优结果(save_best_only),每隔3个epoch存储一次(period),即:

    checkpoint = ModelCheckpoint(log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',

    monitor='val_loss', save_weights_only=True,

    save_best_only=True, period=3)  # 只存储weights权重

     

    五、第2阶段训练

    第2阶段,使用第1阶段已训练的网络权重,继续训练:

    将全部的参数都设置为可训练,而第1阶段则是冻结(freeze)部分参数;

    优化器,仍是Adam,只是学习率(lr)有所下降,从1e-3减少至1e-4,细腻地学习最优参数;

    损失函数,仍是只使用y_pred,忽略y_true。

    for i in range(len(model.layers)):

    model.layers[i].trainable = True

    model.compile(optimizer=Adam(lr=1e-4), loss={'yolo_loss': lambda y_true, y_pred: y_pred})

    第2阶段的模型fit数据,与第1阶段类似,从第5个epoch开始,一直训练到第10个epoch,触发条件则提前终止。

    额外增加了两个回调reduce_lr和early_stopping

    # 定义callbacks方法

    reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3, verbose=1)

    early_stopping = EarlyStopping(monitor='val_loss', min_delta=0, patience=10, verbose=1)

    reduce_lr:当评价指标不在提升时,减少学习率,每次减少10%(factor),当学习率3次未减少(patience)时,终止训练。

    early_stopping:验证集准确率,连续增加小于0(min_delta)时,持续10个epoch(patience),则终止训练。

    batch_size = 16

    print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))

    model.fit_generator(data_generator_wrapper(lines[:num_train], batch_size, input_shape, data_path,anchors, num_classes),

    steps_per_epoch=max(1, num_train//batch_size),

    validation_data=data_generator_wrapper(lines[num_train:], batch_size, input_shape, data_path,anchors, num_classes),

    validation_steps=max(1, num_val//batch_size),

    epochs=10,

    initial_epoch=5,

    callbacks=[reduce_lr, early_stopping])

    至此,在第2阶段训练完成之后,输出的网络参数,就是最终的模型参数。

    作者:hellfire

  • 相关阅读:
    华科机考:特殊排序
    华科机考:排序
    华科机考:字符串连接
    华科机考:a+b
    华科机考:IP地址
    华科机考:统计单词
    iOS 应用评分
    jQuery Custom PopUp Window
    Csharp:字符串操作
    Css:Conditional comments 条件注释
  • 原文地址:https://www.cnblogs.com/2020-zhy-jzoj/p/13164838.html
Copyright © 2011-2022 走看看