目标检测算法丨YOLOv3介绍及Darknet53代码实现

目标检测算法丨YOLOv3介绍及Darknet53代码实现

YOLOv3介绍

Yolo是You Look once的简称,是目标检测算法中比较常用的一种算法,从YOLOv1到YOLOv5总共5个版本,这个算法不是最精准的算法,但是它属于在检测速度和检测精确度之间做了一个折中,其效果也是相当不错的。我们这里主要是介绍其中的第三个版本。

YOLOv3是目标检测算法中的YOLO算法的第三个版本。在这个版本中其实并没有太多的创新点,更多的是借鉴了前两个版本,但是却在保持速度的同时,在精度上做了优化。

YOLOv3使用了一个单独的神经网络作用在图像上,将图像划分成多个区域并且预测边界框和每个区域的概率。

Darknet53

YoloV3所使用的主干特征提取网络为Darknet53,它具有两个重要特点:

1、Darknet53具有一个重要特点是使用了残差网络Residual,Darknet53中的残差卷积就是首先进行一次卷积核大小为3X3、步长为2的卷积,该卷积会压缩输入进来的特征层的宽和高,此时我们可以获得一个特征层,我们将该特征层命名为layer。

之后我们再对该特征层进行一次1X1的卷积和一次3X3的卷积,并把这个结果加上layer,此时我们便构成了残差结构。通过不断的1X1卷积和3X3卷积以及残差边的叠加,我们便大幅度地加深了网络。

残差网络的特点是容易优化,并且能够通过增加相当的深度来提高准确率。其内部的残差块使用了跳跃连接,缓解了在深度神经网络中增加深度带来的梯度消失问题。

2、Darknet53的每一个卷积部分使用了特有的DarknetConv2D结构,每一次卷积的时候进行l2正则化,完成卷积后进行BatchNormalization标准化与LeakyReLU。

普通的ReLU是将所有的负值都设为零,Leaky ReLU则是给所有负值赋予一个非零斜率。以数学的方式我们可以表示为:

代码实现:

import mathfrom collections import OrderedDictimport torch.nn as nn# ———————————————————————## 残差结构# 利用一个1×1卷积下降通道数,然后利用一个3×3卷积提取特征并且上升通道数# 最后接上一个残差边# ———————————————————————#class BasicBlock(nn.Module):def __init__(self, inplanes, planes):super(BasicBlock, self).__init__()self.conv1 = nn.Conv2d(inplanes, planes[0], kernel_size=1, stride=1, padding=0, bias=False)self.bn1 = nn.BatchNorm2d(planes[0])self.relu1 = nn.LeakyReLU(0.1)self.conv2 = nn.Conv2d(planes[0], planes[1], kernel_size=3, stride=1, padding=1, bias=False)self.bn2 = nn.BatchNorm2d(planes[1])self.relu2 = nn.LeakyReLU(0.1)def forward(self, x):residual = xout = self.conv1(x)out = self.bn1(out)out = self.relu1(out)out = self.conv2(out)out = self.bn2(out)out = self.relu2(out)out += residualreturn outclass DarkNet(nn.Module):def __init__(self, layers):super(DarkNet, self).__init__()self.inplanes = 32 # 416,416,3 -> 416,416,32self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=3, stride=1, padding=1, bias=False)self.bn1 = nn.BatchNorm2d(self.inplanes)self.relu1 = nn.LeakyReLU(0.1) # 416,416,32 -> 208,208,64self.layer1 = self._make_layer([32, 64], layers[0]) # 208,208,64 -> 104,104,128self.layer2 = self._make_layer([64, 128], layers[1]) # 104,104,128 -> 52,52,256self.layer3 = self._make_layer([128, 256], layers[2]) # 52,52,256 -> 26,26,512 self.layer4 = self._make_layer([256, 512], layers[3]) # 26,26,512 -> 13,13,1024 self.layer5 = self._make_layer([512, 1024], layers[4])self.layers_out_filters = [64, 128, 256, 512, 1024] # 进行权值初始化 for m in self.modules():if isinstance(m, nn.Conv2d):n = m.kernel_size[0] * m.kernel_size[1] * m.out_channelsm.weight.data.normal_(0, math.sqrt(2. / n))elif isinstance(m, nn.BatchNorm2d):m.weight.data.fill_(1)m.bias.data.zero_() # ———————————————————————## 在每一个layer里面,首先利用一个步长为2的3×3卷积进行下采样# 然后进行残差结构的堆叠# ———————————————————————#def _make_layer(self, planes, blocks):layers = [] # 下采样,步长为2,卷积核大小为3layers.append((“ds_conv”, nn.Conv2d(self.inplanes, planes[1], kernel_size=3, stride=2, padding=1, bias=False)))layers.append((“ds_bn”, nn.BatchNorm2d(planes[1])))layers.append((“ds_relu”, nn.LeakyReLU(0.1))) # 加入残差结构self.inplanes = planes[1]for i in range(0, blocks):layers.append((“residual_{}”.format(i), BasicBlock(self.inplanes, planes)))return nn.Sequential(OrderedDict(layers))def forward(self, x):x = self.conv1(x)x = self.bn1(x)x = self.relu1(x)x = self.layer1(x)x = self.layer2(x)out3 = self.layer3(x)out4 = self.layer4(out3)out5 = self.layer5(out4)return out3, out4, out5def darknet53():model = DarkNet([1, 2, 8, 8, 4])return model

这里就是YOLOv3的骨干网络的实现。

郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
(0)
用户投稿
上一篇 2022年7月2日
下一篇 2022年7月2日

相关推荐

联系我们

联系邮箱:admin#wlmqw.com
工作时间:周一至周五,10:30-18:30,节假日休息