目标检测 YOLO 篇(2)

machine_learning.jpg

我们先来计划一下分享内容,接下来我们分享就进入了边读源码边分析过程,大概就是这个计划,今天我们来分享网络模型,先说原理然后通过代码把网络结构实现

  • 网络模型
  • 数据采集
  • 损失函数
  • 训练模型
  • 预测

YOLOv3

我们对图片分别按 13 \times 1326 \times 2652 \times 52 进行分割得到图片网格,这样做好处是我们使用不同尺寸网格来实现对图像不同大小物体都可以进行目标检测,不会丢掉小的物体,例如 52 \times 52 的网格能够识别更多物体,而且物体的体积可以更小。所以我们用 13 \times 1326 \times 2652 \times 52 网格分别识别大、中和小物体。 这样做避免小物体在多次卷积之后物体信息丢失。每个网格点负责其右下角物体检测。
如果物体的中心点落在某一个网格中,那么该网格就具有该物体位置和种类信息。 这句话很重要,希望大家能够理解。

YOLOv3 实现

我们重点就是分享 YOLOv3 是如何实现目标检测,我们根据 YOLOv3 模型结构图,一步一步来分析 YOLOv3 的目标检测算法。这是一个非常优秀的目标检测算法。为什么说优秀呢,一方面是因为 YOLOv3 表现优秀,而且算法结构还不是那么复杂。



只有大家将这张图吃透,随后才能够轻松地用代码来将其一步一步实现,不然就是只能大概读懂源码,至于每一块为什么要这样做,还是 consufing。

主干网络

左边的部分是 YOLOv3 算法的主干特征提取网络,其功能就是提取特征。

  • 输入(Input) 是 416 \times 416 \times 3 的图片
  • 接下就是一系列特征提取过程,也就是一系列卷积的过程。在卷积过程图片高和宽不断地被压缩,而通道不断扩张,这也就是下采样的过程。通过卷积我们就得到反映的图片一系列特征层。

预测网络

  • 我们截取最后 3 个特征层,分别是
    • 13 \times 13 \times 1024: 进行 5 次卷积,完成 5 次卷积后分两个方向进行前进,一个是现实为黄色块也就是对图片进行分类预测和回归预测。其实就是进行两次卷积得到13 \times 13 \times 75 ,我们输出进行分解为 13 \times 13 \times 3 \times (20 + 1 + 4)。然后我们来一个一个看这些数字都代表什么,13 \times 13 表示将图片划分为 13 \times 13 个网格,然后每一个网格上存在 3 个先验框,这些先验框就是我们预先标记在图片上,然后判断这些先验框是否包含物体,如果包含物体我们就判断这些物体种类。还需要对先验框的中心进行调整将其调整到正确位置上。那么 20,1 和 4 有分别代表什么 1 代表先验框置信度也就是表示先验框中是否有物体,4 表示先验框的位置,20 是因为我们使用 VOC 数据集有 20 种类的数据集,这个可以根据自己的数据集而定。
      然后这个特征层还有一个去处就是对特征层进行进行上采样(也就是增加图片尺寸缩减通道数的过程)然后和 26 \times 26 \times 512进行堆叠,所谓堆叠就是将他们通道维度上进行合并。这样就是将52 \times 52 \times 256再次利用用于在 26 \times 26 网格上提取特征过程。
    • 26 \times 26 \times 512
      52 \times 52 \times 256 堆叠后也需要进行 5 次卷积。得到26 \times 26 \times 75 过程和上面类似,这里不做过多的赘述了。然后同样这个特征也会通过一次上采样后和 13 \times 13 \times 1024
    • 52 \times 52 \times 256

实现主体网络

from keras.models import Model
from keras.layers import Input

model_input = Input(shape(416,416,3))

model = Modle(model_input,model_output)
  • 输入是 (416 \times 416) 的图片
  • 输出两个表示不同大小(维度)的数组
model_input = Input(shape(416,416,3))
model_output = body(model_input)
model = Modle(model_input,model_output)

接下来工作就是搭建 yolov3 的主题网络,也称称为 backbone 网络,用于提取不同尺寸大小的特征图,Darknet53.要写好代码我们就需要熟悉 yolo 网络结构,然后按照结构图一层一层的实现

def body(inputs,num_anchors,num_classes):

我们都已经知道主体网络用于提取特征,body 方法用于构建主体网络,接收 3 个参数分别

  • inputs: 输入,通常是一张416 \times 416 \times 3 的图片
  • num_anchors: 每一个网格生成的多少个预选框
  • num_classes: 表示分类种类数量
return [y1,y2,y3]

那么输出就是 3 种不同尺寸的


我们对照图来一层一层写代码来实现设计图中的层或块,其实我们实现深度学习算法通常做法是打开一个设计好网络结构图,然后对照图一行一行地实现。图中的乘 1 ,乘 2 表示该块重复次数,

