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. Dalvik模式下System.loadLibrary函数的执行流程分析

    本文博客地址:http://blog.csdn.net/qq1084283172/article/details/78212010 Android逆向分析的过程中免不了碰到Android so被加固的 ...

  2. Windows核心编程 第四章 进程(中)

    4.2 CreateProcess函数 可以用C r e a t e P r o c e s s函数创建一个进程: BOOL CreateProcessW( _In_opt_ LPCWSTR lpAp ...

  3. CTF密码学常见加解密总结

    CTF密码学常见加解密总结 2018年03月10日 19:35:06 adversity` 本文链接:https://blog.csdn.net/qq_40836553/article/details ...

  4. 通过 Netty、ZooKeeper 手撸一个 RPC 服务

    说明 项目链接 微服务框架都包括什么? 如何实现 RPC 远程调用? 开源 RPC 框架 限定语言 跨语言 RPC 框架 本地 Docker 搭建 ZooKeeper 下载镜像 启动容器 查看容器日志 ...

  5. 报错com.github.pagehelper.PageHelper cannot be cast to com.github.pagehelper.Dialect

    报错com.github.pagehelper.PageHelper cannot be cast to com.github.pagehelper.Dialect spring以及mybatis版本 ...

  6. 【vue-02】基础语法

    插值操作 插值运算符 语法:{{数据}} 插值运算符可以对数据进行显示{{msg}},也可以在插值运算符中进行表达式计算{{cnt*2}}. v-html 希望以html格式进行输出 htmlData ...

  7. 变分贝叶斯学习(variational bayesian learning)及重参数技巧(reparameterization trick)

    摘要:常规的神经网络权重是一个确定的值,贝叶斯神经网络(BNN)中,将权重视为一个概率分布.BNN的优化常常依赖于重参数技巧(reparameterization trick),本文对该优化方法进行概 ...

  8. nginx 配置后页面访问是报500错

    该问题是html文件权限问题. 用jenkins 并远程服务器上传到另一台服务器的html ,在配置好nginx 的location  root 绝对位置后还是报错500 手工用root上传时访问正常 ...

  9. VS中光标变成方块状,输入时会把光标覆盖的部分替换掉的解决方法

    按下键盘上的Insert键,切换为插入模式.

  10. 从执行上下文(ES3,ES5)的角度来理解"闭包"

    目录 介绍执行上下文和执行上下文栈概念 执行上下文 执行上下文栈 伪代码模拟分析以下代码中执行上下文栈的行为 代码模拟实现栈的执行过程 通过ES3提出的老概念-理解执行上下文 1.变量对象和活动对象 ...