【华为云技术分享】物体检测yolo3算法 学习笔记(1)

2021/5/25 1:24:54

本文主要是介绍【华为云技术分享】物体检测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



这篇关于【华为云技术分享】物体检测yolo3算法 学习笔记(1)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程