块名称 数量 filters size output
CBL 1 32 3 \times 3 416 \times 416 \times 32
PCBL 1 32 3 \times 3/2 208 \times 208 \times 64
CBLR 1 32 1 \times 1
1 64 3 \times 3 208 \times 208 \times 64
PCBL 1 128 3 \times 3/2 104 \times 104 \times 128
CBLR 1 64 1 \times 1
8 256 3 \times 3 104 \times 104 \times 128
PCBL 1 256 3 \times 3/2 52 \times 52 \times 256
CBLR 1 128 1 \times 1
8 256 3 \times 3 52 \times 52 \times 256
PCBL 1 512 3 \times 3/2 26 \times 26 \times 512
CBLR 1 256 1 \times 1
8 512 3 \times 3 26 \times 26 \times 512
PCBL 1 1024 3 \times 3/2 13 \times 13 \times 1024
CBLR 1 512 1 \times 1
4 1024 3 \times 3 13 \times 13 \times 1024
def body(inputs,num_anchors,num_classes):
    out = []
    x = CBL(inputs,32,(3,3))
    n = [1,2,8,8,4]
    for i in range(5):
        x = PCBL(x,2**(6+i))
        for _ in range(n[i]):
            x = CBLR(x,2**(5+i))

        if i in [2,3,4]:
            out.append(x)

通过 for 循环我们将重复部分提炼出来,n = [1,2,8,8,4] 然后我们图中每一个重复块前还有一个

在 CBL 中使用到的卷积 conv

定义卷积 conv 方法

卷积用到的参数有字典参数和列表参数

  • 列表用一个星号
  • 字典用两个星号
def conv(x):
def conv(*args,**kwargs):
    new_kwargs = {'kernel_regularizer':l2(5e-4)}
    new_kwargs['padding'] = 'valid' if kwargs.get('strides') == (2,2) else 'same'
    new_kwargs.update(kwargs)

    return Conv2D(*args,**new_kwargs)

定义 CBL 层(块)

CBL 是我们网络结构的基础,也是出现最多结构,其结构包括以下部分

  • Conv 表示卷积层
  • BN 表示归一化
  • LeakyRelu 激活函数
def CBL(x,*args,**kwargs):
    new_kwargs ={ 'use_bias': False}
    new_kwargs.update(kwargs)
    x = conv(*args,**new_kwargs)(x)
    x = BatchNormalization()(x)
    x = LeakyReLU(alpha=0.1)(x)

这里用到了 L2 正则,L2 正则是控制参数
我们通过卷积的步长(stride)来决定卷积,其实这些都卷积的基础知识。我们
引入依赖

from keras.regularizers import l2
from keras.layers import Conv2D

定义 PCBL 块

用于在完成每一个块对卷积结果进行一次下采样,功能等于一个池化层将通过 stride=(2,2) 将图片长宽缩小为原来的 \frac{1}{2}

def PCBL(x,num_filters):
    x = ZeroPadding2D(((1,0),(1,0)))(x)
    x = CBL(x,num_filters,(3,3),strides=(2,2))

    return x

CBLR 块

CBLR 就是我们在图中重复结构,显示一个 1 \times 1 卷积,用于对通道数减半的卷积,接下拉就是3 \times 3 卷积层同时将通道数翻倍。随后一个将输入和输出在通道上进行叠加通道数翻倍。

def CBLR(x,num_filters):
    y = CBL(x,num_filters,(1,1))
    y = CBL(y,num_filters*2,(3,3))
    x = Add()([x,y])

    return x

检测网络

屏幕快照 2020-05-24 下午3.55.08.png

接下来将主干网络提取特征通过处理输出我们之前提到的 3 中不同尺寸的矩阵

    x1 = CBL5(out[2],512)
    y1 = CBLC(x1,512,num_anchors*(num_classes+5))

    x = CBLU(x1,256)
    x = Concatenate()([x,out[1]])

    x2 = CBL5(x,256)
    y2 = CBLC(x2, 256, num_anchors * (num_classes + 5))

    x = CBLU(x2,128)
    x = Concatenate()([x, out[0]])

    x3 = CBL5(x,128)
    y3 = CBLC(x3, 128, num_anchors * (num_classes + 5))

    return [y1,y2,y3]

CBL5 层

这个解构就是

def CBL5(x,num_filters):
    x = CBL(x, num_filters, (1,1))
    x = CBL(x, num_filters*2, (3,3))
    x = CBL(x, num_filters, (1,1))
    x = CBL(x, num_filters*2, (3,3))
    x = CBL(x, num_filters, (1,1))

    return x

CBLC

def CBLC(x,num_filters,out_filters):
    x = CBL(x, num_filters * 2, (3, 3))
    x = conv(out_filters,(1,1))(x)

    return x

CBLU 层

在 CBL 层上添加一个上采样层,经过 CBLU 后宽度和长度翻倍便于参加网格较大尺寸的层输出。例如13 \times 13 会经过 CBLU 扩大为26 \times 26

def CBLU(x, num_filters):
    x = CBL(x, num_filters, (1, 1))
    x = UpSampling2D(2)(x)

    return x
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343