YoloV3学习笔记

YoloV3笔记(一):


​    按照惯例分享学习资料: YOLO-V3硬核讲解(第二部分-YOLO-V3网络结构+代码实现)_哔哩哔哩_bilibili

本文先介绍YoloV3的相关知识后,再进行代码的讲解。

一.YoloV3的相关知识点

YoloV3由三个网络共同实现:

主干特征提取网络->侦测网络->卷积神经网络

1.主干特征提取网络(darknet53)

​    卷积、下采样(通过卷积利用步长的不同实现)
残差块的实现:
​    卷积->下采样 其中:卷积用于降通道数,下采样用于还原通道数、残差块用于减小误差,反之出现梯度消失问题

    在这里插入图片描述

​   上图中,Convolutional表示卷积,黄框内表示通道数,红框内表示卷积核的大小。正如上图中所描述,进行两级卷积后,进入Residual(残差块),进行残差的操作,残差出来又是一个卷积,但是注意这里的卷积核变为3*3/2,即卷积步长改变了,这里实现的是(卷积)下采样。

2.卷积神经网络

        在这里插入图片描述

  用于提取特征,先用1×1的卷积核进行降通道,再用3×3的卷积核进行特征提取并恢复成原来的通道数,如此反复循环,最后通过1×1把通道降下来并输出。

3.侦测网络(负责13×13,26×26;52×52的输出)

在这里插入图片描述

  因为yolov3检测时,是以三个矩形框来检测图像的,分别为大、中、小,侦测网络就是用于侦测是三个矩阵中,哪个矩阵的特征图像。 左分支(红框):用3×3的卷积提取特征后,再用1×1的卷积降通道 下分支(黄框):1×1的卷积降通道后(也可使用3×3),进行上采样,再将上采样的通道数和主干特征提取网络的26×26或13×13的通道数结合(通道数可以不同,但是形状大小必须相同)。其中,上采样采取的是插值法,本文讲解的是最邻近插值法。

最邻近插值法:

在这里插入图片描述

​   就像上图,将对应位置的特征复制,并填充,因为填充的是原有的特征,没有引入新的特征,所以不会造成误差。

​   当然,直接拿26×26进行侦测也是可以的,但是这就涉及到另一个网络SSD,SSD操作就是进行5次卷积,即5次特征提取,每一次特征提取都进行一次侦测,最后再输出。这种网络缺点,是网络太浅,侦测效果太差,在使用时很容易丢失一些特征,所以我们在此将上采样操作后的图像和主干特征进行拼接,弥补那些丢失的信息。
   但是,为什么不用残差块进行侦测操作呢?
   首先侦测是进行特征的拼接,残差是特征的融合,融合和拼接的操作是大不相同的操作,拼接不会产生新的特征,但是进行融合,就会产生融合后的新特征。融合后我们就无法看到,融合前的两个特征是什么样子的,就比如2+2 = 4,2和2融合后为4,但是只给我们4的时候,我们怎么会知道是2+2形成的4还是1+3形成的4呢,所以残差在此也不合适,相比之下拼接的话就很容易得到特征的原貌,保存了特征的完整性。

二.用pytorch实现网络搭建

注意:网络结构根据需上述给的图来定义。
先看图再看结构:

在这里插入图片描述

import torch
from torch import nn
from torch.nn import  functional

#  卷积块
class ConvolutionalLayer(nn.Module):
    def __init__(self , in_chanel,out_chanel,kerenel_size,stride,padding,bias = False):
        #参数对应  in_chanel输入通道   out_chanel输出通道 kerenel_size卷积核大小  stride步长  padding填充
        super(ConvolutionalLayer,self).__init__()
        self.sub_model = nn.Sequential(
            nn.Conv2d(in_chanel,out_chanel,kerenel_size, stride,padding,bias = bias),
            nn.BatchNorm2d(out_chanel),
            #归一化
            nn.LeakyReLU()
            #nn.LeakyReLU()大于0部分保留原值,小于部分0取斜率
        )

    def forward(self,x):
        return self.sub_model(x)

#   残差块
class ResidualLayer(nn.Module):
    def __init__(self,in_channels,out_chanels):
        super(ResidualLayer, self).__init__()
        self.sub_module = nn.Sequential(
            ConvolutionalLayer(in_channels,out_chanels,1,1,0),
            ConvolutionalLayer(out_chanels,in_channels,3,1,1)
            #如讲解中,两个卷积,一个降通道数,一个恢复通道数
        )

    def forward(self,x):
        return self.sub_module(x)+x

#   卷积集合块 卷积神经网络
class ConvolutionalSetLayer(nn.Module):
    def __init__(self,in_channels,out_channels):
        super(ConvolutionalSetLayer,self).__init__()
        self.sub_module = nn.Sequential(
            #讲解中卷积神经网络的的5个卷积
            ConvolutionalLayer(in_channels,out_channels,1,1,0),
            ConvolutionalLayer(out_channels,in_channels,3,1,1),

            ConvolutionalLayer(in_channels, out_channels, 1, 1, 0),
            ConvolutionalLayer(out_channels, in_channels, 3, 1, 1),

            ConvolutionalLayer(in_channels,out_channels,1,1,0)
        )
    def forward(self,x):
        return self.sub_module(x)

