博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
探索 YOLO v3 实现细节 - 第2篇 模型
阅读量:5909 次
发布时间:2019-06-19

本文共 5294 字,大约阅读时间需要 17 分钟。

YOLO,即You Only Look Once(你只能看一次)的缩写,是一个基于卷积神经网络(CNN)的物体检测算法。而是YOLO的第3个版本,即、、,检测效果,更准更强。

YOLO v3的更多细节,可以参考YOLO的。

YOLO是一句美国的俗语,You Only Live Once,你只能活一次,即人生苦短,及时行乐。

本文主要分享,如何实现YOLO v3的算法细节,Keras框架。这是第2篇,模型。当然还有第3篇,至第n篇,毕竟,这是一个完整版 :)

本文的GitHub:

已更新:

  • 第1篇 :
  • 第2篇 :
  • 第3篇 :
  • 第4篇 :
  • 第5篇 :

欢迎关注,微信公众号 深度算法 (ID: DeepAlgorithm) ,了解更多深度技术!


入口

在训练中,调用create_model方法创建算法模型。因此,本节重点分析create_model的实现逻辑。

create_model方法中,创建YOLO v3的算法模型,其中方法参数是:

  • input_shape:输入图片的尺寸,默认是(416, 416);
  • anchors:默认的9种anchor box,结构是(9, 2);
  • num_classes:类别个数,在创建网络时,只需类别数即可。在网络中,类别值按0~n排列,同时,输入数据的类别也是用索引表示;
  • load_pretrained:是否使用预训练权重。预训练权重,既可以产生更好的效果,也可以加快模型的训练速度;
  • freeze_body:冻结模式,1或2。其中,1是冻结DarkNet53网络中的层,2是只保留最后3个1x1的卷积层,其余层全部冻结;
  • weights_path:预训练权重的读取路径;

如下:

def create_model(input_shape, anchors, num_classes, load_pretrained=True, freeze_body=2,                 weights_path='model_data/yolo_weights.h5'):复制代码

逻辑

create_model方法中,先将输入参数,进行处理:

  • 拆分图片尺寸的宽h和高w;
  • 创建图片的输入层image_input。在输入层中,既可显式指定图片尺寸,如(416, 416, 3),也可隐式指定,用“?”代替,如(?, ?, 3);
  • 计算anchor的数量num_anchors
  • 根据anchor的数量,创建真值y_true的输入格式。

具体的实现,如下:

h, w = input_shape  # 尺寸image_input = Input(shape=(w, h, 3))  # 图片输入格式num_anchors = len(anchors)  # anchor数量# YOLO的三种尺度,每个尺度的anchor数,类别数+边框4个+置信度1y_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)]复制代码

其中,真值y_true,真值即Ground Truth。“//”是Python语法中的整除符号。通过循环,创建3个Input层的列表,作为y_truey_true的张量(Tensor)结构,如下:

Tensor("input_2:0", shape=(?, 13, 13, 3, 6), dtype=float32)Tensor("input_3:0", shape=(?, 26, 26, 3, 6), dtype=float32)Tensor("input_4:0", shape=(?, 52, 52, 3, 6), dtype=float32)复制代码

其中,在真值y_true中,第1位是输入的样本数,第2~3位是特征图的尺寸,如13x13,第4位是每个图中的anchor数,第5位是:类别(n)+4个框值(xywh)+框的置信度(是否含有物体)。

接着,通过传入,输入Input层image_input、每个尺度的anchor数num_anchors//3和类别数num_classes,构建YOLO v3的网络yolo_body,这个yolo_body方法是核心逻辑。

即:

