Darknet_Yolov3模型搭建

YOLO(You only look once)是目前流行的目标检测模型之一,目前最新已经发展到V3版本了,在业界的应用也很广泛。YOLO的特点就是“快”,但由于YOLO对每个网格只预测一个物体,就容易造成漏检,对物体的尺度相对比较敏感,对于尺度变化较大的物体泛化能力较差。YOLO的基本原理是:首先对输入图像划分成7x7的网格,对每个网格预测2个边框,然后根据阈值去除可能性比较低的目标窗口,最后再使用边框合并的方式去除冗余窗口,得出检测结果,如下图:

Darknet卷积模块

Yolo系列的作者把yolo网络叫做Darknet,其实其他神经网络库都已经把卷积层写好了,直接堆叠起来即可。

darknet卷积模块是这个模型里最基本的网络单元,包括卷积层、batch norm(BN)层、激活函数,因此类型命名为 DarknetConv2D_BN_Leaky。原keras实现是卷积层加了L2正则化预防过拟合,Pytorch是把这个操作放到了Optimizer中,所以将在第三部分讲解。

用Pytorch需要注意, 如果训练的时候GPU显存不大,batch size设的很小,这时候就要考虑训练数据集的分布情况。举个例子,加入的batch size设成了1,但数据每张图差别都很大,这会导致的网络一直在震荡,即使网络能够训练到很低的training loss,

在做预测的时候效果也不好,这主要是BN造成的。因为每批数据的统计量(均值和方差)都不同,而且差别大,这就导致网络训练学不到好的BN层的统计量。如果直接去掉BN层,会发现网络训练非常慢,所以BN层还是要加的,好在Pytorch里的BN有个接口来控制要不要记住每批训练的统计量,即track_running_stats=True,如果训练的batch size不能设特别大,就把它改成False。

卷积层、BN层说完了,激活函数Yolo里用的是0.1的LeakReLU,本实验与ReLU没什么明显的区别。

结构很简答,这部分直接上代码,不画图了。

import torch.nn as nn

import torch

class DarknetConv2D_BN_Leaky(nn.Module):

def __init__(self, numIn, numOut, ksize, stride = 1, padding = 1):

super(DarknetConv2D_BN_Leaky, self).__init__()

self.conv1 = nn.Conv2d(numIn, numOut, ksize, stride, padding)#regularizer': l2(5e-4)

self.bn1 = nn.BatchNorm2d(numOut)

self.leakyReLU = nn.LeakyReLU(0.1)

def forward(self, x):

x = self.conv1(x)

x = self.bn1(x)

x = self.leakyReLU(x)

return x

残差模块

残差模块是借鉴了ResNet,残差模块是为了保证深的模型能够得到很好的训练。残差模块ResidualBlock,对外接口有numIn, numOut, numBlock,分别控制模块的输入通道数,输出通道数(卷积核数)和残差模块的堆叠次数。下图是一个numBlock = 2 的模型,注意这里CONV是指上一部分说的Darknet卷积模块,第一个模块(D2)表示是这个卷积模块stride = 2,顺便执行了2倍降采样操作。也就是说特征每经过一个残差模块,分辨率降为原来的一半。

class ResidualBlock(nn.Module):

def __init__(self, numIn, numOut, numBlock):

super(ResidualBlock, self).__init__()

self.numBlock = numBlock

self.dark_conv1 = DarknetConv2D_BN_Leaky(numIn, numOut, ksize = 3, stride = 2, padding = 1)

self.dark_conv2 = []

for i in range(self.numBlock):

layers = []