#  降采样
class DownSamplingLayer(nn.Module):
    def __init__(self,in_channels,out_channels):
        super(DownSamplingLayer,self).__init__()
        self.sub_module = nn.Sequential(
            ConvolutionalLayer(in_channels,out_channels,3,2,1)
            #  卷积修改步长实现
        )

    def forward(self,x):
        return self.sub_module(x)

#  上采样
class UpSamplingLayer(nn.Module):
    def __init__(self):
        super(UpSamplingLayer,self).__init__()

    def forward(self,x):
        return functional.interpolate(x,scale_factor=2,mode = 'nearest')
    #  functional.interpolate()将图片上采样到指定的大小,采用最邻近插值法

class Yolo_v3_Net(nn.Module):
    def __init__(self):
        super(Yolo_v3_Net,self).__init__()
        #       主干52*52
        self.trunk_52 = nn.Sequential(
            ConvolutionalLayer(3,32,3,1,1),
            DownSamplingLayer(32,64),

            ResidualLayer(64,32),
            DownSamplingLayer(64,128),

            ResidualLayer(128,64),
            ResidualLayer(128, 64),
            DownSamplingLayer(128,256),

            #  残差块  数量根据说明图表
            ResidualLayer(256,128 ),
            ResidualLayer(256, 128),
            ResidualLayer(256, 128),
            ResidualLayer(256, 128),
            ResidualLayer(256, 128),
            ResidualLayer(256, 128),
            ResidualLayer(256, 128),
            ResidualLayer(256, 128)
        )
        #    主干26 * 26
        self.trunk_26 = nn.Sequential(
            DownSamplingLayer(256,512),

            #  残差块
            ResidualLayer(512, 256),
            ResidualLayer(512, 256),
            ResidualLayer(512, 256),
            ResidualLayer(512, 256),
            ResidualLayer(512, 256),
            ResidualLayer(512, 256),
            ResidualLayer(512, 256),
            ResidualLayer(512, 256)
        )
        #    主干13*13
        self.trunk_13 = nn.Sequential(
            DownSamplingLayer(512,1024),

            ResidualLayer(1024, 512),
            ResidualLayer(1024, 512),
            ResidualLayer(1024, 512),
            ResidualLayer(1024, 512)
        )

        #以下是侦测网络实现  根据说明图表  下分支
        #   进入卷积块
        self.convset_13 = nn.Sequential(
            ConvolutionalLayer(1024,512,3,1,1)
        )

        #   卷积降通道
        self.detetion_13 = nn.Sequential(
            ConvolutionalLayer(512,1024,3,1,1),
            nn.Conv2d(1024,45,1,1,0)
        )
        #   上采样
        self.up_13_to_26 = nn.Sequential(
            ConvolutionalLayer(512,256,3,1,1),
            UpSamplingLayer()
        )
        #   进入卷积块
        self.convset_26 = nn.Sequential(
            ConvolutionalLayer(768,256,3,1,1)
        )
        #   卷积降通道
        self.detetion_26 = nn.Sequential(
            ConvolutionalLayer(256, 512, 3, 1, 1),
            nn.Conv2d(512, 45, 1, 1, 0)
        )
        #   上采样
        self.up_26_to_52 = nn.Sequential(
            ConvolutionalLayer(256, 128, 3, 1, 1),
            UpSamplingLayer()
        )
        #   进入卷积块
        self.convet_52 = nn.Sequential(
            ConvolutionalLayer(384,128,3,1,1)
        )
        #   卷积降通道
        self.detetion_52 = nn.Sequential(
            ConvolutionalLayer(128, 256, 3, 1, 1),
            nn.Conv2d(256, 45, 1, 1, 0)
        )


#  定义结构连接网络图
    def forward(self,x):
        h_52 = self.trunk_52(x)
        h_26 = self.trunk_26(h_52)
        h_13 = self.trunk_13(h_26)

        convset_13_out = self.convset_13(h_13)
        detetion_13_out = self.detetion_13(convset_13_out)
        up_13_to26_out = self.up_13_to_26(convset_13_out)
        cat_13_to_26 = torch.cat((up_13_to26_out,h_26),dim = 1)

        convset_26_out = self.convset_26(cat_13_to_26)
        detetion_26_out = self.detetion_26(convset_26_out)
        up_26_to52_out = self.up_26_to_52(convset_26_out)
        cat_26_to_52 = torch.cat((up_26_to52_out,h_52),dim = 1)

        convset_52_out = self.convet_52(cat_26_to_52)
        detection_52_out = self.detetion_52(convset_52_out)

        return detetion_13_out,detetion_26_out,detection_52_out

if __name__ == '__main__':
    net = Yolo_v3_Net()
    x = torch.randn(1,3,416,416)
    y = net(x)
    print(y[0].shape)
    print(y[1].shape)
    print(y[2].shape)


10.24学习笔记
下一篇Yolov3学习笔记:
(19条消息) YoloV3笔记(二):_风声向寂的博客-CSDN博客
(20条消息) YoloV3学习笔记(三):_风声向寂的博客-CSDN博客

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值