model_body = yolo_body(image_input, num_anchors // 3, num_classes)复制代码

下一步,是加载预训练权重的逻辑块:

  1. 根据预训练权重的地址weights_path,加载权重文件,设置参数为,按名称对应by_name,略过不匹配skip_mismatch
  2. 选择冻结模式:
    • 模式1是冻结185层,模式2是保留最底部3层,其余全部冻结。整个模型共有252层;
    • 将所冻结的层,设置为不可训练,model_body.layers[i].trainable=False

实现:

if load_pretrained:  # 加载预训练模型    model_body.load_weights(weights_path, by_name=True, skip_mismatch=True)    if freeze_body in [1, 2]:        # Freeze darknet53 body or freeze all but 3 output layers.        num = (185, len(model_body.layers) - 3)[freeze_body - 1]        for i in range(num):            model_body.layers[i].trainable = False  # 将其他层的训练关闭复制代码

其中,185层是DarkNet53网络的层数,而最底部3层是3个1x1的卷积层,用于预测最终结果。185层是DarkNet53网络的最后一个残差(Residual)单元,其输入和输出如下:

input: [(None, 13, 13, 1024), (None, 13, 13, 1024)]output: (None, 13, 13, 1024)复制代码

最底部3个1x1的卷积层,将3个特征矩阵转换为3个预测矩阵,其格式如下:

1: (None, 13, 13, 1024) -> (None, 13, 13, 18)2: (None, 26, 26, 512) -> (None, 26, 26, 18)3: (None, 52, 52, 256) -> (None, 52, 52, 18)复制代码

下一步,构建模型的损失层model_loss,其内容如下:

  • Lambda是Keras的自定义层,输入为model_body.outputy_true,输出output_shape是(1,),即一个损失值;
  • 自定义Lambda层的名字name为yolo_loss
  • 层的参数是锚框列表anchors、类别数num_classes和IoU阈值ignore_thresh。其中,ignore_thresh用于在物体置信度损失(object confidence loss)中过滤IoU(Intersection over Union,重叠度)较小的框;
  • yolo_loss是损失函数的核心逻辑。

实现如下:

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_body的输入(即image_input)和真值y_true
  • 模型的输出层:自定义的model_loss层,其输出是一个损失值(None,1);
  • 保存模型的网络图plot_model和打印网络结构model.summary()

即:

model = Model(inputs=[model_body.input] + y_true, outputs=model_loss) # 模型plot_model(model, to_file=os.path.join('model_data', 'model.png'), show_shapes=True, show_layer_names=True)  # 存储网络结构model.summary()  # 打印网络复制代码

其中,model_body.input是任意(?)个(416,416,3)的图片;y_true是已标注数据所转换的真值结构,即:

[Tensor("input_2:0", shape=(?, 13, 13, 3, 6), dtype=float32),  Tensor("input_3:0", shape=(?, 26, 26, 3, 6), dtype=float32),  Tensor("input_4:0", shape=(?, 52, 52, 3, 6), dtype=float32)]复制代码

最终,这些逻辑,完成算法模型model的构建。


补充1. IoU

IoU,即Intersection over Union,用于计算两个图的重叠度,用于计算两个标注框(bounding box)之间的相关度,值越高,相关度越高。在NMS(Non-Maximum Suppression,非极大值抑制)或计算mAP(mean Average Precision)中,都会使用IoU判断两个框的相关性。

如图:

实现:

def bb_intersection_over_union(boxA, boxB):    boxA = [int(x) for x in boxA]    boxB = [int(x) for x in boxB]    xA = max(boxA[0], boxB[0])    yA = max(boxA[1], boxB[1])    xB = min(boxA[2], boxB[2])    yB = min(boxA[3], boxB[3])    interArea = max(0, xB - xA + 1) * max(0, yB - yA + 1)    boxAArea = (boxA[2] - boxA[0] + 1) * (boxA[3] - boxA[1] + 1)    boxBArea = (boxB[2] - boxB[0] + 1) * (boxB[3] - boxB[1] + 1)        iou = interArea / float(boxAArea + boxBArea - interArea)    return iou复制代码

补充2. 冻结网络层

在微调(fine-tuning)中,需要确定冻结的层数和可训练的层数,主要取决于,数据集相似度和新数据集的大小。原则上,相似度越高,则固定(fix)的层数越多;新数据集越大,不考虑训练时间的成本,则可训练更多的层数。然后可能也要考虑数据集本身的类别间差异度,但上面说的规则基本上还是成立的。

例如,在图片分类的网络中,底层一般是颜色、轮廓、纹理等基础结构,显然大部分问题都由这些相同的基础结构组成,所以可以冻结这些层。层数越高,所具有泛化性越高,例如这些层会包含对鞋子、裙子和眼睛等,具体语义信息,比较敏感的神经元。所以,对于新的数据集,就需要训练这些较高的层。同时,比如一个高层神经元对车的轮胎较为敏感,不等于输入其它图像,就无法激活,因而,普通问题甚至可以只训练最后全连接层。

在Keras中,通过设置每层的trainable参数,即可控制是否冻结该层,如:

model_body.layers[i].trainable = False复制代码

OK, that's all! Enjoy it!

欢迎关注,微信公众号 深度算法 (ID: DeepAlgorithm) ,了解更多深度技术!

转载地址:http://vovpx.baihongyu.com/

你可能感兴趣的文章
搭建Cobbler自动化装机平台
查看>>
ldap快速搭建步骤版
查看>>
Dubbo入门
查看>>
5.电脑公司变卖,准备去当兵 我当程序员的那些事
查看>>
Spring Boot实践--PUT请求不能接收到参数的问题
查看>>
windows收信软件查看邮件头的方法
查看>>
网页色彩搭配教程:三个实用方法搞定网页配色设计
查看>>
mysql备份
查看>>
Sublime Text 3061 增强版 by 赵亮(碧海情天theforever)
查看>>
Eclipse常用配置
查看>>
js中 !! 的作用
查看>>
Android SDK换源
查看>>
[原创]典型Web服务器入门
查看>>
VMware/vSphere克隆主机网卡启动失败
查看>>
linux 笔记--RAID,mdadm,LVM
查看>>
【我们一起自学Python】-程序练习:购物车程序
查看>>
ElasticSearch整理 - 概念相关内容
查看>>
jvm监控工具jps,jstat,jstack,jmap的使用方法
查看>>
自动化批量部署Linux系统(Kickstart+DHCP+NFS(http)+TFTP+PXE)
查看>>
SHELL 自动备份MYSQL数据库(备份单个数据库及所有数据库)
查看>>