文章目录
前言
上一篇文章 神奇的目标检测 已经介绍了目标检测的基础啦。目标检测呢,就是在图片中定位出目标的位置,把它“框”出来就好了。本篇文章使用Yolov3 和Yolov3-tiny,以训练VOC2007和口罩检测为例。教大家如何快速的搭建自己的目标检测平台。下面是资源链接:
内容 | 链接 |
---|---|
VOC2007 数据集 | 链接 |
戴口罩数据集 | 链接 |
权重文件 | 链接 提取码:y32m |
github项目地址 | 链接 |
完整项目地址(包含所有文件) | 链接 提取码 jmpl |
一、Yolov3 和 Yolov3-tiny
2018 年,推出了Yolov3,相比于Yolov2 最主要的改进又一下几点:
1. 加深了网络,使用Darknet53,提升了模型得检测能力。
2.使用了FPN结构(空间金字塔结构),能增强不同大小目标的检测能力。
3.使用了focal loss,解决了样本不均和分类难得问题。
对于tiny版本来说,只使用了简单的44层卷积用作普通的特征提取,只有两个输出的yolo head (Yolov3有3个yolo head)每个网格点使用两3个anchor boxes(和Yolov3一样)。所以tiny版本检测速度是很快的哦~。
优点:检测速度快,背景误检率低,泛化性强
缺点:召回率低,定位精度较差,对于靠近或遮挡的目标,小目标检测能力弱,容易出现漏检。
1.网络结构
网络结构中包含了很多基础块,我们先实现这些基本的块,然后像搭积木一样将这些块给组装起来。每个块的用途我已经写在代码注释里了。
#定义的卷积设置初始化方法和卷积步长和填充方式
@wraps(Conv2D)
def DarknetConv2D(*args, **kwargs):
"""Wrapper to set Darknet parameters for Convolution2D."""
#定义卷积块
darknet_conv_kwargs = {
'kernel_regularizer': l2(5e-4)}
darknet_conv_kwargs['padding'] = 'valid' if kwargs.get('strides')==(2,2) else 'same'
darknet_conv_kwargs.update(kwargs)
return Conv2D(*args, **darknet_conv_kwargs)
def DarknetConv2D_BN_Leaky(*args, **kwargs):
#定义的卷积块包含了BN Leaky 激活函数
"""Darknet Convolution2D followed by BatchNormalization and LeakyReLU."""
no_bias_kwargs = {
'use_bias': False}
no_bias_kwargs.update(kwargs)
return compose(
DarknetConv2D(*args, **no_bias_kwargs),
BatchNormalization(),
LeakyReLU(alpha=0.1))
def resblock_body(x, num_filters, num_blocks):
'''A series of resblocks starting with a downsampling Convolution2D'''
#定义 yolo 主干使用的残差快
# Darknet uses left and top padding instead of 'same' mode
x = ZeroPadding2D(((1,0),(1,0)))(x)
x = DarknetConv2D_BN_Leaky(num_filters, (3,3), strides=(2,2))(x)
for i in range(num_blocks):
y = compose(
DarknetConv2D_BN_Leaky(num_filters//2, (1,1)),
DarknetConv2D_BN_Leaky(num_filters, (3,3)))(x)
x = Add()([x,y])
return x
def darknet_body(x):
'''Darknent body having 52 Convolution2D layers'''
#darknet 53
#卷积核大小3x3 32 个卷积核
x = DarknetConv2D_BN_Leaky(32, (3,3))(x)
x = resblock_body(x, 64, 1)
x = resblock_body(x, 128, 2)
x = resblock_body(x, 256, 8)
x = resblock_body(x, 512, 8)
x = resblock_body(x, 1024, 4)
return x
def make_last_layers(x, num_filters, out_filters):
'''6 Conv2D_BN_Leaky layers followed by a Conv2D_linear layer'''
# 这里是输入yolo,制造最后一层的代码 也就是yolo head
x = compose(
DarknetConv2D_BN_Leaky(num_filters, (1,1)),
DarknetConv2D_BN_Leaky(num_filters*2, (3,3)),
DarknetConv2D_BN_Leaky(num_filters, (1,1)),
DarknetConv2D_BN_Leaky(num_filters*2, (3,3)),
DarknetConv2D_BN_Leaky(num_filters, (1,1)))(x)
y = compose(
DarknetConv2D_BN_Leaky(num_filters*2, (3,3)),
DarknetConv2D(out_filters, (1,1)))(x)
return x, y
yolov3-tiny
tiny 版本网络结构比较简单,我们先来看一个图:
网络中就是普通的卷积核和池化,且网络很浅,网络的计算过程如箭头所示。是不是网络很简单呀~~~~~。
我们接下来看代码如何实现。
def tiny_yolo_body(inputs, num_anchors, num_classes):
#-------------------------------------------------------------------
# inputs 输入向量 num_anchors anchor boxes的数量 num_classes 类别数
#------------------------------------------------------------------
'''Create Tiny YOLO_v3 model CNN body in keras.'''
x1 = compose(
DarknetConv2D_BN_Leaky(16, (3,3)),
MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'),
DarknetConv2D_BN_Leaky(32, (3,3)),
MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'),
DarknetConv2D_BN_Leaky(64, (3,3)),
MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'),
DarknetConv2D_BN_Leaky(128, (3,3)),
MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'),
DarknetConv2D_BN_Leaky(256, (3,3)))(inputs)
x2 = compose(
MaxPooling2D(pool_size=(2,2), strides=(2,2), padding='same'),
DarknetConv2D_BN_Leaky(512, (3,3)),
MaxPooling2D(pool_size=(2,2), strides=(1<