layers.append(DarknetConv2D_BN_Leaky(numOut, numOut//2, ksize = 1, stride = 1, padding = 0))

layers.append(DarknetConv2D_BN_Leaky(numOut//2, numOut, ksize = 3, stride = 1, padding = 1))

self.dark_conv2.append(nn.Sequential(*layers))

self.dark_conv2 = nn.ModuleList(self.dark_conv2)

def forward(self, x):

x = self.dark_conv1(x)

for convblock in self.dark_conv2:

residual = x

x = self.convblock(x)

x = x + residual

return x

后端输出模块

后端输出模块是一个三次降采样(三次升采样在下一部分介绍),这三次降采样+三次升采样,类似Encoder-Decoder的FCN模型。这是为了在三种不同尺度上预测。本系列将在voc2007上训练,训练前输入图片要resize到256x256,那么这三种尺度分别是32x32,16x16,8x8。这一部分是因为图片中的目标有大有小,为了保证从不同尺度上找到最好尺度的特征图来进行预测。当然准确提升的同时,由于分辨率有提升,计算量又有一定的增加,索性这里的分辨率不大。下图所示为最后输出模块,这个模块有两个输出,一个是用作下一个模块的输入,一个是用于输出目标检测结果,即坐标、类别和目标置信度,这一部分将在下一篇详细介绍。注意红色的Conv不是DarknetConv2D_BN_Leaky,而是指普通的卷积模块。

class LastLayer(nn.Module):

def __init__(self, numIn, numOut, numOut2):

super(LastLayer, self).__init__()

self.dark_conv1 = DarknetConv2D_BN_Leaky(numIn, numOut, ksize = 1, stride = 1, padding = 0)

self.dark_conv2 = DarknetConv2D_BN_Leaky(numOut, numOut*2, ksize = 3, stride = 1, padding = 1)

self.dark_conv3 = DarknetConv2D_BN_Leaky(numOut*2, numOut, ksize = 1, stride = 1, padding = 0)

self.dark_conv4 = DarknetConv2D_BN_Leaky(numOut, numOut*2, ksize = 3, stride = 1, padding = 1)

self.dark_conv5 = DarknetConv2D_BN_Leaky(numOut*2, numOut, ksize = 1, stride = 1, padding = 0)

self.dark_conv6 = DarknetConv2D_BN_Leaky(numOut, numOut*2, ksize = 3, stride = 1, padding = 1)

self.conv7 = nn.Conv2d(numOut*2, numOut2, 1, stride = 1, padding = 0)

def forward(self, x):

x = self.dark_conv1(x)

x = self.dark_conv2(x)

x = self.dark_conv3(x)

x = self.dark_conv4(x)

x = self.dark_conv5(x)

y = self.dark_conv6(x)

y = self.conv7(y)

return x,y

Yolov3模型

基本的模块已经定义好,Yolov3的模型就是把这些模型叠加起来。注意下图就是Yolov3的简化模型,数字表示该上一个模块的输出特征尺寸(CxHxW),相应的颜色对应相应的模块。

class Yolov3(nn.Module):

def __init__(self, numAnchor, numClass):

super(Yolov3, self).__init__()

self.dark_conv1 = DarknetConv2D_BN_Leaky(3, 32, ksize = 3, stride = 1, padding = 1)

self.res1 = ResidualBlock(32, 64, 1)

self.res2 = ResidualBlock(64, 128, 2)

self.res3 = ResidualBlock(128, 256, 8)

self.res4 = ResidualBlock(256, 512, 8)

self.res5 = ResidualBlock(512, 1024, 4)

self.last1 = LastLayer(1024, 512, numAnchor*(numClass+5))

self.up1 = nn.Sequential(DarknetConv2D_BN_Leaky(512, 256, ksize = 1, stride = 1, padding = 0),

nn.Upsample(scale_factor=2))

self.last2 = LastLayer(768, 256, numAnchor*(numClass+5))

self.up2 = nn.Sequential(DarknetConv2D_BN_Leaky(256, 128, ksize = 1, stride = 1, padding = 0),

nn.Upsample(scale_factor=2))

self.last3 = LastLayer(384, 128, numAnchor*(numClass+5))

def forward(self, x):

x = self.dark_conv1(x)#32x256x256

x = self.res1(x)#64x128x128

x = self.res2(x)#128x64x64

x3 = self.res3(x)#256x32x32

x4 = self.res4(x3)#512x16x16

x5 = self.res5(x4)#1024x8x8

x,y1 = self.last1(x5)#512x8x8,

x = self.up1(x)#256x16x16

x = torch.cat((x, x4), 1)#768x16x16

x,y2 = self.last2(x)#256x16x16

x = self.up2(x)#128x32x32

x = torch.cat((x, x3), 1)#384x32x32

x,y3 = self.last3(x)#128x32x32

return y1,y2,y3

到这里模型已经完成,模型代码结构非常清晰。有人可能会问,为什么要这种堆叠方式,其实自己根据新的需求定义网络结构完全可以,但是要注意模型深度增加时如何保证收敛,如何加速模型训练,同时输出特征的分辨率要计算好。

Darknet_Yolov3模型搭建的更多相关文章

  1. 一周总结:AutoEncoder、Inception 、模型搭建及下周计划

    一周总结:AutoEncoder.Inception .模型搭建及下周计划   1.AutoEncoder: AutoEncoder: 自动编码器就是一种尽可能复现输入信号的神经网络:自动编码器必须捕 ...

  2. 入门项目数字手写体识别:使用Keras完成CNN模型搭建(重要)

    摘要: 本文是通过Keras实现深度学习入门项目——数字手写体识别,整个流程介绍比较详细,适合初学者上手实践. 对于图像分类任务而言,卷积神经网络(CNN)是目前最优的网络结构,没有之一.在面部识别. ...

  3. Puppet master-agent模型搭建

    Puppet master-agent模型工作过程: 基于ssl xmlrpc进行通信,端口8140/tcp agent:默认每隔30分钟向master发送node name和facts,并请求cat ...

  4. 模型搭建练习2_实现nn模块、optim、two_layer、dynamic_net

    用variable实现nn.module import torch from torch.autograd import Variable N, D_in, H, D_out = 64, 1000, ...

  5. 模型搭建练习1_用numpy和tensor、variable实现前后向传播、实现激活函数

    用numpy实现搭建一个简单的forward和backward import numpy as np N, D_in, H, D_out = 64, 1000, 100, 10 x = np.rand ...

  6. 从零搭建Pytorch模型教程(三)搭建Transformer网络

    ​ 前言 本文介绍了Transformer的基本流程,分块的两种实现方式,Position Emebdding的几种实现方式,Encoder的实现方式,最后分类的两种方式,以及最重要的数据格式的介绍. ...

  7. Python中利用LSTM模型进行时间序列预测分析

    时间序列模型 时间序列预测分析就是利用过去一段时间内某事件时间的特征来预测未来一段时间内该事件的特征.这是一类相对比较复杂的预测建模问题,和回归分析模型的预测不同,时间序列模型是依赖于事件发生的先后顺 ...

  8. 使用webgl(three.js)搭建一个3D建筑,3D消防模拟——第三课

    项目背景 消防安全一直是各大都市关注的重要课题,在消防体系中,特别是高楼消防体系中,消防系统整体布控与监控,火情有效准确定位,防火器材定位,人员逃生路径规划,火情预警,消防演习都是特别重要的环节.所以 ...

  9. simulink创建简单模型

    创建简单模型 您可以使用 Simulink® 对系统建模,然后仿真该系统的动态行为.Simulink 允许您创建模块图,图中的各个连接模块代表系统的各个部分,信号代表这些模块之间的输入/输出关系.Si ...

随机推荐

  1. 11- APP性能测试GT工具的使用

    对性能测试来说有服务端的性能与客户端(APP)的性能. GT简介 1.GT(随身调)是APP的随身调测平台,它是直接运行在手机上的"集成调试环境"(IDTE) 2.利用GT,仅凭一 ...

  2. 命令行运行py文件报错

    起因 今天用ubuntu 终端运行py文件报了个错,找不到模块? 我切换回pycharm中运行,运行一切正常 解决 在报错模块中,插入绝对路径 import sys sys.path.append(' ...

  3. 缓冲区溢出分析第05课:编写通用的ShellCode

    前言 我们这次的实验所要研究的是如何编写通用的ShellCode.可能大家会有疑惑,我们上次所编写的ShellCode已经能够很好地完成任务,哪里不通用了呢?其实这就是因为我们上次所编写的ShellC ...

  4. Win64 驱动内核编程-31.枚举与删除映像回调

    枚举与删除映像回调 映像回调可以拦截 RING3 和 RING0 的映像加载.某些游戏保护会用此来拦截黑名单中的驱动加载,比如 XUETR.WIN64AST 的驱动.同理,在反游戏保护的过程中,也可以 ...

  5. 推荐算法-聚类-K-MEANS

    对于大型的推荐系统,直接上协同过滤或者矩阵分解的话可能存在计算复杂度过高的问题,这个时候可以考虑用聚类做处理,其实聚类本身在机器学习中也常用,属于是非监督学习的应用,我们有的只是一组组数据,最终我们要 ...

  6. Ravindrababu Ravula老师的数据结构与算法

    最关键的问题是,作为印度裔,他的英语口音真的真的很好懂!!!而且语速很慢,适合大家学习. 作为一哥热衷于搬砖的小伙,我将他的视频搬运到了B站,大家可以前往我的B站观看,搜索"爱码士Noe&q ...

  7. 第四部分 数据搜索之使用HBASE的API实现条件查询

    因为数据清洗部分需要用到Mapreduce,所以先解决hbase的问题,可以用命令先在hbase存一下简单的数据进行查询,之后只要替换数据就可以实现了原本功能 在看该部分前,确保Hase API看了, ...

  8. 【c#】 使用Directory.GetFiles获取局域网中任意电脑指定文件夹下的文件

    本文为老魏原创,如需转载请留言 格式如下: // 获取IP地址为10.172.10.167下D盘下railway下的所有文件 string[] picArray = Directory.GetFile ...

  9. 一句 Task.Result 就死锁, 这代码还怎么写?

    一:背景 1. 讲故事 前些天把 .NET 高级调试 方面的文章索引到 github 的过程中,发现了一个有意思的评论,详见 文章,截图如下: 大概就是说在 Winform 的主线程下执行 Task. ...

  10. [re模块、json&pickle模块]

    [re模块.json&pickle模块] re模块 什么是正则? 正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法.或者说:正则就是用来描述一类事物的规则 ...